feat(sdk): Add ZK SDK for all 12 languages
Implement Zero-Knowledge proof SDK for ZK-Rollups and privacy: - Proof systems: Groth16, PLONK, STARK - Circuit types: Transfer, Batch, Deposit, Withdraw - Rollup batch processing and state management - Trusted setup ceremony operations - Merkle proof verification Languages: JS/TS, Python, Go, Rust, Flutter, Java, Kotlin, Swift, C, C++, C#, Ruby
This commit is contained in:
parent
97add23062
commit
eab599767c
22 changed files with 8881 additions and 0 deletions
527
sdk/c/include/synor/zk.h
Normal file
527
sdk/c/include/synor/zk.h
Normal file
|
|
@ -0,0 +1,527 @@
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK for C
|
||||||
|
*
|
||||||
|
* Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SYNOR_ZK_H
|
||||||
|
#define SYNOR_ZK_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Opaque Types
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
typedef struct synor_zk_client synor_zk_client_t;
|
||||||
|
typedef struct synor_zk_proof synor_zk_proof_t;
|
||||||
|
typedef struct synor_zk_verification_key synor_zk_verification_key_t;
|
||||||
|
typedef struct synor_zk_proving_key synor_zk_proving_key_t;
|
||||||
|
typedef struct synor_zk_batch synor_zk_batch_t;
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Enumerations
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/** Proof system backends */
|
||||||
|
typedef enum {
|
||||||
|
SYNOR_ZK_PROOF_SYSTEM_GROTH16 = 0, /**< Smallest proofs (~192 bytes), fastest verification */
|
||||||
|
SYNOR_ZK_PROOF_SYSTEM_PLONK = 1, /**< Universal trusted setup, medium proofs (~512 bytes) */
|
||||||
|
SYNOR_ZK_PROOF_SYSTEM_STARK = 2 /**< No trusted setup, largest proofs (~50KB) */
|
||||||
|
} synor_zk_proof_system_t;
|
||||||
|
|
||||||
|
/** Circuit types for different operations */
|
||||||
|
typedef enum {
|
||||||
|
SYNOR_ZK_CIRCUIT_TRANSFER = 0, /**< Single transfer between accounts */
|
||||||
|
SYNOR_ZK_CIRCUIT_BATCH = 1, /**< Batch of multiple transfers */
|
||||||
|
SYNOR_ZK_CIRCUIT_DEPOSIT = 2, /**< Deposit from L1 to L2 */
|
||||||
|
SYNOR_ZK_CIRCUIT_WITHDRAW = 3 /**< Withdrawal from L2 to L1 */
|
||||||
|
} synor_zk_circuit_type_t;
|
||||||
|
|
||||||
|
/** Rollup state */
|
||||||
|
typedef enum {
|
||||||
|
SYNOR_ZK_ROLLUP_STATE_ACTIVE = 0,
|
||||||
|
SYNOR_ZK_ROLLUP_STATE_PAUSED = 1,
|
||||||
|
SYNOR_ZK_ROLLUP_STATE_FINALIZING = 2,
|
||||||
|
SYNOR_ZK_ROLLUP_STATE_FINALIZED = 3
|
||||||
|
} synor_zk_rollup_state_t;
|
||||||
|
|
||||||
|
/** Proof status */
|
||||||
|
typedef enum {
|
||||||
|
SYNOR_ZK_PROOF_STATUS_GENERATING = 0,
|
||||||
|
SYNOR_ZK_PROOF_STATUS_COMPLETED = 1,
|
||||||
|
SYNOR_ZK_PROOF_STATUS_FAILED = 2,
|
||||||
|
SYNOR_ZK_PROOF_STATUS_VERIFIED = 3
|
||||||
|
} synor_zk_proof_status_t;
|
||||||
|
|
||||||
|
/** Error codes */
|
||||||
|
typedef enum {
|
||||||
|
SYNOR_ZK_OK = 0,
|
||||||
|
SYNOR_ZK_ERROR_INVALID_ARGUMENT = 1,
|
||||||
|
SYNOR_ZK_ERROR_NETWORK = 2,
|
||||||
|
SYNOR_ZK_ERROR_AUTH = 3,
|
||||||
|
SYNOR_ZK_ERROR_NOT_FOUND = 4,
|
||||||
|
SYNOR_ZK_ERROR_TIMEOUT = 5,
|
||||||
|
SYNOR_ZK_ERROR_INTERNAL = 6,
|
||||||
|
SYNOR_ZK_ERROR_CLIENT_CLOSED = 7,
|
||||||
|
SYNOR_ZK_ERROR_PROOF_INVALID = 8,
|
||||||
|
SYNOR_ZK_ERROR_CIRCUIT_ERROR = 9
|
||||||
|
} synor_zk_error_t;
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Structures
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/** SDK configuration */
|
||||||
|
typedef struct {
|
||||||
|
const char* api_key;
|
||||||
|
const char* endpoint; /**< Default: "https://zk.synor.io/v1" */
|
||||||
|
const char* ws_endpoint; /**< Default: "wss://zk.synor.io/v1/ws" */
|
||||||
|
uint32_t timeout_ms; /**< Default: 60000 */
|
||||||
|
uint32_t retries; /**< Default: 3 */
|
||||||
|
synor_zk_proof_system_t default_proof_system; /**< Default: GROTH16 */
|
||||||
|
bool debug; /**< Default: false */
|
||||||
|
} synor_zk_config_t;
|
||||||
|
|
||||||
|
/** Zero-knowledge proof */
|
||||||
|
typedef struct {
|
||||||
|
char id[64];
|
||||||
|
synor_zk_proof_system_t system;
|
||||||
|
synor_zk_circuit_type_t circuit_type;
|
||||||
|
uint8_t* data;
|
||||||
|
size_t data_len;
|
||||||
|
char** public_inputs;
|
||||||
|
size_t public_inputs_count;
|
||||||
|
size_t size;
|
||||||
|
uint64_t generation_time_ms;
|
||||||
|
uint64_t created_at;
|
||||||
|
} synor_zk_proof_info_t;
|
||||||
|
|
||||||
|
/** Verification result */
|
||||||
|
typedef struct {
|
||||||
|
bool valid;
|
||||||
|
uint64_t verification_time_ms;
|
||||||
|
char* error;
|
||||||
|
} synor_zk_verification_result_t;
|
||||||
|
|
||||||
|
/** Account state */
|
||||||
|
typedef struct {
|
||||||
|
char address[64];
|
||||||
|
char balance[32];
|
||||||
|
uint64_t nonce;
|
||||||
|
char pubkey_hash[66];
|
||||||
|
} synor_zk_account_state_t;
|
||||||
|
|
||||||
|
/** Transfer operation */
|
||||||
|
typedef struct {
|
||||||
|
char from[64];
|
||||||
|
char to[64];
|
||||||
|
char amount[32];
|
||||||
|
char fee[32];
|
||||||
|
uint64_t nonce;
|
||||||
|
char* signature; /**< Optional */
|
||||||
|
} synor_zk_transfer_t;
|
||||||
|
|
||||||
|
/** Deposit operation */
|
||||||
|
typedef struct {
|
||||||
|
char l1_tx_hash[66];
|
||||||
|
char recipient[64];
|
||||||
|
char amount[32];
|
||||||
|
char* token; /**< Optional */
|
||||||
|
} synor_zk_deposit_t;
|
||||||
|
|
||||||
|
/** Withdrawal operation */
|
||||||
|
typedef struct {
|
||||||
|
char sender[64];
|
||||||
|
char recipient[64];
|
||||||
|
char amount[32];
|
||||||
|
char* token; /**< Optional */
|
||||||
|
uint64_t nonce;
|
||||||
|
char* signature; /**< Optional */
|
||||||
|
} synor_zk_withdrawal_t;
|
||||||
|
|
||||||
|
/** Rollup statistics */
|
||||||
|
typedef struct {
|
||||||
|
uint64_t current_batch;
|
||||||
|
uint64_t total_transactions;
|
||||||
|
uint64_t total_proofs;
|
||||||
|
uint64_t avg_proof_time_ms;
|
||||||
|
char state_root[66];
|
||||||
|
uint64_t account_count;
|
||||||
|
char tvl[32];
|
||||||
|
} synor_zk_rollup_stats_t;
|
||||||
|
|
||||||
|
/** Proof request */
|
||||||
|
typedef struct {
|
||||||
|
synor_zk_circuit_type_t circuit_type;
|
||||||
|
char** public_inputs;
|
||||||
|
size_t public_inputs_count;
|
||||||
|
char** private_inputs;
|
||||||
|
size_t private_inputs_count;
|
||||||
|
synor_zk_proof_system_t* system; /**< Optional, uses default if NULL */
|
||||||
|
} synor_zk_proof_request_t;
|
||||||
|
|
||||||
|
/** Merkle proof */
|
||||||
|
typedef struct {
|
||||||
|
char leaf[66];
|
||||||
|
char** path;
|
||||||
|
size_t path_len;
|
||||||
|
uint8_t* indices;
|
||||||
|
size_t indices_len;
|
||||||
|
char root[66];
|
||||||
|
} synor_zk_merkle_proof_t;
|
||||||
|
|
||||||
|
/** Ceremony contribution */
|
||||||
|
typedef struct {
|
||||||
|
char contributor_id[64];
|
||||||
|
char hash[66];
|
||||||
|
uint64_t timestamp;
|
||||||
|
bool verified;
|
||||||
|
} synor_zk_ceremony_contribution_t;
|
||||||
|
|
||||||
|
/** Trusted setup ceremony */
|
||||||
|
typedef struct {
|
||||||
|
char id[64];
|
||||||
|
synor_zk_circuit_type_t circuit_type;
|
||||||
|
synor_zk_proof_system_t system;
|
||||||
|
size_t contribution_count;
|
||||||
|
char latest_hash[66];
|
||||||
|
bool complete;
|
||||||
|
synor_zk_ceremony_contribution_t* contributions;
|
||||||
|
size_t contributions_count;
|
||||||
|
} synor_zk_trusted_setup_t;
|
||||||
|
|
||||||
|
/** Proof system characteristics */
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
size_t proof_size;
|
||||||
|
uint32_t verification_time_ms;
|
||||||
|
bool trusted_setup;
|
||||||
|
bool universal;
|
||||||
|
} synor_zk_proof_system_info_t;
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Client Lifecycle
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ZK SDK client
|
||||||
|
*
|
||||||
|
* @param config Configuration options
|
||||||
|
* @return New client handle, or NULL on error
|
||||||
|
*/
|
||||||
|
synor_zk_client_t* synor_zk_client_new(const synor_zk_config_t* config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close and free a client
|
||||||
|
*
|
||||||
|
* @param client Client to close
|
||||||
|
*/
|
||||||
|
void synor_zk_client_free(synor_zk_client_t* client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if client is closed
|
||||||
|
*
|
||||||
|
* @param client Client handle
|
||||||
|
* @return true if closed
|
||||||
|
*/
|
||||||
|
bool synor_zk_client_is_closed(const synor_zk_client_t* client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Health check
|
||||||
|
*
|
||||||
|
* @param client Client handle
|
||||||
|
* @param healthy Output parameter for health status
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_health_check(synor_zk_client_t* client, bool* healthy);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Proof Operations
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a zero-knowledge proof
|
||||||
|
*
|
||||||
|
* @param client Client handle
|
||||||
|
* @param request Proof request parameters
|
||||||
|
* @param proof Output parameter for generated proof
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_proof_generate(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const synor_zk_proof_request_t* request,
|
||||||
|
synor_zk_proof_t** proof
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a proof
|
||||||
|
*
|
||||||
|
* @param client Client handle
|
||||||
|
* @param proof Proof to verify
|
||||||
|
* @param result Output parameter for verification result
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_proof_verify(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const synor_zk_proof_t* proof,
|
||||||
|
synor_zk_verification_result_t* result
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a proof by ID
|
||||||
|
*
|
||||||
|
* @param client Client handle
|
||||||
|
* @param proof_id Proof identifier
|
||||||
|
* @param proof Output parameter for proof
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_proof_get(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const char* proof_id,
|
||||||
|
synor_zk_proof_t** proof
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a proof
|
||||||
|
*/
|
||||||
|
void synor_zk_proof_free(synor_zk_proof_t* proof);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get proof info
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_proof_get_info(
|
||||||
|
const synor_zk_proof_t* proof,
|
||||||
|
synor_zk_proof_info_t* info
|
||||||
|
);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Circuit Operations
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get verification key for a circuit
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_circuit_get_vk(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_circuit_type_t circuit_type,
|
||||||
|
synor_zk_proof_system_t system,
|
||||||
|
synor_zk_verification_key_t** vk
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get proving key for a circuit
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_circuit_get_pk(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_circuit_type_t circuit_type,
|
||||||
|
synor_zk_proof_system_t system,
|
||||||
|
synor_zk_proving_key_t** pk
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free verification key
|
||||||
|
*/
|
||||||
|
void synor_zk_verification_key_free(synor_zk_verification_key_t* vk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free proving key
|
||||||
|
*/
|
||||||
|
void synor_zk_proving_key_free(synor_zk_proving_key_t* pk);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Rollup Operations
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get rollup statistics
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_rollup_get_stats(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_rollup_stats_t* stats
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current batch
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_rollup_get_current_batch(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_batch_t** batch
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get batch by number
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_rollup_get_batch(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
uint64_t batch_number,
|
||||||
|
synor_zk_batch_t** batch
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a transfer
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_rollup_submit_transfer(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const synor_zk_transfer_t* transfer,
|
||||||
|
char* tx_id,
|
||||||
|
size_t tx_id_len
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a deposit
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_rollup_submit_deposit(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const synor_zk_deposit_t* deposit,
|
||||||
|
char* tx_id,
|
||||||
|
size_t tx_id_len
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a withdrawal
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_rollup_submit_withdrawal(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const synor_zk_withdrawal_t* withdrawal,
|
||||||
|
char* tx_id,
|
||||||
|
size_t tx_id_len
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize current batch
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_rollup_finalize_batch(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_batch_t** batch
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free batch
|
||||||
|
*/
|
||||||
|
void synor_zk_batch_free(synor_zk_batch_t* batch);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* State Operations
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current state root
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_state_get_root(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
char* root,
|
||||||
|
size_t root_len
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get account state
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_state_get_account(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const char* address,
|
||||||
|
synor_zk_account_state_t* account
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get merkle proof for account inclusion
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_state_get_merkle_proof(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const char* address,
|
||||||
|
synor_zk_merkle_proof_t* proof
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify merkle proof
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_state_verify_merkle_proof(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
const synor_zk_merkle_proof_t* proof,
|
||||||
|
bool* valid
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free merkle proof
|
||||||
|
*/
|
||||||
|
void synor_zk_merkle_proof_free(synor_zk_merkle_proof_t* proof);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Ceremony Operations
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ceremony status
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_ceremony_get_status(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_circuit_type_t circuit_type,
|
||||||
|
synor_zk_proof_system_t system,
|
||||||
|
synor_zk_trusted_setup_t* setup
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contribute to ceremony
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_ceremony_contribute(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_circuit_type_t circuit_type,
|
||||||
|
const uint8_t* entropy,
|
||||||
|
size_t entropy_len,
|
||||||
|
synor_zk_proof_system_t system,
|
||||||
|
synor_zk_ceremony_contribution_t* contribution
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a contribution
|
||||||
|
*/
|
||||||
|
synor_zk_error_t synor_zk_ceremony_verify_contribution(
|
||||||
|
synor_zk_client_t* client,
|
||||||
|
synor_zk_circuit_type_t circuit_type,
|
||||||
|
const char* contribution_hash,
|
||||||
|
bool* valid
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free trusted setup
|
||||||
|
*/
|
||||||
|
void synor_zk_trusted_setup_free(synor_zk_trusted_setup_t* setup);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Utility Functions
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get proof system info
|
||||||
|
*/
|
||||||
|
synor_zk_proof_system_info_t synor_zk_get_proof_system_info(synor_zk_proof_system_t system);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get error message
|
||||||
|
*/
|
||||||
|
const char* synor_zk_error_message(synor_zk_error_t error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free verification result
|
||||||
|
*/
|
||||||
|
void synor_zk_verification_result_free(synor_zk_verification_result_t* result);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Constants
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
#define SYNOR_ZK_MAX_BATCH_SIZE 1000
|
||||||
|
#define SYNOR_ZK_STATE_TREE_DEPTH 32
|
||||||
|
#define SYNOR_ZK_PROOF_EXPIRY_BLOCKS 100
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SYNOR_ZK_H */
|
||||||
429
sdk/cpp/include/synor/zk.hpp
Normal file
429
sdk/cpp/include/synor/zk.hpp
Normal file
|
|
@ -0,0 +1,429 @@
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK for C++
|
||||||
|
*
|
||||||
|
* Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SYNOR_ZK_HPP
|
||||||
|
#define SYNOR_ZK_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <map>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace synor {
|
||||||
|
namespace zk {
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Enumerations
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/** Proof system backends */
|
||||||
|
enum class ProofSystem {
|
||||||
|
Groth16, ///< Smallest proofs (~192 bytes), fastest verification
|
||||||
|
Plonk, ///< Universal trusted setup, medium proofs (~512 bytes)
|
||||||
|
Stark ///< No trusted setup, largest proofs (~50KB)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Circuit types for different operations */
|
||||||
|
enum class CircuitType {
|
||||||
|
Transfer, ///< Single transfer between accounts
|
||||||
|
Batch, ///< Batch of multiple transfers
|
||||||
|
Deposit, ///< Deposit from L1 to L2
|
||||||
|
Withdraw ///< Withdrawal from L2 to L1
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Rollup state */
|
||||||
|
enum class RollupState {
|
||||||
|
Active,
|
||||||
|
Paused,
|
||||||
|
Finalizing,
|
||||||
|
Finalized
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Proof status */
|
||||||
|
enum class ProofStatus {
|
||||||
|
Generating,
|
||||||
|
Completed,
|
||||||
|
Failed,
|
||||||
|
Verified
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Exception
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
class ZkError : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
ZkError(const std::string& message,
|
||||||
|
const std::optional<std::string>& code = std::nullopt,
|
||||||
|
const std::optional<int>& status = std::nullopt)
|
||||||
|
: std::runtime_error(message), code_(code), status_(status) {}
|
||||||
|
|
||||||
|
const std::optional<std::string>& code() const { return code_; }
|
||||||
|
const std::optional<int>& status() const { return status_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<std::string> code_;
|
||||||
|
std::optional<int> status_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Data Types
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/** Zero-knowledge proof */
|
||||||
|
struct Proof {
|
||||||
|
std::string id;
|
||||||
|
ProofSystem system;
|
||||||
|
CircuitType circuit_type;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
std::vector<std::string> public_inputs;
|
||||||
|
size_t size;
|
||||||
|
uint64_t generation_time_ms;
|
||||||
|
uint64_t created_at;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Verification key for a circuit */
|
||||||
|
struct VerificationKey {
|
||||||
|
std::string circuit_id;
|
||||||
|
CircuitType circuit_type;
|
||||||
|
ProofSystem system;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Proving key for generating proofs */
|
||||||
|
struct ProvingKey {
|
||||||
|
std::string circuit_id;
|
||||||
|
CircuitType circuit_type;
|
||||||
|
ProofSystem system;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Circuit configuration */
|
||||||
|
struct CircuitConfig {
|
||||||
|
CircuitType type;
|
||||||
|
std::optional<size_t> max_batch_size;
|
||||||
|
std::optional<size_t> tree_depth;
|
||||||
|
std::optional<bool> verify_signatures;
|
||||||
|
std::optional<std::map<std::string, std::string>> custom_constraints;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Account state in the rollup */
|
||||||
|
struct AccountState {
|
||||||
|
std::string address;
|
||||||
|
std::string balance;
|
||||||
|
uint64_t nonce;
|
||||||
|
std::string pubkey_hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Transfer operation */
|
||||||
|
struct Transfer {
|
||||||
|
std::string from;
|
||||||
|
std::string to;
|
||||||
|
std::string amount;
|
||||||
|
std::string fee;
|
||||||
|
uint64_t nonce;
|
||||||
|
std::optional<std::string> signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Deposit operation (L1 -> L2) */
|
||||||
|
struct Deposit {
|
||||||
|
std::string l1_tx_hash;
|
||||||
|
std::string recipient;
|
||||||
|
std::string amount;
|
||||||
|
std::optional<std::string> token;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Withdrawal operation (L2 -> L1) */
|
||||||
|
struct Withdrawal {
|
||||||
|
std::string sender;
|
||||||
|
std::string recipient;
|
||||||
|
std::string amount;
|
||||||
|
std::optional<std::string> token;
|
||||||
|
uint64_t nonce;
|
||||||
|
std::optional<std::string> signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Rollup batch */
|
||||||
|
struct Batch {
|
||||||
|
uint64_t batch_number;
|
||||||
|
std::string prev_state_root;
|
||||||
|
std::string new_state_root;
|
||||||
|
std::vector<Transfer> transfers;
|
||||||
|
std::vector<Deposit> deposits;
|
||||||
|
std::vector<Withdrawal> withdrawals;
|
||||||
|
std::optional<Proof> proof;
|
||||||
|
uint64_t timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Rollup statistics */
|
||||||
|
struct RollupStats {
|
||||||
|
uint64_t current_batch;
|
||||||
|
uint64_t total_transactions;
|
||||||
|
uint64_t total_proofs;
|
||||||
|
uint64_t avg_proof_time_ms;
|
||||||
|
std::string state_root;
|
||||||
|
uint64_t account_count;
|
||||||
|
std::string tvl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Proof request */
|
||||||
|
struct ProofRequest {
|
||||||
|
CircuitType circuit_type;
|
||||||
|
std::vector<std::string> public_inputs;
|
||||||
|
std::vector<std::string> private_inputs;
|
||||||
|
std::optional<ProofSystem> system;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Verification result */
|
||||||
|
struct VerificationResult {
|
||||||
|
bool valid;
|
||||||
|
uint64_t verification_time_ms;
|
||||||
|
std::optional<std::string> error;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Merkle proof for state inclusion */
|
||||||
|
struct MerkleProof {
|
||||||
|
std::string leaf;
|
||||||
|
std::vector<std::string> path;
|
||||||
|
std::vector<uint8_t> indices;
|
||||||
|
std::string root;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Ceremony contribution */
|
||||||
|
struct CeremonyContribution {
|
||||||
|
std::string contributor_id;
|
||||||
|
std::string hash;
|
||||||
|
uint64_t timestamp;
|
||||||
|
bool verified;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Trusted setup ceremony */
|
||||||
|
struct TrustedSetup {
|
||||||
|
std::string id;
|
||||||
|
CircuitType circuit_type;
|
||||||
|
ProofSystem system;
|
||||||
|
size_t contribution_count;
|
||||||
|
std::string latest_hash;
|
||||||
|
bool complete;
|
||||||
|
std::vector<CeremonyContribution> contributions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** SDK configuration */
|
||||||
|
struct ZkConfig {
|
||||||
|
std::string api_key;
|
||||||
|
std::string endpoint = "https://zk.synor.io/v1";
|
||||||
|
std::string ws_endpoint = "wss://zk.synor.io/v1/ws";
|
||||||
|
std::chrono::milliseconds timeout{60000};
|
||||||
|
int retries = 3;
|
||||||
|
ProofSystem default_proof_system = ProofSystem::Groth16;
|
||||||
|
bool debug = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Proof system characteristics */
|
||||||
|
struct ProofSystemInfo {
|
||||||
|
std::string name;
|
||||||
|
size_t proof_size;
|
||||||
|
uint32_t verification_time_ms;
|
||||||
|
bool trusted_setup;
|
||||||
|
bool universal;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Client Classes
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
class SynorZk;
|
||||||
|
|
||||||
|
/** Proofs sub-client */
|
||||||
|
class ProofsClient {
|
||||||
|
public:
|
||||||
|
explicit ProofsClient(SynorZk& zk) : zk_(zk) {}
|
||||||
|
|
||||||
|
std::future<Proof> generate(const ProofRequest& request);
|
||||||
|
std::future<VerificationResult> verify(const Proof& proof);
|
||||||
|
std::future<Proof> get(const std::string& proof_id);
|
||||||
|
std::future<std::vector<Proof>> list(std::optional<int> limit = std::nullopt,
|
||||||
|
std::optional<int> offset = std::nullopt);
|
||||||
|
std::future<std::vector<uint8_t>> serialize(const Proof& proof);
|
||||||
|
std::future<Proof> deserialize(const std::vector<uint8_t>& data, ProofSystem system);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SynorZk& zk_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Circuits sub-client */
|
||||||
|
class CircuitsClient {
|
||||||
|
public:
|
||||||
|
explicit CircuitsClient(SynorZk& zk) : zk_(zk) {}
|
||||||
|
|
||||||
|
std::future<VerificationKey> getVerificationKey(CircuitType circuit_type,
|
||||||
|
std::optional<ProofSystem> system = std::nullopt);
|
||||||
|
std::future<ProvingKey> getProvingKey(CircuitType circuit_type,
|
||||||
|
std::optional<ProofSystem> system = std::nullopt);
|
||||||
|
std::future<std::vector<CircuitConfig>> list();
|
||||||
|
std::future<CircuitConfig> getConfig(CircuitType circuit_type);
|
||||||
|
std::future<std::string> compile(const CircuitConfig& config);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SynorZk& zk_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Rollup sub-client */
|
||||||
|
class RollupClient {
|
||||||
|
public:
|
||||||
|
explicit RollupClient(SynorZk& zk) : zk_(zk) {}
|
||||||
|
|
||||||
|
std::future<RollupStats> getStats();
|
||||||
|
std::future<Batch> getCurrentBatch();
|
||||||
|
std::future<Batch> getBatch(uint64_t batch_number);
|
||||||
|
std::future<std::string> submitTransfer(const Transfer& transfer);
|
||||||
|
std::future<std::string> submitDeposit(const Deposit& deposit);
|
||||||
|
std::future<std::string> submitWithdrawal(const Withdrawal& withdrawal);
|
||||||
|
std::future<Batch> finalizeBatch();
|
||||||
|
std::future<std::vector<Transfer>> getPendingTransactions();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SynorZk& zk_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** State sub-client */
|
||||||
|
class StateClient {
|
||||||
|
public:
|
||||||
|
explicit StateClient(SynorZk& zk) : zk_(zk) {}
|
||||||
|
|
||||||
|
std::future<std::string> getRoot();
|
||||||
|
std::future<AccountState> getAccount(const std::string& address);
|
||||||
|
std::future<MerkleProof> getMerkleProof(const std::string& address);
|
||||||
|
std::future<bool> verifyMerkleProof(const MerkleProof& proof);
|
||||||
|
std::future<std::map<std::string, std::string>> getStateAtBatch(uint64_t batch_number);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SynorZk& zk_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Ceremony sub-client */
|
||||||
|
class CeremonyClient {
|
||||||
|
public:
|
||||||
|
explicit CeremonyClient(SynorZk& zk) : zk_(zk) {}
|
||||||
|
|
||||||
|
std::future<TrustedSetup> getStatus(CircuitType circuit_type,
|
||||||
|
std::optional<ProofSystem> system = std::nullopt);
|
||||||
|
std::future<CeremonyContribution> contribute(CircuitType circuit_type,
|
||||||
|
const std::vector<uint8_t>& entropy,
|
||||||
|
std::optional<ProofSystem> system = std::nullopt);
|
||||||
|
std::future<bool> verifyContribution(CircuitType circuit_type,
|
||||||
|
const std::string& contribution_hash);
|
||||||
|
std::future<std::vector<CeremonyContribution>> listContributions(CircuitType circuit_type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SynorZk& zk_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK Client
|
||||||
|
*
|
||||||
|
* Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* synor::zk::ZkConfig config;
|
||||||
|
* config.api_key = "your-api-key";
|
||||||
|
* synor::zk::SynorZk zk(config);
|
||||||
|
*
|
||||||
|
* // Generate a proof
|
||||||
|
* synor::zk::ProofRequest request;
|
||||||
|
* request.circuit_type = synor::zk::CircuitType::Transfer;
|
||||||
|
* request.public_inputs = {...};
|
||||||
|
* request.private_inputs = {...};
|
||||||
|
* auto proof = zk.proofs().generate(request).get();
|
||||||
|
*
|
||||||
|
* // Verify the proof
|
||||||
|
* auto result = zk.proofs().verify(proof).get();
|
||||||
|
* std::cout << "Valid: " << result.valid << std::endl;
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
class SynorZk {
|
||||||
|
public:
|
||||||
|
explicit SynorZk(const ZkConfig& config);
|
||||||
|
~SynorZk();
|
||||||
|
|
||||||
|
// Non-copyable
|
||||||
|
SynorZk(const SynorZk&) = delete;
|
||||||
|
SynorZk& operator=(const SynorZk&) = delete;
|
||||||
|
|
||||||
|
// Movable
|
||||||
|
SynorZk(SynorZk&&) noexcept;
|
||||||
|
SynorZk& operator=(SynorZk&&) noexcept;
|
||||||
|
|
||||||
|
/** Get the default proof system */
|
||||||
|
ProofSystem defaultProofSystem() const { return config_.default_proof_system; }
|
||||||
|
|
||||||
|
/** Health check */
|
||||||
|
std::future<bool> healthCheck();
|
||||||
|
|
||||||
|
/** Get service info */
|
||||||
|
std::future<std::map<std::string, std::string>> getInfo();
|
||||||
|
|
||||||
|
/** Close the client */
|
||||||
|
void close();
|
||||||
|
|
||||||
|
/** Check if client is closed */
|
||||||
|
bool isClosed() const { return closed_; }
|
||||||
|
|
||||||
|
/** Sub-clients */
|
||||||
|
ProofsClient& proofs() { return proofs_; }
|
||||||
|
CircuitsClient& circuits() { return circuits_; }
|
||||||
|
RollupClient& rollup() { return rollup_; }
|
||||||
|
StateClient& state() { return state_; }
|
||||||
|
CeremonyClient& ceremony() { return ceremony_; }
|
||||||
|
|
||||||
|
// Internal HTTP methods (public for sub-clients)
|
||||||
|
std::future<std::map<std::string, std::string>> get(const std::string& path);
|
||||||
|
std::future<std::map<std::string, std::string>> post(const std::string& path,
|
||||||
|
const std::map<std::string, std::string>& body);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ZkConfig config_;
|
||||||
|
bool closed_ = false;
|
||||||
|
ProofsClient proofs_;
|
||||||
|
CircuitsClient circuits_;
|
||||||
|
RollupClient rollup_;
|
||||||
|
StateClient state_;
|
||||||
|
CeremonyClient ceremony_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Utility Functions
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/** Get proof system info */
|
||||||
|
ProofSystemInfo getProofSystemInfo(ProofSystem system);
|
||||||
|
|
||||||
|
/** Convert proof system to string */
|
||||||
|
std::string proofSystemToString(ProofSystem system);
|
||||||
|
|
||||||
|
/** Convert circuit type to string */
|
||||||
|
std::string circuitTypeToString(CircuitType type);
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Constants
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
constexpr size_t MAX_BATCH_SIZE = 1000;
|
||||||
|
constexpr size_t STATE_TREE_DEPTH = 32;
|
||||||
|
constexpr uint64_t PROOF_EXPIRY_BLOCKS = 100;
|
||||||
|
|
||||||
|
} // namespace zk
|
||||||
|
} // namespace synor
|
||||||
|
|
||||||
|
#endif // SYNOR_ZK_HPP
|
||||||
339
sdk/csharp/src/Synor.Zk/SynorZk.cs
Normal file
339
sdk/csharp/src/Synor.Zk/SynorZk.cs
Normal file
|
|
@ -0,0 +1,339 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Synor.Zk;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synor ZK SDK for C#/.NET
|
||||||
|
///
|
||||||
|
/// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
/// </summary>
|
||||||
|
public class SynorZk : IDisposable
|
||||||
|
{
|
||||||
|
private readonly ZkConfig _config;
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private readonly JsonSerializerOptions _jsonOptions;
|
||||||
|
private bool _closed;
|
||||||
|
|
||||||
|
public ProofsClient Proofs { get; }
|
||||||
|
public CircuitsClient Circuits { get; }
|
||||||
|
public RollupClient Rollup { get; }
|
||||||
|
public StateClient State { get; }
|
||||||
|
public CeremonyClient Ceremony { get; }
|
||||||
|
|
||||||
|
public SynorZk(ZkConfig config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_httpClient = new HttpClient
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri(config.Endpoint),
|
||||||
|
Timeout = TimeSpan.FromMilliseconds(config.Timeout)
|
||||||
|
};
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {config.ApiKey}");
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("X-SDK-Version", "csharp/0.1.0");
|
||||||
|
|
||||||
|
_jsonOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
|
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseLower) }
|
||||||
|
};
|
||||||
|
|
||||||
|
Proofs = new ProofsClient(this);
|
||||||
|
Circuits = new CircuitsClient(this);
|
||||||
|
Rollup = new RollupClient(this);
|
||||||
|
State = new StateClient(this);
|
||||||
|
Ceremony = new CeremonyClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofSystem DefaultProofSystem => _config.DefaultProofSystem;
|
||||||
|
|
||||||
|
public async Task<bool> HealthCheckAsync(CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await GetAsync<Dictionary<string, object>>("/health", ct);
|
||||||
|
return result.TryGetValue("status", out var status) && status?.ToString() == "healthy";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Dictionary<string, object>> GetInfoAsync(CancellationToken ct = default) =>
|
||||||
|
GetAsync<Dictionary<string, object>>("/info", ct);
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
_closed = true;
|
||||||
|
_httpClient.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsClosed => _closed;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<T> GetAsync<T>(string path, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
CheckClosed();
|
||||||
|
var response = await _httpClient.GetAsync(path, ct);
|
||||||
|
return await HandleResponseAsync<T>(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<T> PostAsync<T>(string path, object? body = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
CheckClosed();
|
||||||
|
var content = body != null
|
||||||
|
? JsonContent.Create(body, options: _jsonOptions)
|
||||||
|
: JsonContent.Create(new { });
|
||||||
|
var response = await _httpClient.PostAsync(path, content, ct);
|
||||||
|
return await HandleResponseAsync<T>(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<T> HandleResponseAsync<T>(HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var error = JsonSerializer.Deserialize<Dictionary<string, object>>(json, _jsonOptions) ?? new();
|
||||||
|
throw new ZkException(
|
||||||
|
error.TryGetValue("message", out var msg) ? msg?.ToString() ?? $"HTTP {(int)response.StatusCode}" : $"HTTP {(int)response.StatusCode}",
|
||||||
|
error.TryGetValue("code", out var code) ? code?.ToString() : null,
|
||||||
|
(int)response.StatusCode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return JsonSerializer.Deserialize<T>(json, _jsonOptions)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckClosed()
|
||||||
|
{
|
||||||
|
if (_closed) throw new ZkException("Client has been closed", "CLIENT_CLOSED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Proofs sub-client</summary>
|
||||||
|
public class ProofsClient
|
||||||
|
{
|
||||||
|
private readonly SynorZk _zk;
|
||||||
|
|
||||||
|
internal ProofsClient(SynorZk zk) => _zk = zk;
|
||||||
|
|
||||||
|
public async Task<Proof> GenerateAsync(ProofRequest request, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var body = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["circuit_type"] = request.CircuitType.ToApiString(),
|
||||||
|
["public_inputs"] = request.PublicInputs,
|
||||||
|
["private_inputs"] = request.PrivateInputs,
|
||||||
|
["system"] = (request.System ?? _zk.DefaultProofSystem).ToApiString()
|
||||||
|
};
|
||||||
|
return await _zk.PostAsync<Proof>("/proofs/generate", body, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<VerificationResult> VerifyAsync(Proof proof, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var body = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["proof_id"] = proof.Id,
|
||||||
|
["data"] = proof.Data,
|
||||||
|
["public_inputs"] = proof.PublicInputs,
|
||||||
|
["system"] = proof.System.ToApiString(),
|
||||||
|
["circuit_type"] = proof.CircuitType.ToApiString()
|
||||||
|
};
|
||||||
|
return await _zk.PostAsync<VerificationResult>("/proofs/verify", body, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Proof> GetAsync(string proofId, CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<Proof>($"/proofs/{proofId}", ct);
|
||||||
|
|
||||||
|
public async Task<List<Proof>> ListAsync(int? limit = null, int? offset = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var path = "/proofs";
|
||||||
|
var qs = new List<string>();
|
||||||
|
if (limit.HasValue) qs.Add($"limit={limit}");
|
||||||
|
if (offset.HasValue) qs.Add($"offset={offset}");
|
||||||
|
if (qs.Count > 0) path += "?" + string.Join("&", qs);
|
||||||
|
|
||||||
|
var result = await _zk.GetAsync<ProofsListResponse>(path, ct);
|
||||||
|
return result.Proofs ?? new List<Proof>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<byte[]> SerializeAsync(Proof proof, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.PostAsync<SerializeResponse>("/proofs/serialize", new { proof_id = proof.Id }, ct);
|
||||||
|
return Convert.FromBase64String(result.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Proof> DeserializeAsync(byte[] data, ProofSystem system, CancellationToken ct = default) =>
|
||||||
|
_zk.PostAsync<Proof>("/proofs/deserialize", new { data = Convert.ToBase64String(data), system = system.ToApiString() }, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Circuits sub-client</summary>
|
||||||
|
public class CircuitsClient
|
||||||
|
{
|
||||||
|
private readonly SynorZk _zk;
|
||||||
|
|
||||||
|
internal CircuitsClient(SynorZk zk) => _zk = zk;
|
||||||
|
|
||||||
|
public Task<VerificationKey> GetVerificationKeyAsync(CircuitType circuitType, ProofSystem? system = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var sys = system ?? _zk.DefaultProofSystem;
|
||||||
|
return _zk.GetAsync<VerificationKey>($"/circuits/{circuitType.ToApiString()}/vk?system={sys.ToApiString()}", ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ProvingKey> GetProvingKeyAsync(CircuitType circuitType, ProofSystem? system = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var sys = system ?? _zk.DefaultProofSystem;
|
||||||
|
return _zk.GetAsync<ProvingKey>($"/circuits/{circuitType.ToApiString()}/pk?system={sys.ToApiString()}", ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<CircuitConfig>> ListAsync(CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.GetAsync<CircuitsListResponse>("/circuits", ct);
|
||||||
|
return result.Circuits ?? new List<CircuitConfig>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<CircuitConfig> GetConfigAsync(CircuitType circuitType, CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<CircuitConfig>($"/circuits/{circuitType.ToApiString()}/config", ct);
|
||||||
|
|
||||||
|
public async Task<string> CompileAsync(CircuitConfig config, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.PostAsync<CircuitIdResponse>("/circuits/compile", config, ct);
|
||||||
|
return result.CircuitId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Rollup sub-client</summary>
|
||||||
|
public class RollupClient
|
||||||
|
{
|
||||||
|
private readonly SynorZk _zk;
|
||||||
|
|
||||||
|
internal RollupClient(SynorZk zk) => _zk = zk;
|
||||||
|
|
||||||
|
public Task<RollupStats> GetStatsAsync(CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<RollupStats>("/rollup/stats", ct);
|
||||||
|
|
||||||
|
public Task<Batch> GetCurrentBatchAsync(CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<Batch>("/rollup/batch/current", ct);
|
||||||
|
|
||||||
|
public Task<Batch> GetBatchAsync(long batchNumber, CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<Batch>($"/rollup/batch/{batchNumber}", ct);
|
||||||
|
|
||||||
|
public async Task<string> SubmitTransferAsync(Transfer transfer, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.PostAsync<TxIdResponse>("/rollup/transfer", transfer, ct);
|
||||||
|
return result.TxId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> SubmitDepositAsync(Deposit deposit, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.PostAsync<TxIdResponse>("/rollup/deposit", deposit, ct);
|
||||||
|
return result.TxId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> SubmitWithdrawalAsync(Withdrawal withdrawal, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.PostAsync<TxIdResponse>("/rollup/withdraw", withdrawal, ct);
|
||||||
|
return result.TxId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Batch> FinalizeBatchAsync(CancellationToken ct = default) =>
|
||||||
|
_zk.PostAsync<Batch>("/rollup/batch/finalize", null, ct);
|
||||||
|
|
||||||
|
public async Task<List<Transfer>> GetPendingTransactionsAsync(CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.GetAsync<TransactionsListResponse>("/rollup/pending", ct);
|
||||||
|
return result.Transactions ?? new List<Transfer>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>State sub-client</summary>
|
||||||
|
public class StateClient
|
||||||
|
{
|
||||||
|
private readonly SynorZk _zk;
|
||||||
|
|
||||||
|
internal StateClient(SynorZk zk) => _zk = zk;
|
||||||
|
|
||||||
|
public async Task<string> GetRootAsync(CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.GetAsync<RootResponse>("/state/root", ct);
|
||||||
|
return result.Root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AccountState> GetAccountAsync(string address, CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<AccountState>($"/state/account/{address}", ct);
|
||||||
|
|
||||||
|
public Task<MerkleProof> GetMerkleProofAsync(string address, CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<MerkleProof>($"/state/proof/{address}", ct);
|
||||||
|
|
||||||
|
public async Task<bool> VerifyMerkleProofAsync(MerkleProof proof, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.PostAsync<ValidResponse>("/state/proof/verify", proof, ct);
|
||||||
|
return result.Valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Dictionary<string, object>> GetStateAtBatchAsync(long batchNumber, CancellationToken ct = default) =>
|
||||||
|
_zk.GetAsync<Dictionary<string, object>>($"/state/batch/{batchNumber}", ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Ceremony sub-client</summary>
|
||||||
|
public class CeremonyClient
|
||||||
|
{
|
||||||
|
private readonly SynorZk _zk;
|
||||||
|
|
||||||
|
internal CeremonyClient(SynorZk zk) => _zk = zk;
|
||||||
|
|
||||||
|
public Task<TrustedSetup> GetStatusAsync(CircuitType circuitType, ProofSystem? system = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var sys = system ?? _zk.DefaultProofSystem;
|
||||||
|
return _zk.GetAsync<TrustedSetup>($"/ceremony/{circuitType.ToApiString()}?system={sys.ToApiString()}", ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<CeremonyContribution> ContributeAsync(CircuitType circuitType, byte[] entropy, ProofSystem? system = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var sys = system ?? _zk.DefaultProofSystem;
|
||||||
|
return _zk.PostAsync<CeremonyContribution>("/ceremony/contribute", new
|
||||||
|
{
|
||||||
|
circuit_type = circuitType.ToApiString(),
|
||||||
|
entropy = Convert.ToBase64String(entropy),
|
||||||
|
system = sys.ToApiString()
|
||||||
|
}, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> VerifyContributionAsync(CircuitType circuitType, string contributionHash, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.PostAsync<ValidResponse>("/ceremony/verify", new
|
||||||
|
{
|
||||||
|
circuit_type = circuitType.ToApiString(),
|
||||||
|
contribution_hash = contributionHash
|
||||||
|
}, ct);
|
||||||
|
return result.Valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<CeremonyContribution>> ListContributionsAsync(CircuitType circuitType, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var result = await _zk.GetAsync<ContributionsListResponse>($"/ceremony/{circuitType.ToApiString()}/contributions", ct);
|
||||||
|
return result.Contributions ?? new List<CeremonyContribution>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response helper types
|
||||||
|
internal record ProofsListResponse(List<Proof>? Proofs);
|
||||||
|
internal record CircuitsListResponse(List<CircuitConfig>? Circuits);
|
||||||
|
internal record TransactionsListResponse(List<Transfer>? Transactions);
|
||||||
|
internal record ContributionsListResponse(List<CeremonyContribution>? Contributions);
|
||||||
|
internal record SerializeResponse(string Data);
|
||||||
|
internal record CircuitIdResponse(string CircuitId);
|
||||||
|
internal record TxIdResponse(string TxId);
|
||||||
|
internal record RootResponse(string Root);
|
||||||
|
internal record ValidResponse(bool Valid);
|
||||||
246
sdk/csharp/src/Synor.Zk/Types.cs
Normal file
246
sdk/csharp/src/Synor.Zk/Types.cs
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Synor.Zk;
|
||||||
|
|
||||||
|
/// <summary>Proof system backends</summary>
|
||||||
|
public enum ProofSystem
|
||||||
|
{
|
||||||
|
/// <summary>Smallest proofs (~192 bytes), fastest verification</summary>
|
||||||
|
Groth16,
|
||||||
|
/// <summary>Universal trusted setup, medium proofs (~512 bytes)</summary>
|
||||||
|
Plonk,
|
||||||
|
/// <summary>No trusted setup, largest proofs (~50KB)</summary>
|
||||||
|
Stark
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Circuit types for different operations</summary>
|
||||||
|
public enum CircuitType
|
||||||
|
{
|
||||||
|
/// <summary>Single transfer between accounts</summary>
|
||||||
|
Transfer,
|
||||||
|
/// <summary>Batch of multiple transfers</summary>
|
||||||
|
Batch,
|
||||||
|
/// <summary>Deposit from L1 to L2</summary>
|
||||||
|
Deposit,
|
||||||
|
/// <summary>Withdrawal from L2 to L1</summary>
|
||||||
|
Withdraw
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Rollup state</summary>
|
||||||
|
public enum RollupState { Active, Paused, Finalizing, Finalized }
|
||||||
|
|
||||||
|
/// <summary>Proof status</summary>
|
||||||
|
public enum ProofStatus { Generating, Completed, Failed, Verified }
|
||||||
|
|
||||||
|
/// <summary>Zero-knowledge proof</summary>
|
||||||
|
public record Proof(
|
||||||
|
string Id,
|
||||||
|
ProofSystem System,
|
||||||
|
CircuitType CircuitType,
|
||||||
|
string Data,
|
||||||
|
List<string> PublicInputs,
|
||||||
|
int Size,
|
||||||
|
long GenerationTimeMs,
|
||||||
|
long CreatedAt
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Verification key for a circuit</summary>
|
||||||
|
public record VerificationKey(
|
||||||
|
string CircuitId,
|
||||||
|
CircuitType CircuitType,
|
||||||
|
ProofSystem System,
|
||||||
|
string Data,
|
||||||
|
int Size
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Proving key for generating proofs</summary>
|
||||||
|
public record ProvingKey(
|
||||||
|
string CircuitId,
|
||||||
|
CircuitType CircuitType,
|
||||||
|
ProofSystem System,
|
||||||
|
string Data,
|
||||||
|
int Size
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Circuit configuration</summary>
|
||||||
|
public record CircuitConfig(
|
||||||
|
CircuitType Type,
|
||||||
|
int? MaxBatchSize = null,
|
||||||
|
int? TreeDepth = null,
|
||||||
|
bool? VerifySignatures = null,
|
||||||
|
Dictionary<string, object>? CustomConstraints = null
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Account state in the rollup</summary>
|
||||||
|
public record AccountState(
|
||||||
|
string Address,
|
||||||
|
string Balance,
|
||||||
|
long Nonce,
|
||||||
|
string PubkeyHash
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Transfer operation</summary>
|
||||||
|
public record Transfer(
|
||||||
|
string From,
|
||||||
|
string To,
|
||||||
|
string Amount,
|
||||||
|
string Fee,
|
||||||
|
long Nonce,
|
||||||
|
string? Signature = null
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Deposit operation (L1 -> L2)</summary>
|
||||||
|
public record Deposit(
|
||||||
|
string L1TxHash,
|
||||||
|
string Recipient,
|
||||||
|
string Amount,
|
||||||
|
string? Token = null
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Withdrawal operation (L2 -> L1)</summary>
|
||||||
|
public record Withdrawal(
|
||||||
|
string Sender,
|
||||||
|
string Recipient,
|
||||||
|
string Amount,
|
||||||
|
string? Token,
|
||||||
|
long Nonce,
|
||||||
|
string? Signature = null
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Rollup batch</summary>
|
||||||
|
public record Batch(
|
||||||
|
long BatchNumber,
|
||||||
|
string PrevStateRoot,
|
||||||
|
string NewStateRoot,
|
||||||
|
List<Transfer> Transfers,
|
||||||
|
List<Deposit> Deposits,
|
||||||
|
List<Withdrawal> Withdrawals,
|
||||||
|
Proof? Proof,
|
||||||
|
long Timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Rollup statistics</summary>
|
||||||
|
public record RollupStats(
|
||||||
|
long CurrentBatch,
|
||||||
|
long TotalTransactions,
|
||||||
|
long TotalProofs,
|
||||||
|
long AvgProofTimeMs,
|
||||||
|
string StateRoot,
|
||||||
|
long AccountCount,
|
||||||
|
string Tvl
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Proof request</summary>
|
||||||
|
public record ProofRequest(
|
||||||
|
CircuitType CircuitType,
|
||||||
|
List<string> PublicInputs,
|
||||||
|
List<string> PrivateInputs,
|
||||||
|
ProofSystem? System = null
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Verification result</summary>
|
||||||
|
public record VerificationResult(
|
||||||
|
bool Valid,
|
||||||
|
long VerificationTimeMs,
|
||||||
|
string? Error = null
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Merkle proof for state inclusion</summary>
|
||||||
|
public record MerkleProof(
|
||||||
|
string Leaf,
|
||||||
|
List<string> Path,
|
||||||
|
List<int> Indices,
|
||||||
|
string Root
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Ceremony contribution</summary>
|
||||||
|
public record CeremonyContribution(
|
||||||
|
string ContributorId,
|
||||||
|
string Hash,
|
||||||
|
long Timestamp,
|
||||||
|
bool Verified
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Trusted setup ceremony</summary>
|
||||||
|
public record TrustedSetup(
|
||||||
|
string Id,
|
||||||
|
CircuitType CircuitType,
|
||||||
|
ProofSystem System,
|
||||||
|
int ContributionCount,
|
||||||
|
string LatestHash,
|
||||||
|
bool Complete,
|
||||||
|
List<CeremonyContribution> Contributions
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>ZK SDK configuration</summary>
|
||||||
|
public record ZkConfig(
|
||||||
|
string ApiKey,
|
||||||
|
string Endpoint = "https://zk.synor.io/v1",
|
||||||
|
string WsEndpoint = "wss://zk.synor.io/v1/ws",
|
||||||
|
int Timeout = 60000,
|
||||||
|
int Retries = 3,
|
||||||
|
ProofSystem DefaultProofSystem = ProofSystem.Groth16,
|
||||||
|
bool Debug = false
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>ZK SDK exception</summary>
|
||||||
|
public class ZkException : Exception
|
||||||
|
{
|
||||||
|
public string? Code { get; }
|
||||||
|
public int? Status { get; }
|
||||||
|
|
||||||
|
public ZkException(string message, string? code = null, int? status = null)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
Code = code;
|
||||||
|
Status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Proof system characteristics</summary>
|
||||||
|
public record ProofSystemInfo(
|
||||||
|
string Name,
|
||||||
|
int ProofSize,
|
||||||
|
int VerificationTimeMs,
|
||||||
|
bool TrustedSetup,
|
||||||
|
bool Universal
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>Extension methods</summary>
|
||||||
|
public static class ZkExtensions
|
||||||
|
{
|
||||||
|
public static string ToApiString(this ProofSystem system) => system switch
|
||||||
|
{
|
||||||
|
ProofSystem.Groth16 => "groth16",
|
||||||
|
ProofSystem.Plonk => "plonk",
|
||||||
|
ProofSystem.Stark => "stark",
|
||||||
|
_ => "groth16"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string ToApiString(this CircuitType type) => type switch
|
||||||
|
{
|
||||||
|
CircuitType.Transfer => "transfer",
|
||||||
|
CircuitType.Batch => "batch",
|
||||||
|
CircuitType.Deposit => "deposit",
|
||||||
|
CircuitType.Withdraw => "withdraw",
|
||||||
|
_ => "transfer"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ProofSystemInfo GetInfo(this ProofSystem system) => system switch
|
||||||
|
{
|
||||||
|
ProofSystem.Groth16 => new ProofSystemInfo("Groth16", 192, 10, true, false),
|
||||||
|
ProofSystem.Plonk => new ProofSystemInfo("PLONK", 512, 15, true, true),
|
||||||
|
ProofSystem.Stark => new ProofSystemInfo("STARK", 50000, 30, false, true),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(system))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Constants</summary>
|
||||||
|
public static class ZkConstants
|
||||||
|
{
|
||||||
|
public const int MaxBatchSize = 1000;
|
||||||
|
public const int StateTreeDepth = 32;
|
||||||
|
public const int ProofExpiryBlocks = 100;
|
||||||
|
}
|
||||||
415
sdk/flutter/lib/src/zk/client.dart
Normal file
415
sdk/flutter/lib/src/zk/client.dart
Normal file
|
|
@ -0,0 +1,415 @@
|
||||||
|
/// Synor ZK SDK Client for Flutter/Dart
|
||||||
|
///
|
||||||
|
/// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
library synor_zk_client;
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'types.dart';
|
||||||
|
|
||||||
|
export 'types.dart';
|
||||||
|
|
||||||
|
/// Synor ZK SDK Client
|
||||||
|
///
|
||||||
|
/// Provides zero-knowledge proof generation and verification for ZK-Rollups.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// final zk = SynorZk(ZkConfig(apiKey: 'your-api-key'));
|
||||||
|
///
|
||||||
|
/// // Generate a proof
|
||||||
|
/// final proof = await zk.proofs.generate(ProofRequest(
|
||||||
|
/// circuitType: CircuitType.transfer,
|
||||||
|
/// publicInputs: [...],
|
||||||
|
/// privateInputs: [...],
|
||||||
|
/// ));
|
||||||
|
///
|
||||||
|
/// // Verify the proof
|
||||||
|
/// final result = await zk.proofs.verify(proof);
|
||||||
|
/// print('Valid: ${result.valid}');
|
||||||
|
/// ```
|
||||||
|
class SynorZk {
|
||||||
|
final ZkConfig config;
|
||||||
|
final http.Client _client;
|
||||||
|
bool _closed = false;
|
||||||
|
|
||||||
|
late final ProofsClient proofs;
|
||||||
|
late final CircuitsClient circuits;
|
||||||
|
late final RollupClient rollup;
|
||||||
|
late final StateClient state;
|
||||||
|
late final CeremonyClient ceremony;
|
||||||
|
|
||||||
|
SynorZk(this.config, {http.Client? client})
|
||||||
|
: _client = client ?? http.Client() {
|
||||||
|
proofs = ProofsClient(this);
|
||||||
|
circuits = CircuitsClient(this);
|
||||||
|
rollup = RollupClient(this);
|
||||||
|
state = StateClient(this);
|
||||||
|
ceremony = CeremonyClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the default proof system
|
||||||
|
ProofSystem get defaultProofSystem => config.defaultProofSystem;
|
||||||
|
|
||||||
|
/// Health check
|
||||||
|
Future<bool> healthCheck() async {
|
||||||
|
try {
|
||||||
|
final result = await _get('/health');
|
||||||
|
return result['status'] == 'healthy';
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get service info
|
||||||
|
Future<Map<String, dynamic>> getInfo() async {
|
||||||
|
return _get('/info');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Close the client
|
||||||
|
void close() {
|
||||||
|
_closed = true;
|
||||||
|
_client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if client is closed
|
||||||
|
bool get isClosed => _closed;
|
||||||
|
|
||||||
|
// Internal HTTP methods
|
||||||
|
Future<Map<String, dynamic>> _get(String path) async {
|
||||||
|
return _request('GET', path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _post(String path, [Map<String, dynamic>? body]) async {
|
||||||
|
return _request('POST', path, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _delete(String path) async {
|
||||||
|
return _request('DELETE', path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _request(
|
||||||
|
String method,
|
||||||
|
String path, [
|
||||||
|
Map<String, dynamic>? body,
|
||||||
|
]) async {
|
||||||
|
if (_closed) {
|
||||||
|
throw const ZkError('Client has been closed', code: 'CLIENT_CLOSED');
|
||||||
|
}
|
||||||
|
|
||||||
|
final url = Uri.parse('${config.endpoint}$path');
|
||||||
|
final headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer ${config.apiKey}',
|
||||||
|
'X-SDK-Version': 'flutter/0.1.0',
|
||||||
|
};
|
||||||
|
|
||||||
|
Exception? lastError;
|
||||||
|
|
||||||
|
for (var attempt = 0; attempt <= config.retries; attempt++) {
|
||||||
|
try {
|
||||||
|
http.Response response;
|
||||||
|
switch (method) {
|
||||||
|
case 'GET':
|
||||||
|
response = await _client
|
||||||
|
.get(url, headers: headers)
|
||||||
|
.timeout(config.timeout);
|
||||||
|
break;
|
||||||
|
case 'POST':
|
||||||
|
response = await _client
|
||||||
|
.post(url, headers: headers, body: body != null ? jsonEncode(body) : null)
|
||||||
|
.timeout(config.timeout);
|
||||||
|
break;
|
||||||
|
case 'DELETE':
|
||||||
|
response = await _client
|
||||||
|
.delete(url, headers: headers)
|
||||||
|
.timeout(config.timeout);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ArgumentError('Unknown method: $method');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.statusCode >= 400) {
|
||||||
|
final error = response.body.isNotEmpty
|
||||||
|
? jsonDecode(response.body) as Map<String, dynamic>
|
||||||
|
: <String, dynamic>{};
|
||||||
|
throw ZkError(
|
||||||
|
error['message'] as String? ?? 'HTTP ${response.statusCode}',
|
||||||
|
code: error['code'] as String?,
|
||||||
|
status: response.statusCode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonDecode(response.body) as Map<String, dynamic>;
|
||||||
|
} on ZkError {
|
||||||
|
rethrow;
|
||||||
|
} catch (e) {
|
||||||
|
lastError = e as Exception;
|
||||||
|
if (attempt < config.retries) {
|
||||||
|
await Future.delayed(Duration(milliseconds: 100 * (1 << attempt)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ZkError(
|
||||||
|
lastError?.toString() ?? 'Request failed',
|
||||||
|
code: 'NETWORK_ERROR',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proofs sub-client
|
||||||
|
class ProofsClient {
|
||||||
|
final SynorZk _zk;
|
||||||
|
|
||||||
|
ProofsClient(this._zk);
|
||||||
|
|
||||||
|
/// Generate a zero-knowledge proof
|
||||||
|
Future<Proof> generate(ProofRequest request) async {
|
||||||
|
final body = request.toJson();
|
||||||
|
body['system'] ??= _zk.defaultProofSystem.value;
|
||||||
|
final result = await _zk._post('/proofs/generate', body);
|
||||||
|
return Proof.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a proof
|
||||||
|
Future<VerificationResult> verify(Proof proof) async {
|
||||||
|
final result = await _zk._post('/proofs/verify', {
|
||||||
|
'proof_id': proof.id,
|
||||||
|
'data': proof.data,
|
||||||
|
'public_inputs': proof.publicInputs,
|
||||||
|
'system': proof.system.value,
|
||||||
|
'circuit_type': proof.circuitType.value,
|
||||||
|
});
|
||||||
|
return VerificationResult.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a proof by ID
|
||||||
|
Future<Proof> get(String proofId) async {
|
||||||
|
final result = await _zk._get('/proofs/$proofId');
|
||||||
|
return Proof.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List recent proofs
|
||||||
|
Future<List<Proof>> list({int? limit, int? offset}) async {
|
||||||
|
var path = '/proofs';
|
||||||
|
final params = <String>[];
|
||||||
|
if (limit != null) params.add('limit=$limit');
|
||||||
|
if (offset != null) params.add('offset=$offset');
|
||||||
|
if (params.isNotEmpty) path += '?${params.join('&')}';
|
||||||
|
|
||||||
|
final result = await _zk._get(path);
|
||||||
|
final proofs = result['proofs'] as List?;
|
||||||
|
return proofs?.map((p) => Proof.fromJson(p as Map<String, dynamic>)).toList() ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize a proof to bytes
|
||||||
|
Future<Uint8List> serialize(Proof proof) async {
|
||||||
|
final result = await _zk._post('/proofs/serialize', {'proof_id': proof.id});
|
||||||
|
return base64Decode(result['data'] as String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize bytes to a proof
|
||||||
|
Future<Proof> deserialize(Uint8List data, ProofSystem system) async {
|
||||||
|
final result = await _zk._post('/proofs/deserialize', {
|
||||||
|
'data': base64Encode(data),
|
||||||
|
'system': system.value,
|
||||||
|
});
|
||||||
|
return Proof.fromJson(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuits sub-client
|
||||||
|
class CircuitsClient {
|
||||||
|
final SynorZk _zk;
|
||||||
|
|
||||||
|
CircuitsClient(this._zk);
|
||||||
|
|
||||||
|
/// Get verification key for a circuit
|
||||||
|
Future<VerificationKey> getVerificationKey(
|
||||||
|
CircuitType circuitType, [
|
||||||
|
ProofSystem? system,
|
||||||
|
]) async {
|
||||||
|
final sys = system ?? _zk.defaultProofSystem;
|
||||||
|
final result = await _zk._get('/circuits/${circuitType.value}/vk?system=${sys.value}');
|
||||||
|
return VerificationKey.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get proving key for a circuit
|
||||||
|
Future<ProvingKey> getProvingKey(
|
||||||
|
CircuitType circuitType, [
|
||||||
|
ProofSystem? system,
|
||||||
|
]) async {
|
||||||
|
final sys = system ?? _zk.defaultProofSystem;
|
||||||
|
final result = await _zk._get('/circuits/${circuitType.value}/pk?system=${sys.value}');
|
||||||
|
return ProvingKey.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List available circuits
|
||||||
|
Future<List<CircuitConfig>> list() async {
|
||||||
|
final result = await _zk._get('/circuits');
|
||||||
|
final circuits = result['circuits'] as List?;
|
||||||
|
return circuits?.map((c) => CircuitConfig.fromJson(c as Map<String, dynamic>)).toList() ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get circuit configuration
|
||||||
|
Future<CircuitConfig> getConfig(CircuitType circuitType) async {
|
||||||
|
final result = await _zk._get('/circuits/${circuitType.value}/config');
|
||||||
|
return CircuitConfig.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile a custom circuit
|
||||||
|
Future<String> compile(CircuitConfig config) async {
|
||||||
|
final result = await _zk._post('/circuits/compile', config.toJson());
|
||||||
|
return result['circuit_id'] as String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup sub-client
|
||||||
|
class RollupClient {
|
||||||
|
final SynorZk _zk;
|
||||||
|
|
||||||
|
RollupClient(this._zk);
|
||||||
|
|
||||||
|
/// Get rollup statistics
|
||||||
|
Future<RollupStats> getStats() async {
|
||||||
|
final result = await _zk._get('/rollup/stats');
|
||||||
|
return RollupStats.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current batch
|
||||||
|
Future<Batch> getCurrentBatch() async {
|
||||||
|
final result = await _zk._get('/rollup/batch/current');
|
||||||
|
return Batch.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get batch by number
|
||||||
|
Future<Batch> getBatch(int batchNumber) async {
|
||||||
|
final result = await _zk._get('/rollup/batch/$batchNumber');
|
||||||
|
return Batch.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit a transfer
|
||||||
|
Future<String> submitTransfer(Transfer transfer) async {
|
||||||
|
final result = await _zk._post('/rollup/transfer', transfer.toJson());
|
||||||
|
return result['tx_id'] as String;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit a deposit
|
||||||
|
Future<String> submitDeposit(Deposit deposit) async {
|
||||||
|
final result = await _zk._post('/rollup/deposit', deposit.toJson());
|
||||||
|
return result['tx_id'] as String;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit a withdrawal
|
||||||
|
Future<String> submitWithdrawal(Withdrawal withdrawal) async {
|
||||||
|
final result = await _zk._post('/rollup/withdraw', withdrawal.toJson());
|
||||||
|
return result['tx_id'] as String;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finalize current batch
|
||||||
|
Future<Batch> finalizeBatch() async {
|
||||||
|
final result = await _zk._post('/rollup/batch/finalize', {});
|
||||||
|
return Batch.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get pending transactions
|
||||||
|
Future<List<Transfer>> getPendingTransactions() async {
|
||||||
|
final result = await _zk._get('/rollup/pending');
|
||||||
|
final transactions = result['transactions'] as List?;
|
||||||
|
return transactions?.map((t) => Transfer.fromJson(t as Map<String, dynamic>)).toList() ?? [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State sub-client
|
||||||
|
class StateClient {
|
||||||
|
final SynorZk _zk;
|
||||||
|
|
||||||
|
StateClient(this._zk);
|
||||||
|
|
||||||
|
/// Get current state root
|
||||||
|
Future<String> getRoot() async {
|
||||||
|
final result = await _zk._get('/state/root');
|
||||||
|
return result['root'] as String;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get account state
|
||||||
|
Future<AccountState> getAccount(String address) async {
|
||||||
|
final result = await _zk._get('/state/account/$address');
|
||||||
|
return AccountState.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get merkle proof for account inclusion
|
||||||
|
Future<MerkleProof> getMerkleProof(String address) async {
|
||||||
|
final result = await _zk._get('/state/proof/$address');
|
||||||
|
return MerkleProof.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify merkle proof
|
||||||
|
Future<bool> verifyMerkleProof(MerkleProof proof) async {
|
||||||
|
final result = await _zk._post('/state/proof/verify', proof.toJson());
|
||||||
|
return result['valid'] as bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get state at specific batch
|
||||||
|
Future<Map<String, dynamic>> getStateAtBatch(int batchNumber) async {
|
||||||
|
return _zk._get('/state/batch/$batchNumber');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ceremony sub-client (trusted setup)
|
||||||
|
class CeremonyClient {
|
||||||
|
final SynorZk _zk;
|
||||||
|
|
||||||
|
CeremonyClient(this._zk);
|
||||||
|
|
||||||
|
/// Get ceremony status
|
||||||
|
Future<TrustedSetup> getStatus(
|
||||||
|
CircuitType circuitType, [
|
||||||
|
ProofSystem? system,
|
||||||
|
]) async {
|
||||||
|
final sys = system ?? _zk.defaultProofSystem;
|
||||||
|
final result = await _zk._get('/ceremony/${circuitType.value}?system=${sys.value}');
|
||||||
|
return TrustedSetup.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contribute to ceremony
|
||||||
|
Future<CeremonyContribution> contribute(
|
||||||
|
CircuitType circuitType,
|
||||||
|
Uint8List entropy, [
|
||||||
|
ProofSystem? system,
|
||||||
|
]) async {
|
||||||
|
final sys = system ?? _zk.defaultProofSystem;
|
||||||
|
final result = await _zk._post('/ceremony/contribute', {
|
||||||
|
'circuit_type': circuitType.value,
|
||||||
|
'entropy': base64Encode(entropy),
|
||||||
|
'system': sys.value,
|
||||||
|
});
|
||||||
|
return CeremonyContribution.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a contribution
|
||||||
|
Future<bool> verifyContribution(
|
||||||
|
CircuitType circuitType,
|
||||||
|
String contributionHash,
|
||||||
|
) async {
|
||||||
|
final result = await _zk._post('/ceremony/verify', {
|
||||||
|
'circuit_type': circuitType.value,
|
||||||
|
'contribution_hash': contributionHash,
|
||||||
|
});
|
||||||
|
return result['valid'] as bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List contributions
|
||||||
|
Future<List<CeremonyContribution>> listContributions(
|
||||||
|
CircuitType circuitType,
|
||||||
|
) async {
|
||||||
|
final result = await _zk._get('/ceremony/${circuitType.value}/contributions');
|
||||||
|
final contributions = result['contributions'] as List?;
|
||||||
|
return contributions
|
||||||
|
?.map((c) => CeremonyContribution.fromJson(c as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[];
|
||||||
|
}
|
||||||
|
}
|
||||||
682
sdk/flutter/lib/src/zk/types.dart
Normal file
682
sdk/flutter/lib/src/zk/types.dart
Normal file
|
|
@ -0,0 +1,682 @@
|
||||||
|
/// Synor ZK SDK Types for Flutter/Dart
|
||||||
|
///
|
||||||
|
/// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
library synor_zk_types;
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
/// Proof system backends
|
||||||
|
enum ProofSystem {
|
||||||
|
/// Groth16 - smallest proofs (~192 bytes), fastest verification
|
||||||
|
groth16,
|
||||||
|
/// PLONK - universal trusted setup, medium proofs (~512 bytes)
|
||||||
|
plonk,
|
||||||
|
/// STARK - no trusted setup, largest proofs (~50KB)
|
||||||
|
stark,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ProofSystemExtension on ProofSystem {
|
||||||
|
String get value {
|
||||||
|
switch (this) {
|
||||||
|
case ProofSystem.groth16:
|
||||||
|
return 'groth16';
|
||||||
|
case ProofSystem.plonk:
|
||||||
|
return 'plonk';
|
||||||
|
case ProofSystem.stark:
|
||||||
|
return 'stark';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ProofSystem fromString(String value) {
|
||||||
|
switch (value) {
|
||||||
|
case 'groth16':
|
||||||
|
return ProofSystem.groth16;
|
||||||
|
case 'plonk':
|
||||||
|
return ProofSystem.plonk;
|
||||||
|
case 'stark':
|
||||||
|
return ProofSystem.stark;
|
||||||
|
default:
|
||||||
|
return ProofSystem.groth16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuit types for different operations
|
||||||
|
enum CircuitType {
|
||||||
|
/// Single transfer between accounts
|
||||||
|
transfer,
|
||||||
|
/// Batch of multiple transfers
|
||||||
|
batch,
|
||||||
|
/// Deposit from L1 to L2
|
||||||
|
deposit,
|
||||||
|
/// Withdrawal from L2 to L1
|
||||||
|
withdraw,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension CircuitTypeExtension on CircuitType {
|
||||||
|
String get value {
|
||||||
|
switch (this) {
|
||||||
|
case CircuitType.transfer:
|
||||||
|
return 'transfer';
|
||||||
|
case CircuitType.batch:
|
||||||
|
return 'batch';
|
||||||
|
case CircuitType.deposit:
|
||||||
|
return 'deposit';
|
||||||
|
case CircuitType.withdraw:
|
||||||
|
return 'withdraw';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CircuitType fromString(String value) {
|
||||||
|
switch (value) {
|
||||||
|
case 'transfer':
|
||||||
|
return CircuitType.transfer;
|
||||||
|
case 'batch':
|
||||||
|
return CircuitType.batch;
|
||||||
|
case 'deposit':
|
||||||
|
return CircuitType.deposit;
|
||||||
|
case 'withdraw':
|
||||||
|
return CircuitType.withdraw;
|
||||||
|
default:
|
||||||
|
return CircuitType.transfer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup state
|
||||||
|
enum RollupState {
|
||||||
|
active,
|
||||||
|
paused,
|
||||||
|
finalizing,
|
||||||
|
finalized,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof status
|
||||||
|
enum ProofStatus {
|
||||||
|
generating,
|
||||||
|
completed,
|
||||||
|
failed,
|
||||||
|
verified,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Zero-knowledge proof
|
||||||
|
class Proof {
|
||||||
|
final String id;
|
||||||
|
final ProofSystem system;
|
||||||
|
final CircuitType circuitType;
|
||||||
|
final String data; // Base64 encoded
|
||||||
|
final List<String> publicInputs;
|
||||||
|
final int size;
|
||||||
|
final int generationTimeMs;
|
||||||
|
final int createdAt;
|
||||||
|
|
||||||
|
const Proof({
|
||||||
|
required this.id,
|
||||||
|
required this.system,
|
||||||
|
required this.circuitType,
|
||||||
|
required this.data,
|
||||||
|
required this.publicInputs,
|
||||||
|
required this.size,
|
||||||
|
required this.generationTimeMs,
|
||||||
|
required this.createdAt,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Proof.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Proof(
|
||||||
|
id: json['id'] as String,
|
||||||
|
system: ProofSystemExtension.fromString(json['system'] as String),
|
||||||
|
circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
|
||||||
|
data: json['data'] as String,
|
||||||
|
publicInputs: List<String>.from(json['public_inputs'] ?? []),
|
||||||
|
size: json['size'] as int? ?? 0,
|
||||||
|
generationTimeMs: json['generation_time_ms'] as int? ?? 0,
|
||||||
|
createdAt: json['created_at'] as int? ?? 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'id': id,
|
||||||
|
'system': system.value,
|
||||||
|
'circuit_type': circuitType.value,
|
||||||
|
'data': data,
|
||||||
|
'public_inputs': publicInputs,
|
||||||
|
'size': size,
|
||||||
|
'generation_time_ms': generationTimeMs,
|
||||||
|
'created_at': createdAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verification key for a circuit
|
||||||
|
class VerificationKey {
|
||||||
|
final String circuitId;
|
||||||
|
final CircuitType circuitType;
|
||||||
|
final ProofSystem system;
|
||||||
|
final String data; // Base64 encoded
|
||||||
|
final int size;
|
||||||
|
|
||||||
|
const VerificationKey({
|
||||||
|
required this.circuitId,
|
||||||
|
required this.circuitType,
|
||||||
|
required this.system,
|
||||||
|
required this.data,
|
||||||
|
required this.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory VerificationKey.fromJson(Map<String, dynamic> json) {
|
||||||
|
return VerificationKey(
|
||||||
|
circuitId: json['circuit_id'] as String,
|
||||||
|
circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
|
||||||
|
system: ProofSystemExtension.fromString(json['system'] as String),
|
||||||
|
data: json['data'] as String,
|
||||||
|
size: json['size'] as int? ?? 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proving key for generating proofs
|
||||||
|
class ProvingKey {
|
||||||
|
final String circuitId;
|
||||||
|
final CircuitType circuitType;
|
||||||
|
final ProofSystem system;
|
||||||
|
final String data; // Base64 encoded
|
||||||
|
final int size;
|
||||||
|
|
||||||
|
const ProvingKey({
|
||||||
|
required this.circuitId,
|
||||||
|
required this.circuitType,
|
||||||
|
required this.system,
|
||||||
|
required this.data,
|
||||||
|
required this.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ProvingKey.fromJson(Map<String, dynamic> json) {
|
||||||
|
return ProvingKey(
|
||||||
|
circuitId: json['circuit_id'] as String,
|
||||||
|
circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
|
||||||
|
system: ProofSystemExtension.fromString(json['system'] as String),
|
||||||
|
data: json['data'] as String,
|
||||||
|
size: json['size'] as int? ?? 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuit configuration
|
||||||
|
class CircuitConfig {
|
||||||
|
final CircuitType type;
|
||||||
|
final int? maxBatchSize;
|
||||||
|
final int? treeDepth;
|
||||||
|
final bool? verifySignatures;
|
||||||
|
final Map<String, dynamic>? customConstraints;
|
||||||
|
|
||||||
|
const CircuitConfig({
|
||||||
|
required this.type,
|
||||||
|
this.maxBatchSize,
|
||||||
|
this.treeDepth,
|
||||||
|
this.verifySignatures,
|
||||||
|
this.customConstraints,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory CircuitConfig.fromJson(Map<String, dynamic> json) {
|
||||||
|
return CircuitConfig(
|
||||||
|
type: CircuitTypeExtension.fromString(json['type'] as String),
|
||||||
|
maxBatchSize: json['max_batch_size'] as int?,
|
||||||
|
treeDepth: json['tree_depth'] as int?,
|
||||||
|
verifySignatures: json['verify_signatures'] as bool?,
|
||||||
|
customConstraints: json['custom_constraints'] as Map<String, dynamic>?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final result = <String, dynamic>{'type': type.value};
|
||||||
|
if (maxBatchSize != null) result['max_batch_size'] = maxBatchSize;
|
||||||
|
if (treeDepth != null) result['tree_depth'] = treeDepth;
|
||||||
|
if (verifySignatures != null) result['verify_signatures'] = verifySignatures;
|
||||||
|
if (customConstraints != null) result['custom_constraints'] = customConstraints;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Account state in the rollup
|
||||||
|
class AccountState {
|
||||||
|
final String address;
|
||||||
|
final String balance;
|
||||||
|
final int nonce;
|
||||||
|
final String pubkeyHash;
|
||||||
|
|
||||||
|
const AccountState({
|
||||||
|
required this.address,
|
||||||
|
required this.balance,
|
||||||
|
required this.nonce,
|
||||||
|
required this.pubkeyHash,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory AccountState.fromJson(Map<String, dynamic> json) {
|
||||||
|
return AccountState(
|
||||||
|
address: json['address'] as String,
|
||||||
|
balance: json['balance'] as String,
|
||||||
|
nonce: json['nonce'] as int? ?? 0,
|
||||||
|
pubkeyHash: json['pubkey_hash'] as String? ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transfer operation
|
||||||
|
class Transfer {
|
||||||
|
final String from;
|
||||||
|
final String to;
|
||||||
|
final String amount;
|
||||||
|
final String fee;
|
||||||
|
final int nonce;
|
||||||
|
final String? signature;
|
||||||
|
|
||||||
|
const Transfer({
|
||||||
|
required this.from,
|
||||||
|
required this.to,
|
||||||
|
required this.amount,
|
||||||
|
required this.fee,
|
||||||
|
required this.nonce,
|
||||||
|
this.signature,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Transfer.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Transfer(
|
||||||
|
from: json['from'] as String,
|
||||||
|
to: json['to'] as String,
|
||||||
|
amount: json['amount'] as String,
|
||||||
|
fee: json['fee'] as String,
|
||||||
|
nonce: json['nonce'] as int? ?? 0,
|
||||||
|
signature: json['signature'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final result = <String, dynamic>{
|
||||||
|
'from': from,
|
||||||
|
'to': to,
|
||||||
|
'amount': amount,
|
||||||
|
'fee': fee,
|
||||||
|
'nonce': nonce,
|
||||||
|
};
|
||||||
|
if (signature != null) result['signature'] = signature;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deposit operation (L1 -> L2)
|
||||||
|
class Deposit {
|
||||||
|
final String l1TxHash;
|
||||||
|
final String recipient;
|
||||||
|
final String amount;
|
||||||
|
final String? token;
|
||||||
|
|
||||||
|
const Deposit({
|
||||||
|
required this.l1TxHash,
|
||||||
|
required this.recipient,
|
||||||
|
required this.amount,
|
||||||
|
this.token,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Deposit.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Deposit(
|
||||||
|
l1TxHash: json['l1_tx_hash'] as String,
|
||||||
|
recipient: json['recipient'] as String,
|
||||||
|
amount: json['amount'] as String,
|
||||||
|
token: json['token'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final result = <String, dynamic>{
|
||||||
|
'l1_tx_hash': l1TxHash,
|
||||||
|
'recipient': recipient,
|
||||||
|
'amount': amount,
|
||||||
|
};
|
||||||
|
if (token != null) result['token'] = token;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Withdrawal operation (L2 -> L1)
|
||||||
|
class Withdrawal {
|
||||||
|
final String sender;
|
||||||
|
final String recipient;
|
||||||
|
final String amount;
|
||||||
|
final String? token;
|
||||||
|
final int nonce;
|
||||||
|
final String? signature;
|
||||||
|
|
||||||
|
const Withdrawal({
|
||||||
|
required this.sender,
|
||||||
|
required this.recipient,
|
||||||
|
required this.amount,
|
||||||
|
this.token,
|
||||||
|
required this.nonce,
|
||||||
|
this.signature,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Withdrawal.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Withdrawal(
|
||||||
|
sender: json['sender'] as String,
|
||||||
|
recipient: json['recipient'] as String,
|
||||||
|
amount: json['amount'] as String,
|
||||||
|
token: json['token'] as String?,
|
||||||
|
nonce: json['nonce'] as int? ?? 0,
|
||||||
|
signature: json['signature'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final result = <String, dynamic>{
|
||||||
|
'sender': sender,
|
||||||
|
'recipient': recipient,
|
||||||
|
'amount': amount,
|
||||||
|
'nonce': nonce,
|
||||||
|
};
|
||||||
|
if (token != null) result['token'] = token;
|
||||||
|
if (signature != null) result['signature'] = signature;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup batch
|
||||||
|
class Batch {
|
||||||
|
final int batchNumber;
|
||||||
|
final String prevStateRoot;
|
||||||
|
final String newStateRoot;
|
||||||
|
final List<Transfer> transfers;
|
||||||
|
final List<Deposit> deposits;
|
||||||
|
final List<Withdrawal> withdrawals;
|
||||||
|
final Proof? proof;
|
||||||
|
final int timestamp;
|
||||||
|
|
||||||
|
const Batch({
|
||||||
|
required this.batchNumber,
|
||||||
|
required this.prevStateRoot,
|
||||||
|
required this.newStateRoot,
|
||||||
|
required this.transfers,
|
||||||
|
required this.deposits,
|
||||||
|
required this.withdrawals,
|
||||||
|
this.proof,
|
||||||
|
required this.timestamp,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Batch.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Batch(
|
||||||
|
batchNumber: json['batch_number'] as int,
|
||||||
|
prevStateRoot: json['prev_state_root'] as String,
|
||||||
|
newStateRoot: json['new_state_root'] as String,
|
||||||
|
transfers: (json['transfers'] as List?)
|
||||||
|
?.map((t) => Transfer.fromJson(t as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
|
deposits: (json['deposits'] as List?)
|
||||||
|
?.map((d) => Deposit.fromJson(d as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
|
withdrawals: (json['withdrawals'] as List?)
|
||||||
|
?.map((w) => Withdrawal.fromJson(w as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
|
proof: json['proof'] != null
|
||||||
|
? Proof.fromJson(json['proof'] as Map<String, dynamic>)
|
||||||
|
: null,
|
||||||
|
timestamp: json['timestamp'] as int? ?? 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup statistics
|
||||||
|
class RollupStats {
|
||||||
|
final int currentBatch;
|
||||||
|
final int totalTransactions;
|
||||||
|
final int totalProofs;
|
||||||
|
final int avgProofTimeMs;
|
||||||
|
final String stateRoot;
|
||||||
|
final int accountCount;
|
||||||
|
final String tvl;
|
||||||
|
|
||||||
|
const RollupStats({
|
||||||
|
required this.currentBatch,
|
||||||
|
required this.totalTransactions,
|
||||||
|
required this.totalProofs,
|
||||||
|
required this.avgProofTimeMs,
|
||||||
|
required this.stateRoot,
|
||||||
|
required this.accountCount,
|
||||||
|
required this.tvl,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory RollupStats.fromJson(Map<String, dynamic> json) {
|
||||||
|
return RollupStats(
|
||||||
|
currentBatch: json['current_batch'] as int,
|
||||||
|
totalTransactions: json['total_transactions'] as int? ?? 0,
|
||||||
|
totalProofs: json['total_proofs'] as int? ?? 0,
|
||||||
|
avgProofTimeMs: json['avg_proof_time_ms'] as int? ?? 0,
|
||||||
|
stateRoot: json['state_root'] as String,
|
||||||
|
accountCount: json['account_count'] as int? ?? 0,
|
||||||
|
tvl: json['tvl'] as String? ?? '0',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof generation request
|
||||||
|
class ProofRequest {
|
||||||
|
final CircuitType circuitType;
|
||||||
|
final List<String> publicInputs;
|
||||||
|
final List<String> privateInputs;
|
||||||
|
final ProofSystem? system;
|
||||||
|
|
||||||
|
const ProofRequest({
|
||||||
|
required this.circuitType,
|
||||||
|
required this.publicInputs,
|
||||||
|
required this.privateInputs,
|
||||||
|
this.system,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final result = <String, dynamic>{
|
||||||
|
'circuit_type': circuitType.value,
|
||||||
|
'public_inputs': publicInputs,
|
||||||
|
'private_inputs': privateInputs,
|
||||||
|
};
|
||||||
|
if (system != null) result['system'] = system!.value;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof verification result
|
||||||
|
class VerificationResult {
|
||||||
|
final bool valid;
|
||||||
|
final int verificationTimeMs;
|
||||||
|
final String? error;
|
||||||
|
|
||||||
|
const VerificationResult({
|
||||||
|
required this.valid,
|
||||||
|
required this.verificationTimeMs,
|
||||||
|
this.error,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory VerificationResult.fromJson(Map<String, dynamic> json) {
|
||||||
|
return VerificationResult(
|
||||||
|
valid: json['valid'] as bool,
|
||||||
|
verificationTimeMs: json['verification_time_ms'] as int? ?? 0,
|
||||||
|
error: json['error'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merkle proof for state inclusion
|
||||||
|
class MerkleProof {
|
||||||
|
final String leaf;
|
||||||
|
final List<String> path;
|
||||||
|
final List<int> indices;
|
||||||
|
final String root;
|
||||||
|
|
||||||
|
const MerkleProof({
|
||||||
|
required this.leaf,
|
||||||
|
required this.path,
|
||||||
|
required this.indices,
|
||||||
|
required this.root,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory MerkleProof.fromJson(Map<String, dynamic> json) {
|
||||||
|
return MerkleProof(
|
||||||
|
leaf: json['leaf'] as String,
|
||||||
|
path: List<String>.from(json['path']),
|
||||||
|
indices: List<int>.from(json['indices']),
|
||||||
|
root: json['root'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'leaf': leaf,
|
||||||
|
'path': path,
|
||||||
|
'indices': indices,
|
||||||
|
'root': root,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trusted setup ceremony contribution
|
||||||
|
class CeremonyContribution {
|
||||||
|
final String contributorId;
|
||||||
|
final String hash;
|
||||||
|
final int timestamp;
|
||||||
|
final bool verified;
|
||||||
|
|
||||||
|
const CeremonyContribution({
|
||||||
|
required this.contributorId,
|
||||||
|
required this.hash,
|
||||||
|
required this.timestamp,
|
||||||
|
required this.verified,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory CeremonyContribution.fromJson(Map<String, dynamic> json) {
|
||||||
|
return CeremonyContribution(
|
||||||
|
contributorId: json['contributor_id'] as String,
|
||||||
|
hash: json['hash'] as String,
|
||||||
|
timestamp: json['timestamp'] as int? ?? 0,
|
||||||
|
verified: json['verified'] as bool? ?? false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trusted setup ceremony
|
||||||
|
class TrustedSetup {
|
||||||
|
final String id;
|
||||||
|
final CircuitType circuitType;
|
||||||
|
final ProofSystem system;
|
||||||
|
final int contributionCount;
|
||||||
|
final String latestHash;
|
||||||
|
final bool complete;
|
||||||
|
final List<CeremonyContribution> contributions;
|
||||||
|
|
||||||
|
const TrustedSetup({
|
||||||
|
required this.id,
|
||||||
|
required this.circuitType,
|
||||||
|
required this.system,
|
||||||
|
required this.contributionCount,
|
||||||
|
required this.latestHash,
|
||||||
|
required this.complete,
|
||||||
|
required this.contributions,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory TrustedSetup.fromJson(Map<String, dynamic> json) {
|
||||||
|
return TrustedSetup(
|
||||||
|
id: json['id'] as String,
|
||||||
|
circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
|
||||||
|
system: ProofSystemExtension.fromString(json['system'] as String),
|
||||||
|
contributionCount: json['contribution_count'] as int? ?? 0,
|
||||||
|
latestHash: json['latest_hash'] as String? ?? '',
|
||||||
|
complete: json['complete'] as bool? ?? false,
|
||||||
|
contributions: (json['contributions'] as List?)
|
||||||
|
?.map((c) => CeremonyContribution.fromJson(c as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ZK SDK configuration
|
||||||
|
class ZkConfig {
|
||||||
|
final String apiKey;
|
||||||
|
final String endpoint;
|
||||||
|
final String wsEndpoint;
|
||||||
|
final Duration timeout;
|
||||||
|
final int retries;
|
||||||
|
final ProofSystem defaultProofSystem;
|
||||||
|
final bool debug;
|
||||||
|
|
||||||
|
const ZkConfig({
|
||||||
|
required this.apiKey,
|
||||||
|
this.endpoint = 'https://zk.synor.io/v1',
|
||||||
|
this.wsEndpoint = 'wss://zk.synor.io/v1/ws',
|
||||||
|
this.timeout = const Duration(seconds: 60),
|
||||||
|
this.retries = 3,
|
||||||
|
this.defaultProofSystem = ProofSystem.groth16,
|
||||||
|
this.debug = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ZK SDK error
|
||||||
|
class ZkError implements Exception {
|
||||||
|
final String message;
|
||||||
|
final String? code;
|
||||||
|
final int? status;
|
||||||
|
|
||||||
|
const ZkError(this.message, {this.code, this.status});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => code != null ? 'ZkError: $message ($code)' : 'ZkError: $message';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof system characteristics
|
||||||
|
class ProofSystemInfo {
|
||||||
|
final String name;
|
||||||
|
final int proofSize;
|
||||||
|
final int verificationTimeMs;
|
||||||
|
final bool trustedSetup;
|
||||||
|
final bool universal;
|
||||||
|
|
||||||
|
const ProofSystemInfo({
|
||||||
|
required this.name,
|
||||||
|
required this.proofSize,
|
||||||
|
required this.verificationTimeMs,
|
||||||
|
required this.trustedSetup,
|
||||||
|
required this.universal,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get proof system info
|
||||||
|
ProofSystemInfo getProofSystemInfo(ProofSystem system) {
|
||||||
|
switch (system) {
|
||||||
|
case ProofSystem.groth16:
|
||||||
|
return const ProofSystemInfo(
|
||||||
|
name: 'Groth16',
|
||||||
|
proofSize: 192,
|
||||||
|
verificationTimeMs: 10,
|
||||||
|
trustedSetup: true,
|
||||||
|
universal: false,
|
||||||
|
);
|
||||||
|
case ProofSystem.plonk:
|
||||||
|
return const ProofSystemInfo(
|
||||||
|
name: 'PLONK',
|
||||||
|
proofSize: 512,
|
||||||
|
verificationTimeMs: 15,
|
||||||
|
trustedSetup: true,
|
||||||
|
universal: true,
|
||||||
|
);
|
||||||
|
case ProofSystem.stark:
|
||||||
|
return const ProofSystemInfo(
|
||||||
|
name: 'STARK',
|
||||||
|
proofSize: 50000,
|
||||||
|
verificationTimeMs: 30,
|
||||||
|
trustedSetup: false,
|
||||||
|
universal: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constants
|
||||||
|
const int maxBatchSize = 1000;
|
||||||
|
const int stateTreeDepth = 32;
|
||||||
|
const int proofExpiryBlocks = 100;
|
||||||
496
sdk/go/zk/client.go
Normal file
496
sdk/go/zk/client.go
Normal file
|
|
@ -0,0 +1,496 @@
|
||||||
|
// Package zk provides the Synor ZK SDK for Go.
|
||||||
|
package zk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client is the main ZK SDK client
|
||||||
|
type Client struct {
|
||||||
|
config Config
|
||||||
|
httpClient *http.Client
|
||||||
|
closed atomic.Bool
|
||||||
|
|
||||||
|
Proofs *ProofsClient
|
||||||
|
Circuits *CircuitsClient
|
||||||
|
Rollup *RollupClient
|
||||||
|
State *StateClient
|
||||||
|
Ceremony *CeremonyClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new ZK SDK client
|
||||||
|
func New(config Config) *Client {
|
||||||
|
c := &Client{
|
||||||
|
config: config,
|
||||||
|
httpClient: &http.Client{
|
||||||
|
Timeout: config.Timeout,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Proofs = &ProofsClient{client: c}
|
||||||
|
c.Circuits = &CircuitsClient{client: c}
|
||||||
|
c.Rollup = &RollupClient{client: c}
|
||||||
|
c.State = &StateClient{client: c}
|
||||||
|
c.Ceremony = &CeremonyClient{client: c}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultProofSystem returns the default proof system
|
||||||
|
func (c *Client) DefaultProofSystem() ProofSystem {
|
||||||
|
return c.config.DefaultProofSystem
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthCheck checks if the service is healthy
|
||||||
|
func (c *Client) HealthCheck(ctx context.Context) (bool, error) {
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := c.get(ctx, "/health", &result); err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return result["status"] == "healthy", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInfo returns service info
|
||||||
|
func (c *Client) GetInfo(ctx context.Context) (map[string]interface{}, error) {
|
||||||
|
var result map[string]interface{}
|
||||||
|
err := c.get(ctx, "/info", &result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the client
|
||||||
|
func (c *Client) Close() {
|
||||||
|
c.closed.Store(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClosed returns whether the client is closed
|
||||||
|
func (c *Client) IsClosed() bool {
|
||||||
|
return c.closed.Load()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal HTTP methods
|
||||||
|
func (c *Client) get(ctx context.Context, path string, result interface{}) error {
|
||||||
|
return c.request(ctx, "GET", path, nil, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) post(ctx context.Context, path string, body, result interface{}) error {
|
||||||
|
return c.request(ctx, "POST", path, body, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) delete(ctx context.Context, path string, result interface{}) error {
|
||||||
|
return c.request(ctx, "DELETE", path, nil, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) request(ctx context.Context, method, path string, body, result interface{}) error {
|
||||||
|
if c.closed.Load() {
|
||||||
|
return &Error{Message: "Client has been closed", Code: "CLIENT_CLOSED"}
|
||||||
|
}
|
||||||
|
|
||||||
|
url := c.config.Endpoint + path
|
||||||
|
|
||||||
|
var bodyReader io.Reader
|
||||||
|
if body != nil {
|
||||||
|
data, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bodyReader = bytes.NewReader(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastErr error
|
||||||
|
for attempt := 0; attempt <= c.config.Retries; attempt++ {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, method, url, bodyReader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.config.APIKey)
|
||||||
|
req.Header.Set("X-SDK-Version", "go/0.1.0")
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
lastErr = err
|
||||||
|
if attempt < c.config.Retries {
|
||||||
|
time.Sleep(time.Duration(100*(1<<attempt)) * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
respBody, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
var errResp struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
}
|
||||||
|
json.Unmarshal(respBody, &errResp)
|
||||||
|
return &Error{
|
||||||
|
Message: errResp.Message,
|
||||||
|
Code: errResp.Code,
|
||||||
|
Status: resp.StatusCode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
return json.Unmarshal(respBody, result)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Error{
|
||||||
|
Message: fmt.Sprintf("request failed: %v", lastErr),
|
||||||
|
Code: "NETWORK_ERROR",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProofsClient handles proof operations
|
||||||
|
type ProofsClient struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate generates a zero-knowledge proof
|
||||||
|
func (p *ProofsClient) Generate(ctx context.Context, req ProofRequest) (*Proof, error) {
|
||||||
|
system := req.System
|
||||||
|
if system == nil {
|
||||||
|
s := p.client.DefaultProofSystem()
|
||||||
|
system = &s
|
||||||
|
}
|
||||||
|
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"circuit_type": req.CircuitType,
|
||||||
|
"public_inputs": req.PublicInputs,
|
||||||
|
"private_inputs": req.PrivateInputs,
|
||||||
|
"system": *system,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Proof
|
||||||
|
if err := p.client.post(ctx, "/proofs/generate", body, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify verifies a proof
|
||||||
|
func (p *ProofsClient) Verify(ctx context.Context, proof *Proof) (*VerificationResult, error) {
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"proof_id": proof.ID,
|
||||||
|
"data": proof.Data,
|
||||||
|
"public_inputs": proof.PublicInputs,
|
||||||
|
"system": proof.System,
|
||||||
|
"circuit_type": proof.CircuitType,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result VerificationResult
|
||||||
|
if err := p.client.post(ctx, "/proofs/verify", body, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a proof by ID
|
||||||
|
func (p *ProofsClient) Get(ctx context.Context, proofID string) (*Proof, error) {
|
||||||
|
var result Proof
|
||||||
|
if err := p.client.get(ctx, "/proofs/"+proofID, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List lists recent proofs
|
||||||
|
func (p *ProofsClient) List(ctx context.Context, limit, offset int) ([]Proof, error) {
|
||||||
|
path := "/proofs"
|
||||||
|
if limit > 0 || offset > 0 {
|
||||||
|
path = fmt.Sprintf("/proofs?limit=%d&offset=%d", limit, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result proofsResponse
|
||||||
|
if err := p.client.get(ctx, path, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.Proofs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize serializes a proof to bytes
|
||||||
|
func (p *ProofsClient) Serialize(ctx context.Context, proof *Proof) ([]byte, error) {
|
||||||
|
var result serializeResponse
|
||||||
|
if err := p.client.post(ctx, "/proofs/serialize", map[string]string{"proof_id": proof.ID}, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.DecodeString(result.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize deserializes bytes to a proof
|
||||||
|
func (p *ProofsClient) Deserialize(ctx context.Context, data []byte, system ProofSystem) (*Proof, error) {
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"data": base64.StdEncoding.EncodeToString(data),
|
||||||
|
"system": system,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Proof
|
||||||
|
if err := p.client.post(ctx, "/proofs/deserialize", body, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CircuitsClient handles circuit operations
|
||||||
|
type CircuitsClient struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVerificationKey gets the verification key for a circuit
|
||||||
|
func (c *CircuitsClient) GetVerificationKey(ctx context.Context, circuitType CircuitType, system *ProofSystem) (*VerificationKey, error) {
|
||||||
|
sys := c.client.DefaultProofSystem()
|
||||||
|
if system != nil {
|
||||||
|
sys = *system
|
||||||
|
}
|
||||||
|
|
||||||
|
var result VerificationKey
|
||||||
|
if err := c.client.get(ctx, fmt.Sprintf("/circuits/%s/vk?system=%s", circuitType, sys), &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProvingKey gets the proving key for a circuit
|
||||||
|
func (c *CircuitsClient) GetProvingKey(ctx context.Context, circuitType CircuitType, system *ProofSystem) (*ProvingKey, error) {
|
||||||
|
sys := c.client.DefaultProofSystem()
|
||||||
|
if system != nil {
|
||||||
|
sys = *system
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ProvingKey
|
||||||
|
if err := c.client.get(ctx, fmt.Sprintf("/circuits/%s/pk?system=%s", circuitType, sys), &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List lists available circuits
|
||||||
|
func (c *CircuitsClient) List(ctx context.Context) ([]CircuitConfig, error) {
|
||||||
|
var result circuitsResponse
|
||||||
|
if err := c.client.get(ctx, "/circuits", &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.Circuits, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfig gets circuit configuration
|
||||||
|
func (c *CircuitsClient) GetConfig(ctx context.Context, circuitType CircuitType) (*CircuitConfig, error) {
|
||||||
|
var result CircuitConfig
|
||||||
|
if err := c.client.get(ctx, fmt.Sprintf("/circuits/%s/config", circuitType), &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile compiles a custom circuit
|
||||||
|
func (c *CircuitsClient) Compile(ctx context.Context, config CircuitConfig) (string, error) {
|
||||||
|
var result circuitIDResponse
|
||||||
|
if err := c.client.post(ctx, "/circuits/compile", config, &result); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.CircuitID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RollupClient handles rollup operations
|
||||||
|
type RollupClient struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStats gets rollup statistics
|
||||||
|
func (r *RollupClient) GetStats(ctx context.Context) (*RollupStats, error) {
|
||||||
|
var result RollupStats
|
||||||
|
if err := r.client.get(ctx, "/rollup/stats", &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentBatch gets the current batch
|
||||||
|
func (r *RollupClient) GetCurrentBatch(ctx context.Context) (*Batch, error) {
|
||||||
|
var result Batch
|
||||||
|
if err := r.client.get(ctx, "/rollup/batch/current", &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBatch gets a batch by number
|
||||||
|
func (r *RollupClient) GetBatch(ctx context.Context, batchNumber uint64) (*Batch, error) {
|
||||||
|
var result Batch
|
||||||
|
if err := r.client.get(ctx, fmt.Sprintf("/rollup/batch/%d", batchNumber), &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitTransfer submits a transfer
|
||||||
|
func (r *RollupClient) SubmitTransfer(ctx context.Context, transfer Transfer) (string, error) {
|
||||||
|
var result txIDResponse
|
||||||
|
if err := r.client.post(ctx, "/rollup/transfer", transfer, &result); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.TxID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitDeposit submits a deposit
|
||||||
|
func (r *RollupClient) SubmitDeposit(ctx context.Context, deposit Deposit) (string, error) {
|
||||||
|
var result txIDResponse
|
||||||
|
if err := r.client.post(ctx, "/rollup/deposit", deposit, &result); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.TxID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitWithdrawal submits a withdrawal
|
||||||
|
func (r *RollupClient) SubmitWithdrawal(ctx context.Context, withdrawal Withdrawal) (string, error) {
|
||||||
|
var result txIDResponse
|
||||||
|
if err := r.client.post(ctx, "/rollup/withdraw", withdrawal, &result); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.TxID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinalizeBatch finalizes the current batch
|
||||||
|
func (r *RollupClient) FinalizeBatch(ctx context.Context) (*Batch, error) {
|
||||||
|
var result Batch
|
||||||
|
if err := r.client.post(ctx, "/rollup/batch/finalize", struct{}{}, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingTransactions gets pending transactions
|
||||||
|
func (r *RollupClient) GetPendingTransactions(ctx context.Context) ([]Transfer, error) {
|
||||||
|
var result transactionsResponse
|
||||||
|
if err := r.client.get(ctx, "/rollup/pending", &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.Transactions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateClient handles state operations
|
||||||
|
type StateClient struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoot gets the current state root
|
||||||
|
func (s *StateClient) GetRoot(ctx context.Context) (string, error) {
|
||||||
|
var result rootResponse
|
||||||
|
if err := s.client.get(ctx, "/state/root", &result); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.Root, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccount gets account state
|
||||||
|
func (s *StateClient) GetAccount(ctx context.Context, address string) (*AccountState, error) {
|
||||||
|
var result AccountState
|
||||||
|
if err := s.client.get(ctx, "/state/account/"+address, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMerkleProof gets merkle proof for account inclusion
|
||||||
|
func (s *StateClient) GetMerkleProof(ctx context.Context, address string) (*MerkleProof, error) {
|
||||||
|
var result MerkleProof
|
||||||
|
if err := s.client.get(ctx, "/state/proof/"+address, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyMerkleProof verifies a merkle proof
|
||||||
|
func (s *StateClient) VerifyMerkleProof(ctx context.Context, proof MerkleProof) (bool, error) {
|
||||||
|
var result validResponse
|
||||||
|
if err := s.client.post(ctx, "/state/proof/verify", proof, &result); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return result.Valid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStateAtBatch gets state at specific batch
|
||||||
|
func (s *StateClient) GetStateAtBatch(ctx context.Context, batchNumber uint64) (map[string]interface{}, error) {
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := s.client.get(ctx, fmt.Sprintf("/state/batch/%d", batchNumber), &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CeremonyClient handles ceremony operations
|
||||||
|
type CeremonyClient struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStatus gets ceremony status
|
||||||
|
func (c *CeremonyClient) GetStatus(ctx context.Context, circuitType CircuitType, system *ProofSystem) (*TrustedSetup, error) {
|
||||||
|
sys := c.client.DefaultProofSystem()
|
||||||
|
if system != nil {
|
||||||
|
sys = *system
|
||||||
|
}
|
||||||
|
|
||||||
|
var result TrustedSetup
|
||||||
|
if err := c.client.get(ctx, fmt.Sprintf("/ceremony/%s?system=%s", circuitType, sys), &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contribute contributes to ceremony
|
||||||
|
func (c *CeremonyClient) Contribute(ctx context.Context, circuitType CircuitType, entropy []byte, system *ProofSystem) (*CeremonyContribution, error) {
|
||||||
|
sys := c.client.DefaultProofSystem()
|
||||||
|
if system != nil {
|
||||||
|
sys = *system
|
||||||
|
}
|
||||||
|
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"circuit_type": circuitType,
|
||||||
|
"entropy": base64.StdEncoding.EncodeToString(entropy),
|
||||||
|
"system": sys,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result CeremonyContribution
|
||||||
|
if err := c.client.post(ctx, "/ceremony/contribute", body, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyContribution verifies a contribution
|
||||||
|
func (c *CeremonyClient) VerifyContribution(ctx context.Context, circuitType CircuitType, contributionHash string) (bool, error) {
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"circuit_type": circuitType,
|
||||||
|
"contribution_hash": contributionHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result validResponse
|
||||||
|
if err := c.client.post(ctx, "/ceremony/verify", body, &result); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return result.Valid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListContributions lists contributions
|
||||||
|
func (c *CeremonyClient) ListContributions(ctx context.Context, circuitType CircuitType) ([]CeremonyContribution, error) {
|
||||||
|
var result contributionsResponse
|
||||||
|
if err := c.client.get(ctx, fmt.Sprintf("/ceremony/%s/contributions", circuitType), &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.Contributions, nil
|
||||||
|
}
|
||||||
323
sdk/go/zk/types.go
Normal file
323
sdk/go/zk/types.go
Normal file
|
|
@ -0,0 +1,323 @@
|
||||||
|
// Package zk provides the Synor ZK SDK for Go.
|
||||||
|
//
|
||||||
|
// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
package zk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProofSystem represents available proof system backends
|
||||||
|
type ProofSystem string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Groth16 - smallest proofs (~192 bytes), fastest verification
|
||||||
|
ProofSystemGroth16 ProofSystem = "groth16"
|
||||||
|
// Plonk - universal trusted setup, medium proofs (~512 bytes)
|
||||||
|
ProofSystemPlonk ProofSystem = "plonk"
|
||||||
|
// Stark - no trusted setup, largest proofs (~50KB)
|
||||||
|
ProofSystemStark ProofSystem = "stark"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CircuitType represents the type of circuit
|
||||||
|
type CircuitType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CircuitTransfer - single transfer between accounts
|
||||||
|
CircuitTransfer CircuitType = "transfer"
|
||||||
|
// CircuitBatch - batch of multiple transfers
|
||||||
|
CircuitBatch CircuitType = "batch"
|
||||||
|
// CircuitDeposit - deposit from L1 to L2
|
||||||
|
CircuitDeposit CircuitType = "deposit"
|
||||||
|
// CircuitWithdraw - withdrawal from L2 to L1
|
||||||
|
CircuitWithdraw CircuitType = "withdraw"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RollupState represents the state of a rollup
|
||||||
|
type RollupState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RollupStateActive RollupState = "active"
|
||||||
|
RollupStatePaused RollupState = "paused"
|
||||||
|
RollupStateFinalizing RollupState = "finalizing"
|
||||||
|
RollupStateFinalized RollupState = "finalized"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProofStatus represents the status of a proof
|
||||||
|
type ProofStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProofStatusGenerating ProofStatus = "generating"
|
||||||
|
ProofStatusCompleted ProofStatus = "completed"
|
||||||
|
ProofStatusFailed ProofStatus = "failed"
|
||||||
|
ProofStatusVerified ProofStatus = "verified"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Proof represents a zero-knowledge proof
|
||||||
|
type Proof struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
System ProofSystem `json:"system"`
|
||||||
|
CircuitType CircuitType `json:"circuit_type"`
|
||||||
|
Data string `json:"data"` // Base64 encoded
|
||||||
|
PublicInputs []string `json:"public_inputs"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
GenerationTimeMs int64 `json:"generation_time_ms"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerificationKey represents a verification key for a circuit
|
||||||
|
type VerificationKey struct {
|
||||||
|
CircuitID string `json:"circuit_id"`
|
||||||
|
CircuitType CircuitType `json:"circuit_type"`
|
||||||
|
System ProofSystem `json:"system"`
|
||||||
|
Data string `json:"data"` // Base64 encoded
|
||||||
|
Size int `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProvingKey represents a proving key for generating proofs
|
||||||
|
type ProvingKey struct {
|
||||||
|
CircuitID string `json:"circuit_id"`
|
||||||
|
CircuitType CircuitType `json:"circuit_type"`
|
||||||
|
System ProofSystem `json:"system"`
|
||||||
|
Data string `json:"data"` // Base64 encoded
|
||||||
|
Size int `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CircuitConfig represents circuit configuration
|
||||||
|
type CircuitConfig struct {
|
||||||
|
Type CircuitType `json:"type"`
|
||||||
|
MaxBatchSize *int `json:"max_batch_size,omitempty"`
|
||||||
|
TreeDepth *int `json:"tree_depth,omitempty"`
|
||||||
|
VerifySignatures *bool `json:"verify_signatures,omitempty"`
|
||||||
|
CustomConstraints map[string]interface{} `json:"custom_constraints,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountState represents account state in the rollup
|
||||||
|
type AccountState struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Balance string `json:"balance"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
PubkeyHash string `json:"pubkey_hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer represents a transfer operation
|
||||||
|
type Transfer struct {
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Amount string `json:"amount"`
|
||||||
|
Fee string `json:"fee"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
Signature *string `json:"signature,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deposit represents a deposit operation (L1 -> L2)
|
||||||
|
type Deposit struct {
|
||||||
|
L1TxHash string `json:"l1_tx_hash"`
|
||||||
|
Recipient string `json:"recipient"`
|
||||||
|
Amount string `json:"amount"`
|
||||||
|
Token *string `json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Withdrawal represents a withdrawal operation (L2 -> L1)
|
||||||
|
type Withdrawal struct {
|
||||||
|
Sender string `json:"sender"`
|
||||||
|
Recipient string `json:"recipient"`
|
||||||
|
Amount string `json:"amount"`
|
||||||
|
Token *string `json:"token,omitempty"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
Signature *string `json:"signature,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batch represents a rollup batch
|
||||||
|
type Batch struct {
|
||||||
|
BatchNumber uint64 `json:"batch_number"`
|
||||||
|
PrevStateRoot string `json:"prev_state_root"`
|
||||||
|
NewStateRoot string `json:"new_state_root"`
|
||||||
|
Transfers []Transfer `json:"transfers"`
|
||||||
|
Deposits []Deposit `json:"deposits"`
|
||||||
|
Withdrawals []Withdrawal `json:"withdrawals"`
|
||||||
|
Proof *Proof `json:"proof,omitempty"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RollupStats represents rollup statistics
|
||||||
|
type RollupStats struct {
|
||||||
|
CurrentBatch uint64 `json:"current_batch"`
|
||||||
|
TotalTransactions uint64 `json:"total_transactions"`
|
||||||
|
TotalProofs uint64 `json:"total_proofs"`
|
||||||
|
AvgProofTimeMs int64 `json:"avg_proof_time_ms"`
|
||||||
|
StateRoot string `json:"state_root"`
|
||||||
|
AccountCount uint64 `json:"account_count"`
|
||||||
|
TVL string `json:"tvl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProofRequest represents a proof generation request
|
||||||
|
type ProofRequest struct {
|
||||||
|
CircuitType CircuitType `json:"circuit_type"`
|
||||||
|
PublicInputs []string `json:"public_inputs"`
|
||||||
|
PrivateInputs []string `json:"private_inputs"`
|
||||||
|
System *ProofSystem `json:"system,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerificationResult represents proof verification result
|
||||||
|
type VerificationResult struct {
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
VerificationTimeMs int64 `json:"verification_time_ms"`
|
||||||
|
Error *string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MerkleProof represents a merkle proof for state inclusion
|
||||||
|
type MerkleProof struct {
|
||||||
|
Leaf string `json:"leaf"`
|
||||||
|
Path []string `json:"path"`
|
||||||
|
Indices []int `json:"indices"`
|
||||||
|
Root string `json:"root"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CeremonyContribution represents a trusted setup ceremony contribution
|
||||||
|
type CeremonyContribution struct {
|
||||||
|
ContributorID string `json:"contributor_id"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
Verified bool `json:"verified"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrustedSetup represents a trusted setup ceremony
|
||||||
|
type TrustedSetup struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CircuitType CircuitType `json:"circuit_type"`
|
||||||
|
System ProofSystem `json:"system"`
|
||||||
|
ContributionCount int `json:"contribution_count"`
|
||||||
|
LatestHash string `json:"latest_hash"`
|
||||||
|
Complete bool `json:"complete"`
|
||||||
|
Contributions []CeremonyContribution `json:"contributions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config represents ZK SDK configuration
|
||||||
|
type Config struct {
|
||||||
|
APIKey string
|
||||||
|
Endpoint string
|
||||||
|
WSEndpoint string
|
||||||
|
Timeout time.Duration
|
||||||
|
Retries int
|
||||||
|
DefaultProofSystem ProofSystem
|
||||||
|
Debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultConfig returns the default configuration
|
||||||
|
func DefaultConfig(apiKey string) Config {
|
||||||
|
return Config{
|
||||||
|
APIKey: apiKey,
|
||||||
|
Endpoint: "https://zk.synor.io/v1",
|
||||||
|
WSEndpoint: "wss://zk.synor.io/v1/ws",
|
||||||
|
Timeout: 60 * time.Second,
|
||||||
|
Retries: 3,
|
||||||
|
DefaultProofSystem: ProofSystemGroth16,
|
||||||
|
Debug: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error represents a ZK SDK error
|
||||||
|
type Error struct {
|
||||||
|
Message string
|
||||||
|
Code string
|
||||||
|
Status int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
if e.Code != "" {
|
||||||
|
return fmt.Sprintf("%s (%s)", e.Message, e.Code)
|
||||||
|
}
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProofSystemInfo contains information about a proof system
|
||||||
|
type ProofSystemInfo struct {
|
||||||
|
Name string
|
||||||
|
ProofSize int
|
||||||
|
VerificationTimeMs int
|
||||||
|
TrustedSetup bool
|
||||||
|
Universal bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProofSystemInfo returns information about a proof system
|
||||||
|
func GetProofSystemInfo(system ProofSystem) ProofSystemInfo {
|
||||||
|
switch system {
|
||||||
|
case ProofSystemGroth16:
|
||||||
|
return ProofSystemInfo{
|
||||||
|
Name: "Groth16",
|
||||||
|
ProofSize: 192,
|
||||||
|
VerificationTimeMs: 10,
|
||||||
|
TrustedSetup: true,
|
||||||
|
Universal: false,
|
||||||
|
}
|
||||||
|
case ProofSystemPlonk:
|
||||||
|
return ProofSystemInfo{
|
||||||
|
Name: "PLONK",
|
||||||
|
ProofSize: 512,
|
||||||
|
VerificationTimeMs: 15,
|
||||||
|
TrustedSetup: true,
|
||||||
|
Universal: true,
|
||||||
|
}
|
||||||
|
case ProofSystemStark:
|
||||||
|
return ProofSystemInfo{
|
||||||
|
Name: "STARK",
|
||||||
|
ProofSize: 50000,
|
||||||
|
VerificationTimeMs: 30,
|
||||||
|
TrustedSetup: false,
|
||||||
|
Universal: true,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ProofSystemInfo{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const (
|
||||||
|
MaxBatchSize = 1000
|
||||||
|
StateTreeDepth = 32
|
||||||
|
ProofExpiryBlocks = 100
|
||||||
|
)
|
||||||
|
|
||||||
|
// Helper for JSON responses
|
||||||
|
type jsonResponse struct {
|
||||||
|
Data json.RawMessage `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type proofsResponse struct {
|
||||||
|
Proofs []Proof `json:"proofs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type circuitsResponse struct {
|
||||||
|
Circuits []CircuitConfig `json:"circuits"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type transactionsResponse struct {
|
||||||
|
Transactions []Transfer `json:"transactions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type contributionsResponse struct {
|
||||||
|
Contributions []CeremonyContribution `json:"contributions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type rootResponse struct {
|
||||||
|
Root string `json:"root"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type validResponse struct {
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type txIDResponse struct {
|
||||||
|
TxID string `json:"tx_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type circuitIDResponse struct {
|
||||||
|
CircuitID string `json:"circuit_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type serializeResponse struct {
|
||||||
|
Data string `json:"data"`
|
||||||
|
}
|
||||||
321
sdk/java/src/main/java/io/synor/zk/SynorZk.java
Normal file
321
sdk/java/src/main/java/io/synor/zk/SynorZk.java
Normal file
|
|
@ -0,0 +1,321 @@
|
||||||
|
package io.synor.zk;
|
||||||
|
|
||||||
|
import io.synor.zk.Types.*;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK Client for Java
|
||||||
|
*
|
||||||
|
* Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
*/
|
||||||
|
public class SynorZk {
|
||||||
|
private final ZkConfig config;
|
||||||
|
private final HttpClient httpClient;
|
||||||
|
private final Gson gson;
|
||||||
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public final ProofsClient proofs;
|
||||||
|
public final CircuitsClient circuits;
|
||||||
|
public final RollupClient rollup;
|
||||||
|
public final StateClient state;
|
||||||
|
public final CeremonyClient ceremony;
|
||||||
|
|
||||||
|
public SynorZk(ZkConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
this.httpClient = HttpClient.newBuilder()
|
||||||
|
.connectTimeout(Duration.ofMillis(config.getTimeout()))
|
||||||
|
.build();
|
||||||
|
this.gson = new GsonBuilder().create();
|
||||||
|
|
||||||
|
this.proofs = new ProofsClient(this);
|
||||||
|
this.circuits = new CircuitsClient(this);
|
||||||
|
this.rollup = new RollupClient(this);
|
||||||
|
this.state = new StateClient(this);
|
||||||
|
this.ceremony = new CeremonyClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofSystem getDefaultProofSystem() {
|
||||||
|
return config.getDefaultProofSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Boolean> healthCheck() {
|
||||||
|
return get("/health", Map.class)
|
||||||
|
.thenApply(result -> "healthy".equals(result.get("status")))
|
||||||
|
.exceptionally(e -> false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Map<String, Object>> getInfo() {
|
||||||
|
return get("/info", new TypeToken<Map<String, Object>>(){}.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
closed.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal HTTP methods
|
||||||
|
<T> CompletableFuture<T> get(String path, Type type) {
|
||||||
|
return request("GET", path, null, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
<T> CompletableFuture<T> post(String path, Object body, Type type) {
|
||||||
|
return request("POST", path, body, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> CompletableFuture<T> request(String method, String path, Object body, Type type) {
|
||||||
|
if (closed.get()) {
|
||||||
|
return CompletableFuture.failedFuture(
|
||||||
|
new ZkException("Client has been closed", "CLIENT_CLOSED"));
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = config.getEndpoint() + path;
|
||||||
|
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(url))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", "Bearer " + config.getApiKey())
|
||||||
|
.header("X-SDK-Version", "java/0.1.0")
|
||||||
|
.timeout(Duration.ofMillis(config.getTimeout()));
|
||||||
|
|
||||||
|
if ("GET".equals(method)) {
|
||||||
|
requestBuilder.GET();
|
||||||
|
} else if ("POST".equals(method)) {
|
||||||
|
String jsonBody = body != null ? gson.toJson(body) : "{}";
|
||||||
|
requestBuilder.POST(HttpRequest.BodyPublishers.ofString(jsonBody));
|
||||||
|
} else if ("DELETE".equals(method)) {
|
||||||
|
requestBuilder.DELETE();
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpClient.sendAsync(requestBuilder.build(), HttpResponse.BodyHandlers.ofString())
|
||||||
|
.thenApply(response -> {
|
||||||
|
if (response.statusCode() >= 400) {
|
||||||
|
Map<String, Object> error = gson.fromJson(response.body(), Map.class);
|
||||||
|
throw new ZkException(
|
||||||
|
(String) error.getOrDefault("message", "HTTP " + response.statusCode()),
|
||||||
|
(String) error.get("code"),
|
||||||
|
response.statusCode()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return gson.fromJson(response.body(), type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proofs sub-client */
|
||||||
|
public static class ProofsClient {
|
||||||
|
private final SynorZk zk;
|
||||||
|
|
||||||
|
ProofsClient(SynorZk zk) {
|
||||||
|
this.zk = zk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Proof> generate(ProofRequest request) {
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("circuit_type", request.getCircuitType().getValue());
|
||||||
|
body.put("public_inputs", request.getPublicInputs());
|
||||||
|
body.put("private_inputs", request.getPrivateInputs());
|
||||||
|
body.put("system", (request.getSystem() != null ? request.getSystem() : zk.getDefaultProofSystem()).getValue());
|
||||||
|
return zk.post("/proofs/generate", body, Proof.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<VerificationResult> verify(Proof proof) {
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("proof_id", proof.getId());
|
||||||
|
body.put("data", proof.getData());
|
||||||
|
body.put("public_inputs", proof.getPublicInputs());
|
||||||
|
body.put("system", proof.getSystem().getValue());
|
||||||
|
body.put("circuit_type", proof.getCircuitType().getValue());
|
||||||
|
return zk.post("/proofs/verify", body, VerificationResult.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Proof> get(String proofId) {
|
||||||
|
return zk.get("/proofs/" + proofId, Proof.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<List<Proof>> list(Integer limit, Integer offset) {
|
||||||
|
StringBuilder path = new StringBuilder("/proofs");
|
||||||
|
if (limit != null || offset != null) {
|
||||||
|
path.append("?");
|
||||||
|
if (limit != null) path.append("limit=").append(limit);
|
||||||
|
if (limit != null && offset != null) path.append("&");
|
||||||
|
if (offset != null) path.append("offset=").append(offset);
|
||||||
|
}
|
||||||
|
return zk.get(path.toString(), new TypeToken<Map<String, List<Proof>>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, List<Proof>>) result).getOrDefault("proofs", Collections.emptyList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<byte[]> serialize(Proof proof) {
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("proof_id", proof.getId());
|
||||||
|
return zk.post("/proofs/serialize", body, new TypeToken<Map<String, String>>(){}.getType())
|
||||||
|
.thenApply(result -> Base64.getDecoder().decode(((Map<String, String>) result).get("data")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Proof> deserialize(byte[] data, ProofSystem system) {
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("data", Base64.getEncoder().encodeToString(data));
|
||||||
|
body.put("system", system.getValue());
|
||||||
|
return zk.post("/proofs/deserialize", body, Proof.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Circuits sub-client */
|
||||||
|
public static class CircuitsClient {
|
||||||
|
private final SynorZk zk;
|
||||||
|
|
||||||
|
CircuitsClient(SynorZk zk) {
|
||||||
|
this.zk = zk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<VerificationKey> getVerificationKey(CircuitType circuitType, ProofSystem system) {
|
||||||
|
ProofSystem sys = system != null ? system : zk.getDefaultProofSystem();
|
||||||
|
return zk.get("/circuits/" + circuitType.getValue() + "/vk?system=" + sys.getValue(), VerificationKey.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<ProvingKey> getProvingKey(CircuitType circuitType, ProofSystem system) {
|
||||||
|
ProofSystem sys = system != null ? system : zk.getDefaultProofSystem();
|
||||||
|
return zk.get("/circuits/" + circuitType.getValue() + "/pk?system=" + sys.getValue(), ProvingKey.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<List<CircuitConfig>> list() {
|
||||||
|
return zk.get("/circuits", new TypeToken<Map<String, List<CircuitConfig>>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, List<CircuitConfig>>) result).getOrDefault("circuits", Collections.emptyList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<CircuitConfig> getConfig(CircuitType circuitType) {
|
||||||
|
return zk.get("/circuits/" + circuitType.getValue() + "/config", CircuitConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<String> compile(CircuitConfig config) {
|
||||||
|
return zk.post("/circuits/compile", config, new TypeToken<Map<String, String>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, String>) result).get("circuit_id"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rollup sub-client */
|
||||||
|
public static class RollupClient {
|
||||||
|
private final SynorZk zk;
|
||||||
|
|
||||||
|
RollupClient(SynorZk zk) {
|
||||||
|
this.zk = zk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<RollupStats> getStats() {
|
||||||
|
return zk.get("/rollup/stats", RollupStats.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Batch> getCurrentBatch() {
|
||||||
|
return zk.get("/rollup/batch/current", Batch.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Batch> getBatch(long batchNumber) {
|
||||||
|
return zk.get("/rollup/batch/" + batchNumber, Batch.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<String> submitTransfer(Transfer transfer) {
|
||||||
|
return zk.post("/rollup/transfer", transfer, new TypeToken<Map<String, String>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, String>) result).get("tx_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<String> submitDeposit(Deposit deposit) {
|
||||||
|
return zk.post("/rollup/deposit", deposit, new TypeToken<Map<String, String>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, String>) result).get("tx_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<String> submitWithdrawal(Withdrawal withdrawal) {
|
||||||
|
return zk.post("/rollup/withdraw", withdrawal, new TypeToken<Map<String, String>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, String>) result).get("tx_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Batch> finalizeBatch() {
|
||||||
|
return zk.post("/rollup/batch/finalize", Collections.emptyMap(), Batch.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<List<Transfer>> getPendingTransactions() {
|
||||||
|
return zk.get("/rollup/pending", new TypeToken<Map<String, List<Transfer>>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, List<Transfer>>) result).getOrDefault("transactions", Collections.emptyList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** State sub-client */
|
||||||
|
public static class StateClient {
|
||||||
|
private final SynorZk zk;
|
||||||
|
|
||||||
|
StateClient(SynorZk zk) {
|
||||||
|
this.zk = zk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<String> getRoot() {
|
||||||
|
return zk.get("/state/root", new TypeToken<Map<String, String>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, String>) result).get("root"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<AccountState> getAccount(String address) {
|
||||||
|
return zk.get("/state/account/" + address, AccountState.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<MerkleProof> getMerkleProof(String address) {
|
||||||
|
return zk.get("/state/proof/" + address, MerkleProof.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Boolean> verifyMerkleProof(MerkleProof proof) {
|
||||||
|
return zk.post("/state/proof/verify", proof, new TypeToken<Map<String, Boolean>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, Boolean>) result).get("valid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Map<String, Object>> getStateAtBatch(long batchNumber) {
|
||||||
|
return zk.get("/state/batch/" + batchNumber, new TypeToken<Map<String, Object>>(){}.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ceremony sub-client */
|
||||||
|
public static class CeremonyClient {
|
||||||
|
private final SynorZk zk;
|
||||||
|
|
||||||
|
CeremonyClient(SynorZk zk) {
|
||||||
|
this.zk = zk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<TrustedSetup> getStatus(CircuitType circuitType, ProofSystem system) {
|
||||||
|
ProofSystem sys = system != null ? system : zk.getDefaultProofSystem();
|
||||||
|
return zk.get("/ceremony/" + circuitType.getValue() + "?system=" + sys.getValue(), TrustedSetup.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<CeremonyContribution> contribute(CircuitType circuitType, byte[] entropy, ProofSystem system) {
|
||||||
|
ProofSystem sys = system != null ? system : zk.getDefaultProofSystem();
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("circuit_type", circuitType.getValue());
|
||||||
|
body.put("entropy", Base64.getEncoder().encodeToString(entropy));
|
||||||
|
body.put("system", sys.getValue());
|
||||||
|
return zk.post("/ceremony/contribute", body, CeremonyContribution.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Boolean> verifyContribution(CircuitType circuitType, String contributionHash) {
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("circuit_type", circuitType.getValue());
|
||||||
|
body.put("contribution_hash", contributionHash);
|
||||||
|
return zk.post("/ceremony/verify", body, new TypeToken<Map<String, Boolean>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, Boolean>) result).get("valid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<List<CeremonyContribution>> listContributions(CircuitType circuitType) {
|
||||||
|
return zk.get("/ceremony/" + circuitType.getValue() + "/contributions", new TypeToken<Map<String, List<CeremonyContribution>>>(){}.getType())
|
||||||
|
.thenApply(result -> ((Map<String, List<CeremonyContribution>>) result).getOrDefault("contributions", Collections.emptyList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
539
sdk/java/src/main/java/io/synor/zk/Types.java
Normal file
539
sdk/java/src/main/java/io/synor/zk/Types.java
Normal file
|
|
@ -0,0 +1,539 @@
|
||||||
|
package io.synor.zk;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK Types for Java
|
||||||
|
*
|
||||||
|
* Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
*/
|
||||||
|
public class Types {
|
||||||
|
|
||||||
|
/** Proof system backends */
|
||||||
|
public enum ProofSystem {
|
||||||
|
/** Groth16 - smallest proofs (~192 bytes), fastest verification */
|
||||||
|
GROTH16("groth16"),
|
||||||
|
/** PLONK - universal trusted setup, medium proofs (~512 bytes) */
|
||||||
|
PLONK("plonk"),
|
||||||
|
/** STARK - no trusted setup, largest proofs (~50KB) */
|
||||||
|
STARK("stark");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
ProofSystem(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProofSystem fromString(String value) {
|
||||||
|
for (ProofSystem system : values()) {
|
||||||
|
if (system.value.equals(value)) {
|
||||||
|
return system;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GROTH16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Circuit types for different operations */
|
||||||
|
public enum CircuitType {
|
||||||
|
/** Single transfer between accounts */
|
||||||
|
TRANSFER("transfer"),
|
||||||
|
/** Batch of multiple transfers */
|
||||||
|
BATCH("batch"),
|
||||||
|
/** Deposit from L1 to L2 */
|
||||||
|
DEPOSIT("deposit"),
|
||||||
|
/** Withdrawal from L2 to L1 */
|
||||||
|
WITHDRAW("withdraw");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
CircuitType(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CircuitType fromString(String value) {
|
||||||
|
for (CircuitType type : values()) {
|
||||||
|
if (type.value.equals(value)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRANSFER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rollup state */
|
||||||
|
public enum RollupState {
|
||||||
|
ACTIVE, PAUSED, FINALIZING, FINALIZED
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proof status */
|
||||||
|
public enum ProofStatus {
|
||||||
|
GENERATING, COMPLETED, FAILED, VERIFIED
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Zero-knowledge proof */
|
||||||
|
public static class Proof {
|
||||||
|
private String id;
|
||||||
|
private ProofSystem system;
|
||||||
|
private CircuitType circuitType;
|
||||||
|
private String data;
|
||||||
|
private List<String> publicInputs;
|
||||||
|
private int size;
|
||||||
|
private long generationTimeMs;
|
||||||
|
private long createdAt;
|
||||||
|
|
||||||
|
public Proof() {}
|
||||||
|
|
||||||
|
public Proof(String id, ProofSystem system, CircuitType circuitType, String data,
|
||||||
|
List<String> publicInputs, int size, long generationTimeMs, long createdAt) {
|
||||||
|
this.id = id;
|
||||||
|
this.system = system;
|
||||||
|
this.circuitType = circuitType;
|
||||||
|
this.data = data;
|
||||||
|
this.publicInputs = publicInputs;
|
||||||
|
this.size = size;
|
||||||
|
this.generationTimeMs = generationTimeMs;
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() { return id; }
|
||||||
|
public void setId(String id) { this.id = id; }
|
||||||
|
public ProofSystem getSystem() { return system; }
|
||||||
|
public void setSystem(ProofSystem system) { this.system = system; }
|
||||||
|
public CircuitType getCircuitType() { return circuitType; }
|
||||||
|
public void setCircuitType(CircuitType circuitType) { this.circuitType = circuitType; }
|
||||||
|
public String getData() { return data; }
|
||||||
|
public void setData(String data) { this.data = data; }
|
||||||
|
public List<String> getPublicInputs() { return publicInputs; }
|
||||||
|
public void setPublicInputs(List<String> publicInputs) { this.publicInputs = publicInputs; }
|
||||||
|
public int getSize() { return size; }
|
||||||
|
public void setSize(int size) { this.size = size; }
|
||||||
|
public long getGenerationTimeMs() { return generationTimeMs; }
|
||||||
|
public void setGenerationTimeMs(long generationTimeMs) { this.generationTimeMs = generationTimeMs; }
|
||||||
|
public long getCreatedAt() { return createdAt; }
|
||||||
|
public void setCreatedAt(long createdAt) { this.createdAt = createdAt; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Verification key for a circuit */
|
||||||
|
public static class VerificationKey {
|
||||||
|
private String circuitId;
|
||||||
|
private CircuitType circuitType;
|
||||||
|
private ProofSystem system;
|
||||||
|
private String data;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
public String getCircuitId() { return circuitId; }
|
||||||
|
public void setCircuitId(String circuitId) { this.circuitId = circuitId; }
|
||||||
|
public CircuitType getCircuitType() { return circuitType; }
|
||||||
|
public void setCircuitType(CircuitType circuitType) { this.circuitType = circuitType; }
|
||||||
|
public ProofSystem getSystem() { return system; }
|
||||||
|
public void setSystem(ProofSystem system) { this.system = system; }
|
||||||
|
public String getData() { return data; }
|
||||||
|
public void setData(String data) { this.data = data; }
|
||||||
|
public int getSize() { return size; }
|
||||||
|
public void setSize(int size) { this.size = size; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proving key for generating proofs */
|
||||||
|
public static class ProvingKey {
|
||||||
|
private String circuitId;
|
||||||
|
private CircuitType circuitType;
|
||||||
|
private ProofSystem system;
|
||||||
|
private String data;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
public String getCircuitId() { return circuitId; }
|
||||||
|
public void setCircuitId(String circuitId) { this.circuitId = circuitId; }
|
||||||
|
public CircuitType getCircuitType() { return circuitType; }
|
||||||
|
public void setCircuitType(CircuitType circuitType) { this.circuitType = circuitType; }
|
||||||
|
public ProofSystem getSystem() { return system; }
|
||||||
|
public void setSystem(ProofSystem system) { this.system = system; }
|
||||||
|
public String getData() { return data; }
|
||||||
|
public void setData(String data) { this.data = data; }
|
||||||
|
public int getSize() { return size; }
|
||||||
|
public void setSize(int size) { this.size = size; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Circuit configuration */
|
||||||
|
public static class CircuitConfig {
|
||||||
|
private CircuitType type;
|
||||||
|
private Integer maxBatchSize;
|
||||||
|
private Integer treeDepth;
|
||||||
|
private Boolean verifySignatures;
|
||||||
|
private Map<String, Object> customConstraints;
|
||||||
|
|
||||||
|
public CircuitType getType() { return type; }
|
||||||
|
public void setType(CircuitType type) { this.type = type; }
|
||||||
|
public Integer getMaxBatchSize() { return maxBatchSize; }
|
||||||
|
public void setMaxBatchSize(Integer maxBatchSize) { this.maxBatchSize = maxBatchSize; }
|
||||||
|
public Integer getTreeDepth() { return treeDepth; }
|
||||||
|
public void setTreeDepth(Integer treeDepth) { this.treeDepth = treeDepth; }
|
||||||
|
public Boolean getVerifySignatures() { return verifySignatures; }
|
||||||
|
public void setVerifySignatures(Boolean verifySignatures) { this.verifySignatures = verifySignatures; }
|
||||||
|
public Map<String, Object> getCustomConstraints() { return customConstraints; }
|
||||||
|
public void setCustomConstraints(Map<String, Object> customConstraints) { this.customConstraints = customConstraints; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Account state in the rollup */
|
||||||
|
public static class AccountState {
|
||||||
|
private String address;
|
||||||
|
private String balance;
|
||||||
|
private long nonce;
|
||||||
|
private String pubkeyHash;
|
||||||
|
|
||||||
|
public String getAddress() { return address; }
|
||||||
|
public void setAddress(String address) { this.address = address; }
|
||||||
|
public String getBalance() { return balance; }
|
||||||
|
public void setBalance(String balance) { this.balance = balance; }
|
||||||
|
public long getNonce() { return nonce; }
|
||||||
|
public void setNonce(long nonce) { this.nonce = nonce; }
|
||||||
|
public String getPubkeyHash() { return pubkeyHash; }
|
||||||
|
public void setPubkeyHash(String pubkeyHash) { this.pubkeyHash = pubkeyHash; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Transfer operation */
|
||||||
|
public static class Transfer {
|
||||||
|
private String from;
|
||||||
|
private String to;
|
||||||
|
private String amount;
|
||||||
|
private String fee;
|
||||||
|
private long nonce;
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
public Transfer() {}
|
||||||
|
|
||||||
|
public Transfer(String from, String to, String amount, String fee, long nonce) {
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.amount = amount;
|
||||||
|
this.fee = fee;
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFrom() { return from; }
|
||||||
|
public void setFrom(String from) { this.from = from; }
|
||||||
|
public String getTo() { return to; }
|
||||||
|
public void setTo(String to) { this.to = to; }
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public void setAmount(String amount) { this.amount = amount; }
|
||||||
|
public String getFee() { return fee; }
|
||||||
|
public void setFee(String fee) { this.fee = fee; }
|
||||||
|
public long getNonce() { return nonce; }
|
||||||
|
public void setNonce(long nonce) { this.nonce = nonce; }
|
||||||
|
public String getSignature() { return signature; }
|
||||||
|
public void setSignature(String signature) { this.signature = signature; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deposit operation (L1 -> L2) */
|
||||||
|
public static class Deposit {
|
||||||
|
private String l1TxHash;
|
||||||
|
private String recipient;
|
||||||
|
private String amount;
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
public Deposit() {}
|
||||||
|
|
||||||
|
public Deposit(String l1TxHash, String recipient, String amount) {
|
||||||
|
this.l1TxHash = l1TxHash;
|
||||||
|
this.recipient = recipient;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getL1TxHash() { return l1TxHash; }
|
||||||
|
public void setL1TxHash(String l1TxHash) { this.l1TxHash = l1TxHash; }
|
||||||
|
public String getRecipient() { return recipient; }
|
||||||
|
public void setRecipient(String recipient) { this.recipient = recipient; }
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public void setAmount(String amount) { this.amount = amount; }
|
||||||
|
public String getToken() { return token; }
|
||||||
|
public void setToken(String token) { this.token = token; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Withdrawal operation (L2 -> L1) */
|
||||||
|
public static class Withdrawal {
|
||||||
|
private String sender;
|
||||||
|
private String recipient;
|
||||||
|
private String amount;
|
||||||
|
private String token;
|
||||||
|
private long nonce;
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
public Withdrawal() {}
|
||||||
|
|
||||||
|
public Withdrawal(String sender, String recipient, String amount, long nonce) {
|
||||||
|
this.sender = sender;
|
||||||
|
this.recipient = recipient;
|
||||||
|
this.amount = amount;
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSender() { return sender; }
|
||||||
|
public void setSender(String sender) { this.sender = sender; }
|
||||||
|
public String getRecipient() { return recipient; }
|
||||||
|
public void setRecipient(String recipient) { this.recipient = recipient; }
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public void setAmount(String amount) { this.amount = amount; }
|
||||||
|
public String getToken() { return token; }
|
||||||
|
public void setToken(String token) { this.token = token; }
|
||||||
|
public long getNonce() { return nonce; }
|
||||||
|
public void setNonce(long nonce) { this.nonce = nonce; }
|
||||||
|
public String getSignature() { return signature; }
|
||||||
|
public void setSignature(String signature) { this.signature = signature; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rollup batch */
|
||||||
|
public static class Batch {
|
||||||
|
private long batchNumber;
|
||||||
|
private String prevStateRoot;
|
||||||
|
private String newStateRoot;
|
||||||
|
private List<Transfer> transfers;
|
||||||
|
private List<Deposit> deposits;
|
||||||
|
private List<Withdrawal> withdrawals;
|
||||||
|
private Proof proof;
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
|
public long getBatchNumber() { return batchNumber; }
|
||||||
|
public void setBatchNumber(long batchNumber) { this.batchNumber = batchNumber; }
|
||||||
|
public String getPrevStateRoot() { return prevStateRoot; }
|
||||||
|
public void setPrevStateRoot(String prevStateRoot) { this.prevStateRoot = prevStateRoot; }
|
||||||
|
public String getNewStateRoot() { return newStateRoot; }
|
||||||
|
public void setNewStateRoot(String newStateRoot) { this.newStateRoot = newStateRoot; }
|
||||||
|
public List<Transfer> getTransfers() { return transfers; }
|
||||||
|
public void setTransfers(List<Transfer> transfers) { this.transfers = transfers; }
|
||||||
|
public List<Deposit> getDeposits() { return deposits; }
|
||||||
|
public void setDeposits(List<Deposit> deposits) { this.deposits = deposits; }
|
||||||
|
public List<Withdrawal> getWithdrawals() { return withdrawals; }
|
||||||
|
public void setWithdrawals(List<Withdrawal> withdrawals) { this.withdrawals = withdrawals; }
|
||||||
|
public Proof getProof() { return proof; }
|
||||||
|
public void setProof(Proof proof) { this.proof = proof; }
|
||||||
|
public long getTimestamp() { return timestamp; }
|
||||||
|
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rollup statistics */
|
||||||
|
public static class RollupStats {
|
||||||
|
private long currentBatch;
|
||||||
|
private long totalTransactions;
|
||||||
|
private long totalProofs;
|
||||||
|
private long avgProofTimeMs;
|
||||||
|
private String stateRoot;
|
||||||
|
private long accountCount;
|
||||||
|
private String tvl;
|
||||||
|
|
||||||
|
public long getCurrentBatch() { return currentBatch; }
|
||||||
|
public void setCurrentBatch(long currentBatch) { this.currentBatch = currentBatch; }
|
||||||
|
public long getTotalTransactions() { return totalTransactions; }
|
||||||
|
public void setTotalTransactions(long totalTransactions) { this.totalTransactions = totalTransactions; }
|
||||||
|
public long getTotalProofs() { return totalProofs; }
|
||||||
|
public void setTotalProofs(long totalProofs) { this.totalProofs = totalProofs; }
|
||||||
|
public long getAvgProofTimeMs() { return avgProofTimeMs; }
|
||||||
|
public void setAvgProofTimeMs(long avgProofTimeMs) { this.avgProofTimeMs = avgProofTimeMs; }
|
||||||
|
public String getStateRoot() { return stateRoot; }
|
||||||
|
public void setStateRoot(String stateRoot) { this.stateRoot = stateRoot; }
|
||||||
|
public long getAccountCount() { return accountCount; }
|
||||||
|
public void setAccountCount(long accountCount) { this.accountCount = accountCount; }
|
||||||
|
public String getTvl() { return tvl; }
|
||||||
|
public void setTvl(String tvl) { this.tvl = tvl; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proof generation request */
|
||||||
|
public static class ProofRequest {
|
||||||
|
private CircuitType circuitType;
|
||||||
|
private List<String> publicInputs;
|
||||||
|
private List<String> privateInputs;
|
||||||
|
private ProofSystem system;
|
||||||
|
|
||||||
|
public ProofRequest() {}
|
||||||
|
|
||||||
|
public ProofRequest(CircuitType circuitType, List<String> publicInputs, List<String> privateInputs) {
|
||||||
|
this.circuitType = circuitType;
|
||||||
|
this.publicInputs = publicInputs;
|
||||||
|
this.privateInputs = privateInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CircuitType getCircuitType() { return circuitType; }
|
||||||
|
public void setCircuitType(CircuitType circuitType) { this.circuitType = circuitType; }
|
||||||
|
public List<String> getPublicInputs() { return publicInputs; }
|
||||||
|
public void setPublicInputs(List<String> publicInputs) { this.publicInputs = publicInputs; }
|
||||||
|
public List<String> getPrivateInputs() { return privateInputs; }
|
||||||
|
public void setPrivateInputs(List<String> privateInputs) { this.privateInputs = privateInputs; }
|
||||||
|
public ProofSystem getSystem() { return system; }
|
||||||
|
public void setSystem(ProofSystem system) { this.system = system; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proof verification result */
|
||||||
|
public static class VerificationResult {
|
||||||
|
private boolean valid;
|
||||||
|
private long verificationTimeMs;
|
||||||
|
private String error;
|
||||||
|
|
||||||
|
public boolean isValid() { return valid; }
|
||||||
|
public void setValid(boolean valid) { this.valid = valid; }
|
||||||
|
public long getVerificationTimeMs() { return verificationTimeMs; }
|
||||||
|
public void setVerificationTimeMs(long verificationTimeMs) { this.verificationTimeMs = verificationTimeMs; }
|
||||||
|
public String getError() { return error; }
|
||||||
|
public void setError(String error) { this.error = error; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Merkle proof for state inclusion */
|
||||||
|
public static class MerkleProof {
|
||||||
|
private String leaf;
|
||||||
|
private List<String> path;
|
||||||
|
private List<Integer> indices;
|
||||||
|
private String root;
|
||||||
|
|
||||||
|
public String getLeaf() { return leaf; }
|
||||||
|
public void setLeaf(String leaf) { this.leaf = leaf; }
|
||||||
|
public List<String> getPath() { return path; }
|
||||||
|
public void setPath(List<String> path) { this.path = path; }
|
||||||
|
public List<Integer> getIndices() { return indices; }
|
||||||
|
public void setIndices(List<Integer> indices) { this.indices = indices; }
|
||||||
|
public String getRoot() { return root; }
|
||||||
|
public void setRoot(String root) { this.root = root; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Trusted setup ceremony contribution */
|
||||||
|
public static class CeremonyContribution {
|
||||||
|
private String contributorId;
|
||||||
|
private String hash;
|
||||||
|
private long timestamp;
|
||||||
|
private boolean verified;
|
||||||
|
|
||||||
|
public String getContributorId() { return contributorId; }
|
||||||
|
public void setContributorId(String contributorId) { this.contributorId = contributorId; }
|
||||||
|
public String getHash() { return hash; }
|
||||||
|
public void setHash(String hash) { this.hash = hash; }
|
||||||
|
public long getTimestamp() { return timestamp; }
|
||||||
|
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
|
||||||
|
public boolean isVerified() { return verified; }
|
||||||
|
public void setVerified(boolean verified) { this.verified = verified; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Trusted setup ceremony */
|
||||||
|
public static class TrustedSetup {
|
||||||
|
private String id;
|
||||||
|
private CircuitType circuitType;
|
||||||
|
private ProofSystem system;
|
||||||
|
private int contributionCount;
|
||||||
|
private String latestHash;
|
||||||
|
private boolean complete;
|
||||||
|
private List<CeremonyContribution> contributions;
|
||||||
|
|
||||||
|
public String getId() { return id; }
|
||||||
|
public void setId(String id) { this.id = id; }
|
||||||
|
public CircuitType getCircuitType() { return circuitType; }
|
||||||
|
public void setCircuitType(CircuitType circuitType) { this.circuitType = circuitType; }
|
||||||
|
public ProofSystem getSystem() { return system; }
|
||||||
|
public void setSystem(ProofSystem system) { this.system = system; }
|
||||||
|
public int getContributionCount() { return contributionCount; }
|
||||||
|
public void setContributionCount(int contributionCount) { this.contributionCount = contributionCount; }
|
||||||
|
public String getLatestHash() { return latestHash; }
|
||||||
|
public void setLatestHash(String latestHash) { this.latestHash = latestHash; }
|
||||||
|
public boolean isComplete() { return complete; }
|
||||||
|
public void setComplete(boolean complete) { this.complete = complete; }
|
||||||
|
public List<CeremonyContribution> getContributions() { return contributions; }
|
||||||
|
public void setContributions(List<CeremonyContribution> contributions) { this.contributions = contributions; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ZK SDK configuration */
|
||||||
|
public static class ZkConfig {
|
||||||
|
private String apiKey;
|
||||||
|
private String endpoint = "https://zk.synor.io/v1";
|
||||||
|
private String wsEndpoint = "wss://zk.synor.io/v1/ws";
|
||||||
|
private int timeout = 60000;
|
||||||
|
private int retries = 3;
|
||||||
|
private ProofSystem defaultProofSystem = ProofSystem.GROTH16;
|
||||||
|
private boolean debug = false;
|
||||||
|
|
||||||
|
public ZkConfig(String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiKey() { return apiKey; }
|
||||||
|
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
|
||||||
|
public String getEndpoint() { return endpoint; }
|
||||||
|
public void setEndpoint(String endpoint) { this.endpoint = endpoint; }
|
||||||
|
public String getWsEndpoint() { return wsEndpoint; }
|
||||||
|
public void setWsEndpoint(String wsEndpoint) { this.wsEndpoint = wsEndpoint; }
|
||||||
|
public int getTimeout() { return timeout; }
|
||||||
|
public void setTimeout(int timeout) { this.timeout = timeout; }
|
||||||
|
public int getRetries() { return retries; }
|
||||||
|
public void setRetries(int retries) { this.retries = retries; }
|
||||||
|
public ProofSystem getDefaultProofSystem() { return defaultProofSystem; }
|
||||||
|
public void setDefaultProofSystem(ProofSystem defaultProofSystem) { this.defaultProofSystem = defaultProofSystem; }
|
||||||
|
public boolean isDebug() { return debug; }
|
||||||
|
public void setDebug(boolean debug) { this.debug = debug; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ZK SDK exception */
|
||||||
|
public static class ZkException extends RuntimeException {
|
||||||
|
private final String code;
|
||||||
|
private final Integer status;
|
||||||
|
|
||||||
|
public ZkException(String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = null;
|
||||||
|
this.status = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZkException(String message, String code) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
this.status = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZkException(String message, String code, Integer status) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() { return code; }
|
||||||
|
public Integer getStatus() { return status; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proof system characteristics */
|
||||||
|
public static class ProofSystemInfo {
|
||||||
|
public final String name;
|
||||||
|
public final int proofSize;
|
||||||
|
public final int verificationTimeMs;
|
||||||
|
public final boolean trustedSetup;
|
||||||
|
public final boolean universal;
|
||||||
|
|
||||||
|
public ProofSystemInfo(String name, int proofSize, int verificationTimeMs,
|
||||||
|
boolean trustedSetup, boolean universal) {
|
||||||
|
this.name = name;
|
||||||
|
this.proofSize = proofSize;
|
||||||
|
this.verificationTimeMs = verificationTimeMs;
|
||||||
|
this.trustedSetup = trustedSetup;
|
||||||
|
this.universal = universal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProofSystemInfo getProofSystemInfo(ProofSystem system) {
|
||||||
|
switch (system) {
|
||||||
|
case GROTH16:
|
||||||
|
return new ProofSystemInfo("Groth16", 192, 10, true, false);
|
||||||
|
case PLONK:
|
||||||
|
return new ProofSystemInfo("PLONK", 512, 15, true, true);
|
||||||
|
case STARK:
|
||||||
|
return new ProofSystemInfo("STARK", 50000, 30, false, true);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
public static final int MAX_BATCH_SIZE = 1000;
|
||||||
|
public static final int STATE_TREE_DEPTH = 32;
|
||||||
|
public static final int PROOF_EXPIRY_BLOCKS = 100;
|
||||||
|
}
|
||||||
455
sdk/js/src/zk/index.ts
Normal file
455
sdk/js/src/zk/index.ts
Normal file
|
|
@ -0,0 +1,455 @@
|
||||||
|
// Synor ZK SDK for JavaScript/TypeScript
|
||||||
|
//
|
||||||
|
// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
|
||||||
|
import {
|
||||||
|
ZkConfig,
|
||||||
|
ZkError,
|
||||||
|
DEFAULT_CONFIG,
|
||||||
|
ProofSystem,
|
||||||
|
CircuitType,
|
||||||
|
Proof,
|
||||||
|
VerificationKey,
|
||||||
|
ProvingKey,
|
||||||
|
CircuitConfig,
|
||||||
|
ProofRequest,
|
||||||
|
VerificationResult,
|
||||||
|
Batch,
|
||||||
|
RollupStats,
|
||||||
|
Transfer,
|
||||||
|
Deposit,
|
||||||
|
Withdrawal,
|
||||||
|
AccountState,
|
||||||
|
MerkleProof,
|
||||||
|
TrustedSetup,
|
||||||
|
CeremonyContribution,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK Client
|
||||||
|
*
|
||||||
|
* Provides zero-knowledge proof generation and verification for ZK-Rollups.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* const zk = new SynorZk({ apiKey: 'your-api-key' });
|
||||||
|
*
|
||||||
|
* // Generate a proof
|
||||||
|
* const proof = await zk.proofs.generate({
|
||||||
|
* circuitType: CircuitType.Transfer,
|
||||||
|
* publicInputs: [...],
|
||||||
|
* privateInputs: [...],
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Verify the proof
|
||||||
|
* const result = await zk.proofs.verify(proof);
|
||||||
|
* console.log('Valid:', result.valid);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class SynorZk {
|
||||||
|
private readonly config: Required<ZkConfig>;
|
||||||
|
private closed = false;
|
||||||
|
|
||||||
|
public readonly proofs: ProofsClient;
|
||||||
|
public readonly circuits: CircuitsClient;
|
||||||
|
public readonly rollup: RollupClient;
|
||||||
|
public readonly state: StateClient;
|
||||||
|
public readonly ceremony: CeremonyClient;
|
||||||
|
|
||||||
|
constructor(config: ZkConfig) {
|
||||||
|
this.config = {
|
||||||
|
...DEFAULT_CONFIG,
|
||||||
|
...config,
|
||||||
|
} as Required<ZkConfig>;
|
||||||
|
|
||||||
|
this.proofs = new ProofsClient(this);
|
||||||
|
this.circuits = new CircuitsClient(this);
|
||||||
|
this.rollup = new RollupClient(this);
|
||||||
|
this.state = new StateClient(this);
|
||||||
|
this.ceremony = new CeremonyClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default proof system
|
||||||
|
*/
|
||||||
|
get defaultProofSystem(): ProofSystem {
|
||||||
|
return this.config.defaultProofSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Health check
|
||||||
|
*/
|
||||||
|
async healthCheck(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const result = await this.get<{ status: string }>('/health');
|
||||||
|
return result.status === 'healthy';
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get service info
|
||||||
|
*/
|
||||||
|
async getInfo(): Promise<Record<string, unknown>> {
|
||||||
|
return this.get('/info');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the client
|
||||||
|
*/
|
||||||
|
close(): void {
|
||||||
|
this.closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if client is closed
|
||||||
|
*/
|
||||||
|
get isClosed(): boolean {
|
||||||
|
return this.closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal HTTP methods
|
||||||
|
async get<T>(path: string): Promise<T> {
|
||||||
|
return this.request<T>('GET', path);
|
||||||
|
}
|
||||||
|
|
||||||
|
async post<T>(path: string, body?: unknown): Promise<T> {
|
||||||
|
return this.request<T>('POST', path, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete<T>(path: string): Promise<T> {
|
||||||
|
return this.request<T>('DELETE', path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
|
||||||
|
if (this.closed) {
|
||||||
|
throw new ZkError('Client has been closed', 'CLIENT_CLOSED');
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${this.config.endpoint}${path}`;
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${this.config.apiKey}`,
|
||||||
|
'X-SDK-Version': 'js/0.1.0',
|
||||||
|
};
|
||||||
|
|
||||||
|
let lastError: Error | null = null;
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt <= this.config.retries; attempt++) {
|
||||||
|
try {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
body: body ? JSON.stringify(body) : undefined,
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const error = await response.json().catch(() => ({}));
|
||||||
|
throw new ZkError(
|
||||||
|
error.message || `HTTP ${response.status}`,
|
||||||
|
error.code,
|
||||||
|
response.status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error as Error;
|
||||||
|
if (error instanceof ZkError) throw error;
|
||||||
|
if (attempt < this.config.retries) {
|
||||||
|
await new Promise((r) => setTimeout(r, 100 * Math.pow(2, attempt)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ZkError(lastError?.message || 'Request failed', 'NETWORK_ERROR');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proofs sub-client
|
||||||
|
*/
|
||||||
|
export class ProofsClient {
|
||||||
|
constructor(private readonly zk: SynorZk) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a zero-knowledge proof
|
||||||
|
*/
|
||||||
|
async generate(request: ProofRequest): Promise<Proof> {
|
||||||
|
return this.zk.post('/proofs/generate', {
|
||||||
|
circuit_type: request.circuitType,
|
||||||
|
public_inputs: request.publicInputs,
|
||||||
|
private_inputs: request.privateInputs,
|
||||||
|
system: request.system || this.zk.defaultProofSystem,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a proof
|
||||||
|
*/
|
||||||
|
async verify(proof: Proof): Promise<VerificationResult> {
|
||||||
|
return this.zk.post('/proofs/verify', {
|
||||||
|
proof_id: proof.id,
|
||||||
|
data: proof.data,
|
||||||
|
public_inputs: proof.publicInputs,
|
||||||
|
system: proof.system,
|
||||||
|
circuit_type: proof.circuitType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a proof by ID
|
||||||
|
*/
|
||||||
|
async get(proofId: string): Promise<Proof> {
|
||||||
|
return this.zk.get(`/proofs/${proofId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List recent proofs
|
||||||
|
*/
|
||||||
|
async list(options?: { limit?: number; offset?: number }): Promise<Proof[]> {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (options?.limit) params.set('limit', options.limit.toString());
|
||||||
|
if (options?.offset) params.set('offset', options.offset.toString());
|
||||||
|
const query = params.toString();
|
||||||
|
const result = await this.zk.get<{ proofs: Proof[] }>(`/proofs${query ? `?${query}` : ''}`);
|
||||||
|
return result.proofs || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a proof to bytes
|
||||||
|
*/
|
||||||
|
async serialize(proof: Proof): Promise<Uint8Array> {
|
||||||
|
const result = await this.zk.post<{ data: string }>('/proofs/serialize', {
|
||||||
|
proof_id: proof.id,
|
||||||
|
});
|
||||||
|
return Uint8Array.from(atob(result.data), (c) => c.charCodeAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize bytes to a proof
|
||||||
|
*/
|
||||||
|
async deserialize(data: Uint8Array, system: ProofSystem): Promise<Proof> {
|
||||||
|
const base64 = btoa(String.fromCharCode(...data));
|
||||||
|
return this.zk.post('/proofs/deserialize', {
|
||||||
|
data: base64,
|
||||||
|
system,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Circuits sub-client
|
||||||
|
*/
|
||||||
|
export class CircuitsClient {
|
||||||
|
constructor(private readonly zk: SynorZk) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get verification key for a circuit
|
||||||
|
*/
|
||||||
|
async getVerificationKey(circuitType: CircuitType, system?: ProofSystem): Promise<VerificationKey> {
|
||||||
|
return this.zk.get(`/circuits/${circuitType}/vk?system=${system || this.zk.defaultProofSystem}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get proving key for a circuit
|
||||||
|
*/
|
||||||
|
async getProvingKey(circuitType: CircuitType, system?: ProofSystem): Promise<ProvingKey> {
|
||||||
|
return this.zk.get(`/circuits/${circuitType}/pk?system=${system || this.zk.defaultProofSystem}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List available circuits
|
||||||
|
*/
|
||||||
|
async list(): Promise<CircuitConfig[]> {
|
||||||
|
const result = await this.zk.get<{ circuits: CircuitConfig[] }>('/circuits');
|
||||||
|
return result.circuits || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get circuit configuration
|
||||||
|
*/
|
||||||
|
async getConfig(circuitType: CircuitType): Promise<CircuitConfig> {
|
||||||
|
return this.zk.get(`/circuits/${circuitType}/config`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile a custom circuit
|
||||||
|
*/
|
||||||
|
async compile(config: CircuitConfig): Promise<{ circuitId: string }> {
|
||||||
|
return this.zk.post('/circuits/compile', config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollup sub-client
|
||||||
|
*/
|
||||||
|
export class RollupClient {
|
||||||
|
constructor(private readonly zk: SynorZk) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get rollup statistics
|
||||||
|
*/
|
||||||
|
async getStats(): Promise<RollupStats> {
|
||||||
|
return this.zk.get('/rollup/stats');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current batch
|
||||||
|
*/
|
||||||
|
async getCurrentBatch(): Promise<Batch> {
|
||||||
|
return this.zk.get('/rollup/batch/current');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get batch by number
|
||||||
|
*/
|
||||||
|
async getBatch(batchNumber: number): Promise<Batch> {
|
||||||
|
return this.zk.get(`/rollup/batch/${batchNumber}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a transfer
|
||||||
|
*/
|
||||||
|
async submitTransfer(transfer: Transfer): Promise<{ txId: string }> {
|
||||||
|
return this.zk.post('/rollup/transfer', transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a deposit
|
||||||
|
*/
|
||||||
|
async submitDeposit(deposit: Deposit): Promise<{ txId: string }> {
|
||||||
|
return this.zk.post('/rollup/deposit', deposit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a withdrawal
|
||||||
|
*/
|
||||||
|
async submitWithdrawal(withdrawal: Withdrawal): Promise<{ txId: string }> {
|
||||||
|
return this.zk.post('/rollup/withdraw', withdrawal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize current batch (generates proof and submits to L1)
|
||||||
|
*/
|
||||||
|
async finalizeBatch(): Promise<Batch> {
|
||||||
|
return this.zk.post('/rollup/batch/finalize', {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get pending transactions
|
||||||
|
*/
|
||||||
|
async getPendingTransactions(): Promise<Transfer[]> {
|
||||||
|
const result = await this.zk.get<{ transactions: Transfer[] }>('/rollup/pending');
|
||||||
|
return result.transactions || [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State sub-client
|
||||||
|
*/
|
||||||
|
export class StateClient {
|
||||||
|
constructor(private readonly zk: SynorZk) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current state root
|
||||||
|
*/
|
||||||
|
async getRoot(): Promise<string> {
|
||||||
|
const result = await this.zk.get<{ root: string }>('/state/root');
|
||||||
|
return result.root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get account state
|
||||||
|
*/
|
||||||
|
async getAccount(address: string): Promise<AccountState> {
|
||||||
|
return this.zk.get(`/state/account/${address}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get merkle proof for account inclusion
|
||||||
|
*/
|
||||||
|
async getMerkleProof(address: string): Promise<MerkleProof> {
|
||||||
|
return this.zk.get(`/state/proof/${address}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify merkle proof
|
||||||
|
*/
|
||||||
|
async verifyMerkleProof(proof: MerkleProof): Promise<boolean> {
|
||||||
|
const result = await this.zk.post<{ valid: boolean }>('/state/proof/verify', proof);
|
||||||
|
return result.valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get state at specific batch
|
||||||
|
*/
|
||||||
|
async getStateAtBatch(batchNumber: number): Promise<{ root: string; accountCount: number }> {
|
||||||
|
return this.zk.get(`/state/batch/${batchNumber}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ceremony sub-client (trusted setup)
|
||||||
|
*/
|
||||||
|
export class CeremonyClient {
|
||||||
|
constructor(private readonly zk: SynorZk) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ceremony status
|
||||||
|
*/
|
||||||
|
async getStatus(circuitType: CircuitType, system?: ProofSystem): Promise<TrustedSetup> {
|
||||||
|
return this.zk.get(`/ceremony/${circuitType}?system=${system || this.zk.defaultProofSystem}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contribute to ceremony
|
||||||
|
*/
|
||||||
|
async contribute(
|
||||||
|
circuitType: CircuitType,
|
||||||
|
entropy: Uint8Array,
|
||||||
|
system?: ProofSystem
|
||||||
|
): Promise<CeremonyContribution> {
|
||||||
|
const entropyBase64 = btoa(String.fromCharCode(...entropy));
|
||||||
|
return this.zk.post('/ceremony/contribute', {
|
||||||
|
circuit_type: circuitType,
|
||||||
|
entropy: entropyBase64,
|
||||||
|
system: system || this.zk.defaultProofSystem,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a contribution
|
||||||
|
*/
|
||||||
|
async verifyContribution(
|
||||||
|
circuitType: CircuitType,
|
||||||
|
contributionHash: string
|
||||||
|
): Promise<{ valid: boolean }> {
|
||||||
|
return this.zk.post('/ceremony/verify', {
|
||||||
|
circuit_type: circuitType,
|
||||||
|
contribution_hash: contributionHash,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List contributions
|
||||||
|
*/
|
||||||
|
async listContributions(circuitType: CircuitType): Promise<CeremonyContribution[]> {
|
||||||
|
const result = await this.zk.get<{ contributions: CeremonyContribution[] }>(
|
||||||
|
`/ceremony/${circuitType}/contributions`
|
||||||
|
);
|
||||||
|
return result.contributions || [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default export
|
||||||
|
export default SynorZk;
|
||||||
401
sdk/js/src/zk/types.ts
Normal file
401
sdk/js/src/zk/types.ts
Normal file
|
|
@ -0,0 +1,401 @@
|
||||||
|
// Synor ZK SDK Types for JavaScript/TypeScript
|
||||||
|
//
|
||||||
|
// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proof system backends
|
||||||
|
*/
|
||||||
|
export enum ProofSystem {
|
||||||
|
/** Groth16 - smallest proofs (~192 bytes), fastest verification */
|
||||||
|
Groth16 = 'groth16',
|
||||||
|
/** PLONK - universal trusted setup, medium proofs (~512 bytes) */
|
||||||
|
Plonk = 'plonk',
|
||||||
|
/** STARK - no trusted setup, largest proofs (~50KB) */
|
||||||
|
Stark = 'stark',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Circuit types for different operations
|
||||||
|
*/
|
||||||
|
export enum CircuitType {
|
||||||
|
/** Single transfer between accounts */
|
||||||
|
Transfer = 'transfer',
|
||||||
|
/** Batch of multiple transfers */
|
||||||
|
Batch = 'batch',
|
||||||
|
/** Deposit from L1 to L2 */
|
||||||
|
Deposit = 'deposit',
|
||||||
|
/** Withdrawal from L2 to L1 */
|
||||||
|
Withdraw = 'withdraw',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollup state
|
||||||
|
*/
|
||||||
|
export enum RollupState {
|
||||||
|
/** Rollup is accepting transactions */
|
||||||
|
Active = 'active',
|
||||||
|
/** Rollup is paused */
|
||||||
|
Paused = 'paused',
|
||||||
|
/** Rollup is finalizing */
|
||||||
|
Finalizing = 'finalizing',
|
||||||
|
/** Rollup has been finalized */
|
||||||
|
Finalized = 'finalized',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proof status
|
||||||
|
*/
|
||||||
|
export enum ProofStatus {
|
||||||
|
/** Proof is being generated */
|
||||||
|
Generating = 'generating',
|
||||||
|
/** Proof generation completed */
|
||||||
|
Completed = 'completed',
|
||||||
|
/** Proof generation failed */
|
||||||
|
Failed = 'failed',
|
||||||
|
/** Proof has been verified */
|
||||||
|
Verified = 'verified',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zero-knowledge proof
|
||||||
|
*/
|
||||||
|
export interface Proof {
|
||||||
|
/** Unique proof identifier */
|
||||||
|
id: string;
|
||||||
|
/** Proof system used */
|
||||||
|
system: ProofSystem;
|
||||||
|
/** Circuit type */
|
||||||
|
circuitType: CircuitType;
|
||||||
|
/** Serialized proof data (base64) */
|
||||||
|
data: string;
|
||||||
|
/** Public inputs (base64 encoded) */
|
||||||
|
publicInputs: string[];
|
||||||
|
/** Proof size in bytes */
|
||||||
|
size: number;
|
||||||
|
/** Generation time in milliseconds */
|
||||||
|
generationTimeMs: number;
|
||||||
|
/** Timestamp when proof was created */
|
||||||
|
createdAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verification key for a circuit
|
||||||
|
*/
|
||||||
|
export interface VerificationKey {
|
||||||
|
/** Circuit identifier */
|
||||||
|
circuitId: string;
|
||||||
|
/** Circuit type */
|
||||||
|
circuitType: CircuitType;
|
||||||
|
/** Proof system */
|
||||||
|
system: ProofSystem;
|
||||||
|
/** Serialized verification key (base64) */
|
||||||
|
data: string;
|
||||||
|
/** Key size in bytes */
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proving key for generating proofs
|
||||||
|
*/
|
||||||
|
export interface ProvingKey {
|
||||||
|
/** Circuit identifier */
|
||||||
|
circuitId: string;
|
||||||
|
/** Circuit type */
|
||||||
|
circuitType: CircuitType;
|
||||||
|
/** Proof system */
|
||||||
|
system: ProofSystem;
|
||||||
|
/** Serialized proving key (base64) */
|
||||||
|
data: string;
|
||||||
|
/** Key size in bytes */
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Circuit configuration
|
||||||
|
*/
|
||||||
|
export interface CircuitConfig {
|
||||||
|
/** Circuit type */
|
||||||
|
type: CircuitType;
|
||||||
|
/** Maximum batch size for batch circuits */
|
||||||
|
maxBatchSize?: number;
|
||||||
|
/** State tree depth */
|
||||||
|
treeDepth?: number;
|
||||||
|
/** Whether to verify signatures in circuit */
|
||||||
|
verifySignatures?: boolean;
|
||||||
|
/** Custom constraints */
|
||||||
|
customConstraints?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State tree node
|
||||||
|
*/
|
||||||
|
export interface StateNode {
|
||||||
|
/** Node hash */
|
||||||
|
hash: string;
|
||||||
|
/** Left child hash (if internal node) */
|
||||||
|
left?: string;
|
||||||
|
/** Right child hash (if internal node) */
|
||||||
|
right?: string;
|
||||||
|
/** Account data (if leaf node) */
|
||||||
|
account?: AccountState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account state in the rollup
|
||||||
|
*/
|
||||||
|
export interface AccountState {
|
||||||
|
/** Account address */
|
||||||
|
address: string;
|
||||||
|
/** Account balance */
|
||||||
|
balance: string;
|
||||||
|
/** Account nonce */
|
||||||
|
nonce: number;
|
||||||
|
/** Public key hash */
|
||||||
|
pubkeyHash: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer operation
|
||||||
|
*/
|
||||||
|
export interface Transfer {
|
||||||
|
/** Sender address */
|
||||||
|
from: string;
|
||||||
|
/** Recipient address */
|
||||||
|
to: string;
|
||||||
|
/** Amount to transfer */
|
||||||
|
amount: string;
|
||||||
|
/** Fee */
|
||||||
|
fee: string;
|
||||||
|
/** Nonce */
|
||||||
|
nonce: number;
|
||||||
|
/** Signature */
|
||||||
|
signature?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deposit operation (L1 -> L2)
|
||||||
|
*/
|
||||||
|
export interface Deposit {
|
||||||
|
/** L1 transaction hash */
|
||||||
|
l1TxHash: string;
|
||||||
|
/** Recipient address on L2 */
|
||||||
|
recipient: string;
|
||||||
|
/** Amount deposited */
|
||||||
|
amount: string;
|
||||||
|
/** Token address (or native if null) */
|
||||||
|
token?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdrawal operation (L2 -> L1)
|
||||||
|
*/
|
||||||
|
export interface Withdrawal {
|
||||||
|
/** Sender address on L2 */
|
||||||
|
sender: string;
|
||||||
|
/** Recipient address on L1 */
|
||||||
|
recipient: string;
|
||||||
|
/** Amount to withdraw */
|
||||||
|
amount: string;
|
||||||
|
/** Token address (or native if null) */
|
||||||
|
token?: string;
|
||||||
|
/** Nonce */
|
||||||
|
nonce: number;
|
||||||
|
/** Signature */
|
||||||
|
signature?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollup batch
|
||||||
|
*/
|
||||||
|
export interface Batch {
|
||||||
|
/** Batch number */
|
||||||
|
batchNumber: number;
|
||||||
|
/** Previous state root */
|
||||||
|
prevStateRoot: string;
|
||||||
|
/** New state root after batch */
|
||||||
|
newStateRoot: string;
|
||||||
|
/** Transfers in this batch */
|
||||||
|
transfers: Transfer[];
|
||||||
|
/** Deposits in this batch */
|
||||||
|
deposits: Deposit[];
|
||||||
|
/** Withdrawals in this batch */
|
||||||
|
withdrawals: Withdrawal[];
|
||||||
|
/** Batch proof (once generated) */
|
||||||
|
proof?: Proof;
|
||||||
|
/** Timestamp */
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollup statistics
|
||||||
|
*/
|
||||||
|
export interface RollupStats {
|
||||||
|
/** Current batch number */
|
||||||
|
currentBatch: number;
|
||||||
|
/** Total transactions processed */
|
||||||
|
totalTransactions: number;
|
||||||
|
/** Total proofs generated */
|
||||||
|
totalProofs: number;
|
||||||
|
/** Average proof generation time (ms) */
|
||||||
|
avgProofTimeMs: number;
|
||||||
|
/** Current state root */
|
||||||
|
stateRoot: string;
|
||||||
|
/** Number of accounts */
|
||||||
|
accountCount: number;
|
||||||
|
/** Total value locked */
|
||||||
|
tvl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proof generation request
|
||||||
|
*/
|
||||||
|
export interface ProofRequest {
|
||||||
|
/** Circuit type */
|
||||||
|
circuitType: CircuitType;
|
||||||
|
/** Public inputs */
|
||||||
|
publicInputs: string[];
|
||||||
|
/** Private inputs (witness) */
|
||||||
|
privateInputs: string[];
|
||||||
|
/** Proof system to use */
|
||||||
|
system?: ProofSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proof verification result
|
||||||
|
*/
|
||||||
|
export interface VerificationResult {
|
||||||
|
/** Whether the proof is valid */
|
||||||
|
valid: boolean;
|
||||||
|
/** Verification time in milliseconds */
|
||||||
|
verificationTimeMs: number;
|
||||||
|
/** Error message if invalid */
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup ceremony contribution
|
||||||
|
*/
|
||||||
|
export interface CeremonyContribution {
|
||||||
|
/** Contributor identifier */
|
||||||
|
contributorId: string;
|
||||||
|
/** Contribution hash */
|
||||||
|
hash: string;
|
||||||
|
/** Timestamp */
|
||||||
|
timestamp: number;
|
||||||
|
/** Verification status */
|
||||||
|
verified: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trusted setup ceremony
|
||||||
|
*/
|
||||||
|
export interface TrustedSetup {
|
||||||
|
/** Ceremony identifier */
|
||||||
|
id: string;
|
||||||
|
/** Circuit type */
|
||||||
|
circuitType: CircuitType;
|
||||||
|
/** Proof system */
|
||||||
|
system: ProofSystem;
|
||||||
|
/** Number of contributions */
|
||||||
|
contributionCount: number;
|
||||||
|
/** Latest contribution hash */
|
||||||
|
latestHash: string;
|
||||||
|
/** Whether ceremony is complete */
|
||||||
|
complete: boolean;
|
||||||
|
/** Contributions */
|
||||||
|
contributions: CeremonyContribution[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merkle proof for state inclusion
|
||||||
|
*/
|
||||||
|
export interface MerkleProof {
|
||||||
|
/** Leaf value */
|
||||||
|
leaf: string;
|
||||||
|
/** Path from leaf to root (sibling hashes) */
|
||||||
|
path: string[];
|
||||||
|
/** Path indices (0 = left, 1 = right) */
|
||||||
|
indices: number[];
|
||||||
|
/** Root hash */
|
||||||
|
root: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZK SDK configuration
|
||||||
|
*/
|
||||||
|
export interface ZkConfig {
|
||||||
|
/** API key for authentication */
|
||||||
|
apiKey: string;
|
||||||
|
/** API endpoint */
|
||||||
|
endpoint?: string;
|
||||||
|
/** WebSocket endpoint for subscriptions */
|
||||||
|
wsEndpoint?: string;
|
||||||
|
/** Request timeout in milliseconds */
|
||||||
|
timeout?: number;
|
||||||
|
/** Number of retries for failed requests */
|
||||||
|
retries?: number;
|
||||||
|
/** Default proof system */
|
||||||
|
defaultProofSystem?: ProofSystem;
|
||||||
|
/** Enable debug logging */
|
||||||
|
debug?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZK SDK error
|
||||||
|
*/
|
||||||
|
export class ZkError extends Error {
|
||||||
|
constructor(
|
||||||
|
message: string,
|
||||||
|
public readonly code?: string,
|
||||||
|
public readonly status?: number
|
||||||
|
) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'ZkError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default configuration values
|
||||||
|
*/
|
||||||
|
export const DEFAULT_CONFIG = {
|
||||||
|
endpoint: 'https://zk.synor.io/v1',
|
||||||
|
wsEndpoint: 'wss://zk.synor.io/v1/ws',
|
||||||
|
timeout: 60000, // ZK proofs can take longer
|
||||||
|
retries: 3,
|
||||||
|
defaultProofSystem: ProofSystem.Groth16,
|
||||||
|
debug: false,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proof system characteristics
|
||||||
|
*/
|
||||||
|
export const PROOF_SYSTEM_INFO = {
|
||||||
|
[ProofSystem.Groth16]: {
|
||||||
|
name: 'Groth16',
|
||||||
|
proofSize: 192,
|
||||||
|
verificationTimeMs: 10,
|
||||||
|
trustedSetup: true,
|
||||||
|
universal: false,
|
||||||
|
},
|
||||||
|
[ProofSystem.Plonk]: {
|
||||||
|
name: 'PLONK',
|
||||||
|
proofSize: 512,
|
||||||
|
verificationTimeMs: 15,
|
||||||
|
trustedSetup: true,
|
||||||
|
universal: true,
|
||||||
|
},
|
||||||
|
[ProofSystem.Stark]: {
|
||||||
|
name: 'STARK',
|
||||||
|
proofSize: 50000,
|
||||||
|
verificationTimeMs: 30,
|
||||||
|
trustedSetup: false,
|
||||||
|
universal: true,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants
|
||||||
|
*/
|
||||||
|
export const MAX_BATCH_SIZE = 1000;
|
||||||
|
export const STATE_TREE_DEPTH = 32;
|
||||||
|
export const PROOF_EXPIRY_BLOCKS = 100;
|
||||||
449
sdk/kotlin/src/main/kotlin/io/synor/zk/SynorZk.kt
Normal file
449
sdk/kotlin/src/main/kotlin/io/synor/zk/SynorZk.kt
Normal file
|
|
@ -0,0 +1,449 @@
|
||||||
|
package io.synor.zk
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.json.*
|
||||||
|
import java.net.URI
|
||||||
|
import java.net.http.HttpClient
|
||||||
|
import java.net.http.HttpRequest
|
||||||
|
import java.net.http.HttpResponse
|
||||||
|
import java.time.Duration
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK for Kotlin
|
||||||
|
*
|
||||||
|
* Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Enums
|
||||||
|
enum class ProofSystem(val value: String) {
|
||||||
|
@SerialName("groth16") GROTH16("groth16"),
|
||||||
|
@SerialName("plonk") PLONK("plonk"),
|
||||||
|
@SerialName("stark") STARK("stark");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromString(value: String) = entries.find { it.value == value } ?: GROTH16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class CircuitType(val value: String) {
|
||||||
|
@SerialName("transfer") TRANSFER("transfer"),
|
||||||
|
@SerialName("batch") BATCH("batch"),
|
||||||
|
@SerialName("deposit") DEPOSIT("deposit"),
|
||||||
|
@SerialName("withdraw") WITHDRAW("withdraw");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromString(value: String) = entries.find { it.value == value } ?: TRANSFER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class RollupState { ACTIVE, PAUSED, FINALIZING, FINALIZED }
|
||||||
|
enum class ProofStatus { GENERATING, COMPLETED, FAILED, VERIFIED }
|
||||||
|
|
||||||
|
// Data classes
|
||||||
|
@Serializable
|
||||||
|
data class Proof(
|
||||||
|
val id: String,
|
||||||
|
val system: ProofSystem,
|
||||||
|
@SerialName("circuit_type") val circuitType: CircuitType,
|
||||||
|
val data: String,
|
||||||
|
@SerialName("public_inputs") val publicInputs: List<String>,
|
||||||
|
val size: Int,
|
||||||
|
@SerialName("generation_time_ms") val generationTimeMs: Long,
|
||||||
|
@SerialName("created_at") val createdAt: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class VerificationKey(
|
||||||
|
@SerialName("circuit_id") val circuitId: String,
|
||||||
|
@SerialName("circuit_type") val circuitType: CircuitType,
|
||||||
|
val system: ProofSystem,
|
||||||
|
val data: String,
|
||||||
|
val size: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ProvingKey(
|
||||||
|
@SerialName("circuit_id") val circuitId: String,
|
||||||
|
@SerialName("circuit_type") val circuitType: CircuitType,
|
||||||
|
val system: ProofSystem,
|
||||||
|
val data: String,
|
||||||
|
val size: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CircuitConfig(
|
||||||
|
val type: CircuitType,
|
||||||
|
@SerialName("max_batch_size") val maxBatchSize: Int? = null,
|
||||||
|
@SerialName("tree_depth") val treeDepth: Int? = null,
|
||||||
|
@SerialName("verify_signatures") val verifySignatures: Boolean? = null,
|
||||||
|
@SerialName("custom_constraints") val customConstraints: JsonObject? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AccountState(
|
||||||
|
val address: String,
|
||||||
|
val balance: String,
|
||||||
|
val nonce: Long,
|
||||||
|
@SerialName("pubkey_hash") val pubkeyHash: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Transfer(
|
||||||
|
val from: String,
|
||||||
|
val to: String,
|
||||||
|
val amount: String,
|
||||||
|
val fee: String,
|
||||||
|
val nonce: Long,
|
||||||
|
val signature: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Deposit(
|
||||||
|
@SerialName("l1_tx_hash") val l1TxHash: String,
|
||||||
|
val recipient: String,
|
||||||
|
val amount: String,
|
||||||
|
val token: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Withdrawal(
|
||||||
|
val sender: String,
|
||||||
|
val recipient: String,
|
||||||
|
val amount: String,
|
||||||
|
val token: String? = null,
|
||||||
|
val nonce: Long,
|
||||||
|
val signature: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Batch(
|
||||||
|
@SerialName("batch_number") val batchNumber: Long,
|
||||||
|
@SerialName("prev_state_root") val prevStateRoot: String,
|
||||||
|
@SerialName("new_state_root") val newStateRoot: String,
|
||||||
|
val transfers: List<Transfer>,
|
||||||
|
val deposits: List<Deposit>,
|
||||||
|
val withdrawals: List<Withdrawal>,
|
||||||
|
val proof: Proof? = null,
|
||||||
|
val timestamp: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RollupStats(
|
||||||
|
@SerialName("current_batch") val currentBatch: Long,
|
||||||
|
@SerialName("total_transactions") val totalTransactions: Long,
|
||||||
|
@SerialName("total_proofs") val totalProofs: Long,
|
||||||
|
@SerialName("avg_proof_time_ms") val avgProofTimeMs: Long,
|
||||||
|
@SerialName("state_root") val stateRoot: String,
|
||||||
|
@SerialName("account_count") val accountCount: Long,
|
||||||
|
val tvl: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ProofRequest(
|
||||||
|
@SerialName("circuit_type") val circuitType: CircuitType,
|
||||||
|
@SerialName("public_inputs") val publicInputs: List<String>,
|
||||||
|
@SerialName("private_inputs") val privateInputs: List<String>,
|
||||||
|
val system: ProofSystem? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class VerificationResult(
|
||||||
|
val valid: Boolean,
|
||||||
|
@SerialName("verification_time_ms") val verificationTimeMs: Long,
|
||||||
|
val error: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MerkleProof(
|
||||||
|
val leaf: String,
|
||||||
|
val path: List<String>,
|
||||||
|
val indices: List<Int>,
|
||||||
|
val root: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CeremonyContribution(
|
||||||
|
@SerialName("contributor_id") val contributorId: String,
|
||||||
|
val hash: String,
|
||||||
|
val timestamp: Long,
|
||||||
|
val verified: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TrustedSetup(
|
||||||
|
val id: String,
|
||||||
|
@SerialName("circuit_type") val circuitType: CircuitType,
|
||||||
|
val system: ProofSystem,
|
||||||
|
@SerialName("contribution_count") val contributionCount: Int,
|
||||||
|
@SerialName("latest_hash") val latestHash: String,
|
||||||
|
val complete: Boolean,
|
||||||
|
val contributions: List<CeremonyContribution>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ZkConfig(
|
||||||
|
val apiKey: String,
|
||||||
|
val endpoint: String = "https://zk.synor.io/v1",
|
||||||
|
val wsEndpoint: String = "wss://zk.synor.io/v1/ws",
|
||||||
|
val timeout: Long = 60000,
|
||||||
|
val retries: Int = 3,
|
||||||
|
val defaultProofSystem: ProofSystem = ProofSystem.GROTH16,
|
||||||
|
val debug: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
class ZkException(
|
||||||
|
message: String,
|
||||||
|
val code: String? = null,
|
||||||
|
val status: Int? = null
|
||||||
|
) : RuntimeException(message)
|
||||||
|
|
||||||
|
data class ProofSystemInfo(
|
||||||
|
val name: String,
|
||||||
|
val proofSize: Int,
|
||||||
|
val verificationTimeMs: Int,
|
||||||
|
val trustedSetup: Boolean,
|
||||||
|
val universal: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getProofSystemInfo(system: ProofSystem): ProofSystemInfo = when (system) {
|
||||||
|
ProofSystem.GROTH16 -> ProofSystemInfo("Groth16", 192, 10, true, false)
|
||||||
|
ProofSystem.PLONK -> ProofSystemInfo("PLONK", 512, 15, true, true)
|
||||||
|
ProofSystem.STARK -> ProofSystemInfo("STARK", 50000, 30, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const val MAX_BATCH_SIZE = 1000
|
||||||
|
const val STATE_TREE_DEPTH = 32
|
||||||
|
const val PROOF_EXPIRY_BLOCKS = 100
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main ZK SDK client
|
||||||
|
*/
|
||||||
|
class SynorZk(private val config: ZkConfig) {
|
||||||
|
private val httpClient = HttpClient.newBuilder()
|
||||||
|
.connectTimeout(Duration.ofMillis(config.timeout))
|
||||||
|
.build()
|
||||||
|
private val json = Json { ignoreUnknownKeys = true }
|
||||||
|
private val closed = AtomicBoolean(false)
|
||||||
|
|
||||||
|
val proofs = ProofsClient(this)
|
||||||
|
val circuits = CircuitsClient(this)
|
||||||
|
val rollup = RollupClient(this)
|
||||||
|
val state = StateClient(this)
|
||||||
|
val ceremony = CeremonyClient(this)
|
||||||
|
|
||||||
|
val defaultProofSystem: ProofSystem get() = config.defaultProofSystem
|
||||||
|
|
||||||
|
suspend fun healthCheck(): Boolean = try {
|
||||||
|
val result = get<JsonObject>("/health")
|
||||||
|
result["status"]?.jsonPrimitive?.content == "healthy"
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getInfo(): JsonObject = get("/info")
|
||||||
|
|
||||||
|
fun close() { closed.set(true) }
|
||||||
|
val isClosed: Boolean get() = closed.get()
|
||||||
|
|
||||||
|
internal suspend inline fun <reified T> get(path: String): T = request("GET", path, null)
|
||||||
|
internal suspend inline fun <reified T> post(path: String, body: Any?): T = request("POST", path, body)
|
||||||
|
|
||||||
|
internal suspend inline fun <reified T> request(method: String, path: String, body: Any?): T {
|
||||||
|
if (closed.get()) throw ZkException("Client has been closed", "CLIENT_CLOSED")
|
||||||
|
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val url = "${config.endpoint}$path"
|
||||||
|
val requestBuilder = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(url))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", "Bearer ${config.apiKey}")
|
||||||
|
.header("X-SDK-Version", "kotlin/0.1.0")
|
||||||
|
.timeout(Duration.ofMillis(config.timeout))
|
||||||
|
|
||||||
|
when (method) {
|
||||||
|
"GET" -> requestBuilder.GET()
|
||||||
|
"POST" -> {
|
||||||
|
val jsonBody = if (body != null) json.encodeToString(body as? JsonElement ?: buildJsonObject {
|
||||||
|
(body as? Map<*, *>)?.forEach { (k, v) ->
|
||||||
|
put(k.toString(), when (v) {
|
||||||
|
is String -> JsonPrimitive(v)
|
||||||
|
is Number -> JsonPrimitive(v)
|
||||||
|
is Boolean -> JsonPrimitive(v)
|
||||||
|
is List<*> -> JsonArray(v.map { JsonPrimitive(it.toString()) })
|
||||||
|
else -> JsonPrimitive(v.toString())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}) else "{}"
|
||||||
|
requestBuilder.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
|
||||||
|
}
|
||||||
|
"DELETE" -> requestBuilder.DELETE()
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString())
|
||||||
|
|
||||||
|
if (response.statusCode() >= 400) {
|
||||||
|
val error = json.parseToJsonElement(response.body()).jsonObject
|
||||||
|
throw ZkException(
|
||||||
|
error["message"]?.jsonPrimitive?.content ?: "HTTP ${response.statusCode()}",
|
||||||
|
error["code"]?.jsonPrimitive?.content,
|
||||||
|
response.statusCode()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
json.decodeFromString(response.body())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProofsClient(private val zk: SynorZk) {
|
||||||
|
suspend fun generate(request: ProofRequest): Proof {
|
||||||
|
val body = buildJsonObject {
|
||||||
|
put("circuit_type", request.circuitType.value)
|
||||||
|
put("public_inputs", JsonArray(request.publicInputs.map { JsonPrimitive(it) }))
|
||||||
|
put("private_inputs", JsonArray(request.privateInputs.map { JsonPrimitive(it) }))
|
||||||
|
put("system", (request.system ?: zk.defaultProofSystem).value)
|
||||||
|
}
|
||||||
|
return zk.post("/proofs/generate", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun verify(proof: Proof): VerificationResult {
|
||||||
|
val body = buildJsonObject {
|
||||||
|
put("proof_id", proof.id)
|
||||||
|
put("data", proof.data)
|
||||||
|
put("public_inputs", JsonArray(proof.publicInputs.map { JsonPrimitive(it) }))
|
||||||
|
put("system", proof.system.value)
|
||||||
|
put("circuit_type", proof.circuitType.value)
|
||||||
|
}
|
||||||
|
return zk.post("/proofs/verify", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun get(proofId: String): Proof = zk.get("/proofs/$proofId")
|
||||||
|
|
||||||
|
suspend fun list(limit: Int? = null, offset: Int? = null): List<Proof> {
|
||||||
|
val params = listOfNotNull(
|
||||||
|
limit?.let { "limit=$it" },
|
||||||
|
offset?.let { "offset=$it" }
|
||||||
|
).joinToString("&")
|
||||||
|
val path = if (params.isNotEmpty()) "/proofs?$params" else "/proofs"
|
||||||
|
val result: JsonObject = zk.get(path)
|
||||||
|
return result["proofs"]?.jsonArray?.map { Json.decodeFromJsonElement(it) } ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun serialize(proof: Proof): ByteArray {
|
||||||
|
val body = buildJsonObject { put("proof_id", proof.id) }
|
||||||
|
val result: JsonObject = zk.post("/proofs/serialize", body)
|
||||||
|
return Base64.getDecoder().decode(result["data"]?.jsonPrimitive?.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun deserialize(data: ByteArray, system: ProofSystem): Proof {
|
||||||
|
val body = buildJsonObject {
|
||||||
|
put("data", Base64.getEncoder().encodeToString(data))
|
||||||
|
put("system", system.value)
|
||||||
|
}
|
||||||
|
return zk.post("/proofs/deserialize", body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CircuitsClient(private val zk: SynorZk) {
|
||||||
|
suspend fun getVerificationKey(circuitType: CircuitType, system: ProofSystem? = null): VerificationKey {
|
||||||
|
val sys = system ?: zk.defaultProofSystem
|
||||||
|
return zk.get("/circuits/${circuitType.value}/vk?system=${sys.value}")
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getProvingKey(circuitType: CircuitType, system: ProofSystem? = null): ProvingKey {
|
||||||
|
val sys = system ?: zk.defaultProofSystem
|
||||||
|
return zk.get("/circuits/${circuitType.value}/pk?system=${sys.value}")
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun list(): List<CircuitConfig> {
|
||||||
|
val result: JsonObject = zk.get("/circuits")
|
||||||
|
return result["circuits"]?.jsonArray?.map { Json.decodeFromJsonElement(it) } ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getConfig(circuitType: CircuitType): CircuitConfig =
|
||||||
|
zk.get("/circuits/${circuitType.value}/config")
|
||||||
|
|
||||||
|
suspend fun compile(config: CircuitConfig): String {
|
||||||
|
val result: JsonObject = zk.post("/circuits/compile", Json.encodeToJsonElement(config))
|
||||||
|
return result["circuit_id"]?.jsonPrimitive?.content ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RollupClient(private val zk: SynorZk) {
|
||||||
|
suspend fun getStats(): RollupStats = zk.get("/rollup/stats")
|
||||||
|
suspend fun getCurrentBatch(): Batch = zk.get("/rollup/batch/current")
|
||||||
|
suspend fun getBatch(batchNumber: Long): Batch = zk.get("/rollup/batch/$batchNumber")
|
||||||
|
|
||||||
|
suspend fun submitTransfer(transfer: Transfer): String {
|
||||||
|
val result: JsonObject = zk.post("/rollup/transfer", Json.encodeToJsonElement(transfer))
|
||||||
|
return result["tx_id"]?.jsonPrimitive?.content ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun submitDeposit(deposit: Deposit): String {
|
||||||
|
val result: JsonObject = zk.post("/rollup/deposit", Json.encodeToJsonElement(deposit))
|
||||||
|
return result["tx_id"]?.jsonPrimitive?.content ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun submitWithdrawal(withdrawal: Withdrawal): String {
|
||||||
|
val result: JsonObject = zk.post("/rollup/withdraw", Json.encodeToJsonElement(withdrawal))
|
||||||
|
return result["tx_id"]?.jsonPrimitive?.content ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun finalizeBatch(): Batch = zk.post("/rollup/batch/finalize", buildJsonObject {})
|
||||||
|
|
||||||
|
suspend fun getPendingTransactions(): List<Transfer> {
|
||||||
|
val result: JsonObject = zk.get("/rollup/pending")
|
||||||
|
return result["transactions"]?.jsonArray?.map { Json.decodeFromJsonElement(it) } ?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StateClient(private val zk: SynorZk) {
|
||||||
|
suspend fun getRoot(): String {
|
||||||
|
val result: JsonObject = zk.get("/state/root")
|
||||||
|
return result["root"]?.jsonPrimitive?.content ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getAccount(address: String): AccountState = zk.get("/state/account/$address")
|
||||||
|
suspend fun getMerkleProof(address: String): MerkleProof = zk.get("/state/proof/$address")
|
||||||
|
|
||||||
|
suspend fun verifyMerkleProof(proof: MerkleProof): Boolean {
|
||||||
|
val result: JsonObject = zk.post("/state/proof/verify", Json.encodeToJsonElement(proof))
|
||||||
|
return result["valid"]?.jsonPrimitive?.boolean ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getStateAtBatch(batchNumber: Long): JsonObject = zk.get("/state/batch/$batchNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
class CeremonyClient(private val zk: SynorZk) {
|
||||||
|
suspend fun getStatus(circuitType: CircuitType, system: ProofSystem? = null): TrustedSetup {
|
||||||
|
val sys = system ?: zk.defaultProofSystem
|
||||||
|
return zk.get("/ceremony/${circuitType.value}?system=${sys.value}")
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun contribute(circuitType: CircuitType, entropy: ByteArray, system: ProofSystem? = null): CeremonyContribution {
|
||||||
|
val sys = system ?: zk.defaultProofSystem
|
||||||
|
val body = buildJsonObject {
|
||||||
|
put("circuit_type", circuitType.value)
|
||||||
|
put("entropy", Base64.getEncoder().encodeToString(entropy))
|
||||||
|
put("system", sys.value)
|
||||||
|
}
|
||||||
|
return zk.post("/ceremony/contribute", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun verifyContribution(circuitType: CircuitType, contributionHash: String): Boolean {
|
||||||
|
val body = buildJsonObject {
|
||||||
|
put("circuit_type", circuitType.value)
|
||||||
|
put("contribution_hash", contributionHash)
|
||||||
|
}
|
||||||
|
val result: JsonObject = zk.post("/ceremony/verify", body)
|
||||||
|
return result["valid"]?.jsonPrimitive?.boolean ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun listContributions(circuitType: CircuitType): List<CeremonyContribution> {
|
||||||
|
val result: JsonObject = zk.get("/ceremony/${circuitType.value}/contributions")
|
||||||
|
return result["contributions"]?.jsonArray?.map { Json.decodeFromJsonElement(it) } ?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
62
sdk/python/src/synor_zk/__init__.py
Normal file
62
sdk/python/src/synor_zk/__init__.py
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
"""
|
||||||
|
Synor ZK SDK for Python
|
||||||
|
|
||||||
|
Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .types import (
|
||||||
|
ProofSystem,
|
||||||
|
CircuitType,
|
||||||
|
RollupState,
|
||||||
|
ProofStatus,
|
||||||
|
Proof,
|
||||||
|
VerificationKey,
|
||||||
|
ProvingKey,
|
||||||
|
CircuitConfig,
|
||||||
|
AccountState,
|
||||||
|
Transfer,
|
||||||
|
Deposit,
|
||||||
|
Withdrawal,
|
||||||
|
Batch,
|
||||||
|
RollupStats,
|
||||||
|
ProofRequest,
|
||||||
|
VerificationResult,
|
||||||
|
MerkleProof,
|
||||||
|
TrustedSetup,
|
||||||
|
CeremonyContribution,
|
||||||
|
ZkConfig,
|
||||||
|
ZkError,
|
||||||
|
DEFAULT_CONFIG,
|
||||||
|
MAX_BATCH_SIZE,
|
||||||
|
STATE_TREE_DEPTH,
|
||||||
|
)
|
||||||
|
from .client import SynorZk
|
||||||
|
|
||||||
|
__version__ = "0.1.0"
|
||||||
|
__all__ = [
|
||||||
|
"SynorZk",
|
||||||
|
"ProofSystem",
|
||||||
|
"CircuitType",
|
||||||
|
"RollupState",
|
||||||
|
"ProofStatus",
|
||||||
|
"Proof",
|
||||||
|
"VerificationKey",
|
||||||
|
"ProvingKey",
|
||||||
|
"CircuitConfig",
|
||||||
|
"AccountState",
|
||||||
|
"Transfer",
|
||||||
|
"Deposit",
|
||||||
|
"Withdrawal",
|
||||||
|
"Batch",
|
||||||
|
"RollupStats",
|
||||||
|
"ProofRequest",
|
||||||
|
"VerificationResult",
|
||||||
|
"MerkleProof",
|
||||||
|
"TrustedSetup",
|
||||||
|
"CeremonyContribution",
|
||||||
|
"ZkConfig",
|
||||||
|
"ZkError",
|
||||||
|
"DEFAULT_CONFIG",
|
||||||
|
"MAX_BATCH_SIZE",
|
||||||
|
"STATE_TREE_DEPTH",
|
||||||
|
]
|
||||||
407
sdk/python/src/synor_zk/client.py
Normal file
407
sdk/python/src/synor_zk/client.py
Normal file
|
|
@ -0,0 +1,407 @@
|
||||||
|
"""
|
||||||
|
Synor ZK SDK Client for Python
|
||||||
|
|
||||||
|
Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import base64
|
||||||
|
from typing import Optional, List, Dict, Any
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
from .types import (
|
||||||
|
ProofSystem,
|
||||||
|
CircuitType,
|
||||||
|
Proof,
|
||||||
|
VerificationKey,
|
||||||
|
ProvingKey,
|
||||||
|
CircuitConfig,
|
||||||
|
AccountState,
|
||||||
|
Transfer,
|
||||||
|
Deposit,
|
||||||
|
Withdrawal,
|
||||||
|
Batch,
|
||||||
|
RollupStats,
|
||||||
|
ProofRequest,
|
||||||
|
VerificationResult,
|
||||||
|
MerkleProof,
|
||||||
|
TrustedSetup,
|
||||||
|
CeremonyContribution,
|
||||||
|
ZkConfig,
|
||||||
|
ZkError,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SynorZk:
|
||||||
|
"""
|
||||||
|
Synor ZK SDK Client
|
||||||
|
|
||||||
|
Provides zero-knowledge proof generation and verification for ZK-Rollups.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async with SynorZk(ZkConfig(api_key="your-api-key")) as zk:
|
||||||
|
# Generate a proof
|
||||||
|
proof = await zk.proofs.generate(ProofRequest(
|
||||||
|
circuit_type=CircuitType.TRANSFER,
|
||||||
|
public_inputs=[...],
|
||||||
|
private_inputs=[...],
|
||||||
|
))
|
||||||
|
|
||||||
|
# Verify the proof
|
||||||
|
result = await zk.proofs.verify(proof)
|
||||||
|
print(f"Valid: {result.valid}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, config: ZkConfig):
|
||||||
|
self.config = config
|
||||||
|
self._client: Optional[httpx.AsyncClient] = None
|
||||||
|
self._closed = False
|
||||||
|
|
||||||
|
self.proofs = ProofsClient(self)
|
||||||
|
self.circuits = CircuitsClient(self)
|
||||||
|
self.rollup = RollupClient(self)
|
||||||
|
self.state = StateClient(self)
|
||||||
|
self.ceremony = CeremonyClient(self)
|
||||||
|
|
||||||
|
async def __aenter__(self) -> "SynorZk":
|
||||||
|
self._client = httpx.AsyncClient(timeout=self.config.timeout)
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(self, *args) -> None:
|
||||||
|
await self.close()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def default_proof_system(self) -> ProofSystem:
|
||||||
|
"""Get the default proof system"""
|
||||||
|
return self.config.default_proof_system
|
||||||
|
|
||||||
|
async def health_check(self) -> bool:
|
||||||
|
"""Health check"""
|
||||||
|
try:
|
||||||
|
result = await self._get("/health")
|
||||||
|
return result.get("status") == "healthy"
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def get_info(self) -> Dict[str, Any]:
|
||||||
|
"""Get service info"""
|
||||||
|
return await self._get("/info")
|
||||||
|
|
||||||
|
async def close(self) -> None:
|
||||||
|
"""Close the client"""
|
||||||
|
self._closed = True
|
||||||
|
if self._client:
|
||||||
|
await self._client.aclose()
|
||||||
|
self._client = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_closed(self) -> bool:
|
||||||
|
"""Check if client is closed"""
|
||||||
|
return self._closed
|
||||||
|
|
||||||
|
async def _get(self, path: str) -> Dict[str, Any]:
|
||||||
|
"""Internal GET request"""
|
||||||
|
return await self._request("GET", path)
|
||||||
|
|
||||||
|
async def _post(self, path: str, body: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
||||||
|
"""Internal POST request"""
|
||||||
|
return await self._request("POST", path, body)
|
||||||
|
|
||||||
|
async def _delete(self, path: str) -> Dict[str, Any]:
|
||||||
|
"""Internal DELETE request"""
|
||||||
|
return await self._request("DELETE", path)
|
||||||
|
|
||||||
|
async def _request(
|
||||||
|
self,
|
||||||
|
method: str,
|
||||||
|
path: str,
|
||||||
|
body: Optional[Dict[str, Any]] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Internal HTTP request with retries"""
|
||||||
|
if self._closed:
|
||||||
|
raise ZkError("Client has been closed", code="CLIENT_CLOSED")
|
||||||
|
|
||||||
|
if not self._client:
|
||||||
|
self._client = httpx.AsyncClient(timeout=self.config.timeout)
|
||||||
|
|
||||||
|
url = f"{self.config.endpoint}{path}"
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"Bearer {self.config.api_key}",
|
||||||
|
"X-SDK-Version": "python/0.1.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
last_error: Optional[Exception] = None
|
||||||
|
|
||||||
|
for attempt in range(self.config.retries + 1):
|
||||||
|
try:
|
||||||
|
if method == "GET":
|
||||||
|
response = await self._client.get(url, headers=headers)
|
||||||
|
elif method == "POST":
|
||||||
|
response = await self._client.post(url, headers=headers, json=body)
|
||||||
|
elif method == "DELETE":
|
||||||
|
response = await self._client.delete(url, headers=headers)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown method: {method}")
|
||||||
|
|
||||||
|
if response.status_code >= 400:
|
||||||
|
error = response.json() if response.content else {}
|
||||||
|
raise ZkError(
|
||||||
|
error.get("message", f"HTTP {response.status_code}"),
|
||||||
|
code=error.get("code"),
|
||||||
|
status=response.status_code,
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
except ZkError:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
last_error = e
|
||||||
|
if attempt < self.config.retries:
|
||||||
|
await asyncio.sleep(0.1 * (2 ** attempt))
|
||||||
|
|
||||||
|
raise ZkError(
|
||||||
|
str(last_error) if last_error else "Request failed",
|
||||||
|
code="NETWORK_ERROR",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ProofsClient:
|
||||||
|
"""Proofs sub-client"""
|
||||||
|
|
||||||
|
def __init__(self, zk: SynorZk):
|
||||||
|
self._zk = zk
|
||||||
|
|
||||||
|
async def generate(self, request: ProofRequest) -> Proof:
|
||||||
|
"""Generate a zero-knowledge proof"""
|
||||||
|
body = request.to_dict()
|
||||||
|
if not body.get("system"):
|
||||||
|
body["system"] = self._zk.default_proof_system.value
|
||||||
|
result = await self._zk._post("/proofs/generate", body)
|
||||||
|
return Proof.from_dict(result)
|
||||||
|
|
||||||
|
async def verify(self, proof: Proof) -> VerificationResult:
|
||||||
|
"""Verify a proof"""
|
||||||
|
result = await self._zk._post("/proofs/verify", {
|
||||||
|
"proof_id": proof.id,
|
||||||
|
"data": proof.data,
|
||||||
|
"public_inputs": proof.public_inputs,
|
||||||
|
"system": proof.system.value,
|
||||||
|
"circuit_type": proof.circuit_type.value,
|
||||||
|
})
|
||||||
|
return VerificationResult.from_dict(result)
|
||||||
|
|
||||||
|
async def get(self, proof_id: str) -> Proof:
|
||||||
|
"""Get a proof by ID"""
|
||||||
|
result = await self._zk._get(f"/proofs/{proof_id}")
|
||||||
|
return Proof.from_dict(result)
|
||||||
|
|
||||||
|
async def list(
|
||||||
|
self,
|
||||||
|
limit: Optional[int] = None,
|
||||||
|
offset: Optional[int] = None,
|
||||||
|
) -> List[Proof]:
|
||||||
|
"""List recent proofs"""
|
||||||
|
params = []
|
||||||
|
if limit:
|
||||||
|
params.append(f"limit={limit}")
|
||||||
|
if offset:
|
||||||
|
params.append(f"offset={offset}")
|
||||||
|
query = f"?{'&'.join(params)}" if params else ""
|
||||||
|
result = await self._zk._get(f"/proofs{query}")
|
||||||
|
return [Proof.from_dict(p) for p in result.get("proofs", [])]
|
||||||
|
|
||||||
|
async def serialize(self, proof: Proof) -> bytes:
|
||||||
|
"""Serialize a proof to bytes"""
|
||||||
|
result = await self._zk._post("/proofs/serialize", {"proof_id": proof.id})
|
||||||
|
return base64.b64decode(result["data"])
|
||||||
|
|
||||||
|
async def deserialize(self, data: bytes, system: ProofSystem) -> Proof:
|
||||||
|
"""Deserialize bytes to a proof"""
|
||||||
|
result = await self._zk._post("/proofs/deserialize", {
|
||||||
|
"data": base64.b64encode(data).decode(),
|
||||||
|
"system": system.value,
|
||||||
|
})
|
||||||
|
return Proof.from_dict(result)
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitsClient:
|
||||||
|
"""Circuits sub-client"""
|
||||||
|
|
||||||
|
def __init__(self, zk: SynorZk):
|
||||||
|
self._zk = zk
|
||||||
|
|
||||||
|
async def get_verification_key(
|
||||||
|
self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
system: Optional[ProofSystem] = None,
|
||||||
|
) -> VerificationKey:
|
||||||
|
"""Get verification key for a circuit"""
|
||||||
|
sys = system or self._zk.default_proof_system
|
||||||
|
result = await self._zk._get(f"/circuits/{circuit_type.value}/vk?system={sys.value}")
|
||||||
|
return VerificationKey.from_dict(result)
|
||||||
|
|
||||||
|
async def get_proving_key(
|
||||||
|
self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
system: Optional[ProofSystem] = None,
|
||||||
|
) -> ProvingKey:
|
||||||
|
"""Get proving key for a circuit"""
|
||||||
|
sys = system or self._zk.default_proof_system
|
||||||
|
result = await self._zk._get(f"/circuits/{circuit_type.value}/pk?system={sys.value}")
|
||||||
|
return ProvingKey.from_dict(result)
|
||||||
|
|
||||||
|
async def list(self) -> List[CircuitConfig]:
|
||||||
|
"""List available circuits"""
|
||||||
|
result = await self._zk._get("/circuits")
|
||||||
|
return [CircuitConfig.from_dict(c) for c in result.get("circuits", [])]
|
||||||
|
|
||||||
|
async def get_config(self, circuit_type: CircuitType) -> CircuitConfig:
|
||||||
|
"""Get circuit configuration"""
|
||||||
|
result = await self._zk._get(f"/circuits/{circuit_type.value}/config")
|
||||||
|
return CircuitConfig.from_dict(result)
|
||||||
|
|
||||||
|
async def compile(self, config: CircuitConfig) -> str:
|
||||||
|
"""Compile a custom circuit, returns circuit ID"""
|
||||||
|
result = await self._zk._post("/circuits/compile", {
|
||||||
|
"type": config.type.value,
|
||||||
|
"max_batch_size": config.max_batch_size,
|
||||||
|
"tree_depth": config.tree_depth,
|
||||||
|
"verify_signatures": config.verify_signatures,
|
||||||
|
"custom_constraints": config.custom_constraints,
|
||||||
|
})
|
||||||
|
return result["circuit_id"]
|
||||||
|
|
||||||
|
|
||||||
|
class RollupClient:
|
||||||
|
"""Rollup sub-client"""
|
||||||
|
|
||||||
|
def __init__(self, zk: SynorZk):
|
||||||
|
self._zk = zk
|
||||||
|
|
||||||
|
async def get_stats(self) -> RollupStats:
|
||||||
|
"""Get rollup statistics"""
|
||||||
|
result = await self._zk._get("/rollup/stats")
|
||||||
|
return RollupStats.from_dict(result)
|
||||||
|
|
||||||
|
async def get_current_batch(self) -> Batch:
|
||||||
|
"""Get current batch"""
|
||||||
|
result = await self._zk._get("/rollup/batch/current")
|
||||||
|
return Batch.from_dict(result)
|
||||||
|
|
||||||
|
async def get_batch(self, batch_number: int) -> Batch:
|
||||||
|
"""Get batch by number"""
|
||||||
|
result = await self._zk._get(f"/rollup/batch/{batch_number}")
|
||||||
|
return Batch.from_dict(result)
|
||||||
|
|
||||||
|
async def submit_transfer(self, transfer: Transfer) -> str:
|
||||||
|
"""Submit a transfer, returns transaction ID"""
|
||||||
|
result = await self._zk._post("/rollup/transfer", transfer.to_dict())
|
||||||
|
return result["tx_id"]
|
||||||
|
|
||||||
|
async def submit_deposit(self, deposit: Deposit) -> str:
|
||||||
|
"""Submit a deposit, returns transaction ID"""
|
||||||
|
result = await self._zk._post("/rollup/deposit", deposit.to_dict())
|
||||||
|
return result["tx_id"]
|
||||||
|
|
||||||
|
async def submit_withdrawal(self, withdrawal: Withdrawal) -> str:
|
||||||
|
"""Submit a withdrawal, returns transaction ID"""
|
||||||
|
result = await self._zk._post("/rollup/withdraw", withdrawal.to_dict())
|
||||||
|
return result["tx_id"]
|
||||||
|
|
||||||
|
async def finalize_batch(self) -> Batch:
|
||||||
|
"""Finalize current batch (generates proof and submits to L1)"""
|
||||||
|
result = await self._zk._post("/rollup/batch/finalize", {})
|
||||||
|
return Batch.from_dict(result)
|
||||||
|
|
||||||
|
async def get_pending_transactions(self) -> List[Transfer]:
|
||||||
|
"""Get pending transactions"""
|
||||||
|
result = await self._zk._get("/rollup/pending")
|
||||||
|
return [Transfer.from_dict(t) for t in result.get("transactions", [])]
|
||||||
|
|
||||||
|
|
||||||
|
class StateClient:
|
||||||
|
"""State sub-client"""
|
||||||
|
|
||||||
|
def __init__(self, zk: SynorZk):
|
||||||
|
self._zk = zk
|
||||||
|
|
||||||
|
async def get_root(self) -> str:
|
||||||
|
"""Get current state root"""
|
||||||
|
result = await self._zk._get("/state/root")
|
||||||
|
return result["root"]
|
||||||
|
|
||||||
|
async def get_account(self, address: str) -> AccountState:
|
||||||
|
"""Get account state"""
|
||||||
|
result = await self._zk._get(f"/state/account/{address}")
|
||||||
|
return AccountState.from_dict(result)
|
||||||
|
|
||||||
|
async def get_merkle_proof(self, address: str) -> MerkleProof:
|
||||||
|
"""Get merkle proof for account inclusion"""
|
||||||
|
result = await self._zk._get(f"/state/proof/{address}")
|
||||||
|
return MerkleProof.from_dict(result)
|
||||||
|
|
||||||
|
async def verify_merkle_proof(self, proof: MerkleProof) -> bool:
|
||||||
|
"""Verify merkle proof"""
|
||||||
|
result = await self._zk._post("/state/proof/verify", proof.to_dict())
|
||||||
|
return result["valid"]
|
||||||
|
|
||||||
|
async def get_state_at_batch(self, batch_number: int) -> Dict[str, Any]:
|
||||||
|
"""Get state at specific batch"""
|
||||||
|
return await self._zk._get(f"/state/batch/{batch_number}")
|
||||||
|
|
||||||
|
|
||||||
|
class CeremonyClient:
|
||||||
|
"""Ceremony sub-client (trusted setup)"""
|
||||||
|
|
||||||
|
def __init__(self, zk: SynorZk):
|
||||||
|
self._zk = zk
|
||||||
|
|
||||||
|
async def get_status(
|
||||||
|
self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
system: Optional[ProofSystem] = None,
|
||||||
|
) -> TrustedSetup:
|
||||||
|
"""Get ceremony status"""
|
||||||
|
sys = system or self._zk.default_proof_system
|
||||||
|
result = await self._zk._get(f"/ceremony/{circuit_type.value}?system={sys.value}")
|
||||||
|
return TrustedSetup.from_dict(result)
|
||||||
|
|
||||||
|
async def contribute(
|
||||||
|
self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
entropy: bytes,
|
||||||
|
system: Optional[ProofSystem] = None,
|
||||||
|
) -> CeremonyContribution:
|
||||||
|
"""Contribute to ceremony"""
|
||||||
|
sys = system or self._zk.default_proof_system
|
||||||
|
result = await self._zk._post("/ceremony/contribute", {
|
||||||
|
"circuit_type": circuit_type.value,
|
||||||
|
"entropy": base64.b64encode(entropy).decode(),
|
||||||
|
"system": sys.value,
|
||||||
|
})
|
||||||
|
return CeremonyContribution.from_dict(result)
|
||||||
|
|
||||||
|
async def verify_contribution(
|
||||||
|
self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
contribution_hash: str,
|
||||||
|
) -> bool:
|
||||||
|
"""Verify a contribution"""
|
||||||
|
result = await self._zk._post("/ceremony/verify", {
|
||||||
|
"circuit_type": circuit_type.value,
|
||||||
|
"contribution_hash": contribution_hash,
|
||||||
|
})
|
||||||
|
return result["valid"]
|
||||||
|
|
||||||
|
async def list_contributions(
|
||||||
|
self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
) -> List[CeremonyContribution]:
|
||||||
|
"""List contributions"""
|
||||||
|
result = await self._zk._get(f"/ceremony/{circuit_type.value}/contributions")
|
||||||
|
return [CeremonyContribution.from_dict(c) for c in result.get("contributions", [])]
|
||||||
464
sdk/python/src/synor_zk/types.py
Normal file
464
sdk/python/src/synor_zk/types.py
Normal file
|
|
@ -0,0 +1,464 @@
|
||||||
|
"""
|
||||||
|
Synor ZK SDK Types for Python
|
||||||
|
|
||||||
|
Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Optional, List, Dict, Any
|
||||||
|
|
||||||
|
|
||||||
|
class ProofSystem(str, Enum):
|
||||||
|
"""Proof system backends"""
|
||||||
|
GROTH16 = "groth16" # Smallest proofs (~192 bytes), fastest verification
|
||||||
|
PLONK = "plonk" # Universal trusted setup, medium proofs (~512 bytes)
|
||||||
|
STARK = "stark" # No trusted setup, largest proofs (~50KB)
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitType(str, Enum):
|
||||||
|
"""Circuit types for different operations"""
|
||||||
|
TRANSFER = "transfer" # Single transfer between accounts
|
||||||
|
BATCH = "batch" # Batch of multiple transfers
|
||||||
|
DEPOSIT = "deposit" # Deposit from L1 to L2
|
||||||
|
WITHDRAW = "withdraw" # Withdrawal from L2 to L1
|
||||||
|
|
||||||
|
|
||||||
|
class RollupState(str, Enum):
|
||||||
|
"""Rollup state"""
|
||||||
|
ACTIVE = "active"
|
||||||
|
PAUSED = "paused"
|
||||||
|
FINALIZING = "finalizing"
|
||||||
|
FINALIZED = "finalized"
|
||||||
|
|
||||||
|
|
||||||
|
class ProofStatus(str, Enum):
|
||||||
|
"""Proof status"""
|
||||||
|
GENERATING = "generating"
|
||||||
|
COMPLETED = "completed"
|
||||||
|
FAILED = "failed"
|
||||||
|
VERIFIED = "verified"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Proof:
|
||||||
|
"""Zero-knowledge proof"""
|
||||||
|
id: str
|
||||||
|
system: ProofSystem
|
||||||
|
circuit_type: CircuitType
|
||||||
|
data: str # Base64 encoded
|
||||||
|
public_inputs: List[str]
|
||||||
|
size: int
|
||||||
|
generation_time_ms: int
|
||||||
|
created_at: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "Proof":
|
||||||
|
return cls(
|
||||||
|
id=data["id"],
|
||||||
|
system=ProofSystem(data["system"]),
|
||||||
|
circuit_type=CircuitType(data["circuit_type"]),
|
||||||
|
data=data["data"],
|
||||||
|
public_inputs=data.get("public_inputs", []),
|
||||||
|
size=data.get("size", 0),
|
||||||
|
generation_time_ms=data.get("generation_time_ms", 0),
|
||||||
|
created_at=data.get("created_at", 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VerificationKey:
|
||||||
|
"""Verification key for a circuit"""
|
||||||
|
circuit_id: str
|
||||||
|
circuit_type: CircuitType
|
||||||
|
system: ProofSystem
|
||||||
|
data: str # Base64 encoded
|
||||||
|
size: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "VerificationKey":
|
||||||
|
return cls(
|
||||||
|
circuit_id=data["circuit_id"],
|
||||||
|
circuit_type=CircuitType(data["circuit_type"]),
|
||||||
|
system=ProofSystem(data["system"]),
|
||||||
|
data=data["data"],
|
||||||
|
size=data.get("size", 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProvingKey:
|
||||||
|
"""Proving key for generating proofs"""
|
||||||
|
circuit_id: str
|
||||||
|
circuit_type: CircuitType
|
||||||
|
system: ProofSystem
|
||||||
|
data: str # Base64 encoded
|
||||||
|
size: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "ProvingKey":
|
||||||
|
return cls(
|
||||||
|
circuit_id=data["circuit_id"],
|
||||||
|
circuit_type=CircuitType(data["circuit_type"]),
|
||||||
|
system=ProofSystem(data["system"]),
|
||||||
|
data=data["data"],
|
||||||
|
size=data.get("size", 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CircuitConfig:
|
||||||
|
"""Circuit configuration"""
|
||||||
|
type: CircuitType
|
||||||
|
max_batch_size: Optional[int] = None
|
||||||
|
tree_depth: Optional[int] = None
|
||||||
|
verify_signatures: Optional[bool] = None
|
||||||
|
custom_constraints: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "CircuitConfig":
|
||||||
|
return cls(
|
||||||
|
type=CircuitType(data["type"]),
|
||||||
|
max_batch_size=data.get("max_batch_size"),
|
||||||
|
tree_depth=data.get("tree_depth"),
|
||||||
|
verify_signatures=data.get("verify_signatures"),
|
||||||
|
custom_constraints=data.get("custom_constraints"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AccountState:
|
||||||
|
"""Account state in the rollup"""
|
||||||
|
address: str
|
||||||
|
balance: str
|
||||||
|
nonce: int
|
||||||
|
pubkey_hash: str
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "AccountState":
|
||||||
|
return cls(
|
||||||
|
address=data["address"],
|
||||||
|
balance=data["balance"],
|
||||||
|
nonce=data.get("nonce", 0),
|
||||||
|
pubkey_hash=data.get("pubkey_hash", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Transfer:
|
||||||
|
"""Transfer operation"""
|
||||||
|
from_addr: str
|
||||||
|
to: str
|
||||||
|
amount: str
|
||||||
|
fee: str
|
||||||
|
nonce: int
|
||||||
|
signature: Optional[str] = None
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
result = {
|
||||||
|
"from": self.from_addr,
|
||||||
|
"to": self.to,
|
||||||
|
"amount": self.amount,
|
||||||
|
"fee": self.fee,
|
||||||
|
"nonce": self.nonce,
|
||||||
|
}
|
||||||
|
if self.signature:
|
||||||
|
result["signature"] = self.signature
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "Transfer":
|
||||||
|
return cls(
|
||||||
|
from_addr=data["from"],
|
||||||
|
to=data["to"],
|
||||||
|
amount=data["amount"],
|
||||||
|
fee=data["fee"],
|
||||||
|
nonce=data.get("nonce", 0),
|
||||||
|
signature=data.get("signature"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Deposit:
|
||||||
|
"""Deposit operation (L1 -> L2)"""
|
||||||
|
l1_tx_hash: str
|
||||||
|
recipient: str
|
||||||
|
amount: str
|
||||||
|
token: Optional[str] = None
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
result = {
|
||||||
|
"l1_tx_hash": self.l1_tx_hash,
|
||||||
|
"recipient": self.recipient,
|
||||||
|
"amount": self.amount,
|
||||||
|
}
|
||||||
|
if self.token:
|
||||||
|
result["token"] = self.token
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "Deposit":
|
||||||
|
return cls(
|
||||||
|
l1_tx_hash=data["l1_tx_hash"],
|
||||||
|
recipient=data["recipient"],
|
||||||
|
amount=data["amount"],
|
||||||
|
token=data.get("token"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Withdrawal:
|
||||||
|
"""Withdrawal operation (L2 -> L1)"""
|
||||||
|
sender: str
|
||||||
|
recipient: str
|
||||||
|
amount: str
|
||||||
|
token: Optional[str] = None
|
||||||
|
nonce: int = 0
|
||||||
|
signature: Optional[str] = None
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
result = {
|
||||||
|
"sender": self.sender,
|
||||||
|
"recipient": self.recipient,
|
||||||
|
"amount": self.amount,
|
||||||
|
"nonce": self.nonce,
|
||||||
|
}
|
||||||
|
if self.token:
|
||||||
|
result["token"] = self.token
|
||||||
|
if self.signature:
|
||||||
|
result["signature"] = self.signature
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "Withdrawal":
|
||||||
|
return cls(
|
||||||
|
sender=data["sender"],
|
||||||
|
recipient=data["recipient"],
|
||||||
|
amount=data["amount"],
|
||||||
|
token=data.get("token"),
|
||||||
|
nonce=data.get("nonce", 0),
|
||||||
|
signature=data.get("signature"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Batch:
|
||||||
|
"""Rollup batch"""
|
||||||
|
batch_number: int
|
||||||
|
prev_state_root: str
|
||||||
|
new_state_root: str
|
||||||
|
transfers: List[Transfer]
|
||||||
|
deposits: List[Deposit]
|
||||||
|
withdrawals: List[Withdrawal]
|
||||||
|
proof: Optional[Proof] = None
|
||||||
|
timestamp: int = 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "Batch":
|
||||||
|
return cls(
|
||||||
|
batch_number=data["batch_number"],
|
||||||
|
prev_state_root=data["prev_state_root"],
|
||||||
|
new_state_root=data["new_state_root"],
|
||||||
|
transfers=[Transfer.from_dict(t) for t in data.get("transfers", [])],
|
||||||
|
deposits=[Deposit.from_dict(d) for d in data.get("deposits", [])],
|
||||||
|
withdrawals=[Withdrawal.from_dict(w) for w in data.get("withdrawals", [])],
|
||||||
|
proof=Proof.from_dict(data["proof"]) if data.get("proof") else None,
|
||||||
|
timestamp=data.get("timestamp", 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RollupStats:
|
||||||
|
"""Rollup statistics"""
|
||||||
|
current_batch: int
|
||||||
|
total_transactions: int
|
||||||
|
total_proofs: int
|
||||||
|
avg_proof_time_ms: int
|
||||||
|
state_root: str
|
||||||
|
account_count: int
|
||||||
|
tvl: str
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "RollupStats":
|
||||||
|
return cls(
|
||||||
|
current_batch=data["current_batch"],
|
||||||
|
total_transactions=data.get("total_transactions", 0),
|
||||||
|
total_proofs=data.get("total_proofs", 0),
|
||||||
|
avg_proof_time_ms=data.get("avg_proof_time_ms", 0),
|
||||||
|
state_root=data["state_root"],
|
||||||
|
account_count=data.get("account_count", 0),
|
||||||
|
tvl=data.get("tvl", "0"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProofRequest:
|
||||||
|
"""Proof generation request"""
|
||||||
|
circuit_type: CircuitType
|
||||||
|
public_inputs: List[str]
|
||||||
|
private_inputs: List[str]
|
||||||
|
system: Optional[ProofSystem] = None
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
result = {
|
||||||
|
"circuit_type": self.circuit_type.value,
|
||||||
|
"public_inputs": self.public_inputs,
|
||||||
|
"private_inputs": self.private_inputs,
|
||||||
|
}
|
||||||
|
if self.system:
|
||||||
|
result["system"] = self.system.value
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VerificationResult:
|
||||||
|
"""Proof verification result"""
|
||||||
|
valid: bool
|
||||||
|
verification_time_ms: int
|
||||||
|
error: Optional[str] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "VerificationResult":
|
||||||
|
return cls(
|
||||||
|
valid=data["valid"],
|
||||||
|
verification_time_ms=data.get("verification_time_ms", 0),
|
||||||
|
error=data.get("error"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MerkleProof:
|
||||||
|
"""Merkle proof for state inclusion"""
|
||||||
|
leaf: str
|
||||||
|
path: List[str]
|
||||||
|
indices: List[int]
|
||||||
|
root: str
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"leaf": self.leaf,
|
||||||
|
"path": self.path,
|
||||||
|
"indices": self.indices,
|
||||||
|
"root": self.root,
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "MerkleProof":
|
||||||
|
return cls(
|
||||||
|
leaf=data["leaf"],
|
||||||
|
path=data["path"],
|
||||||
|
indices=data["indices"],
|
||||||
|
root=data["root"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CeremonyContribution:
|
||||||
|
"""Trusted setup ceremony contribution"""
|
||||||
|
contributor_id: str
|
||||||
|
hash: str
|
||||||
|
timestamp: int
|
||||||
|
verified: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "CeremonyContribution":
|
||||||
|
return cls(
|
||||||
|
contributor_id=data["contributor_id"],
|
||||||
|
hash=data["hash"],
|
||||||
|
timestamp=data.get("timestamp", 0),
|
||||||
|
verified=data.get("verified", False),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TrustedSetup:
|
||||||
|
"""Trusted setup ceremony"""
|
||||||
|
id: str
|
||||||
|
circuit_type: CircuitType
|
||||||
|
system: ProofSystem
|
||||||
|
contribution_count: int
|
||||||
|
latest_hash: str
|
||||||
|
complete: bool
|
||||||
|
contributions: List[CeremonyContribution]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]) -> "TrustedSetup":
|
||||||
|
return cls(
|
||||||
|
id=data["id"],
|
||||||
|
circuit_type=CircuitType(data["circuit_type"]),
|
||||||
|
system=ProofSystem(data["system"]),
|
||||||
|
contribution_count=data.get("contribution_count", 0),
|
||||||
|
latest_hash=data.get("latest_hash", ""),
|
||||||
|
complete=data.get("complete", False),
|
||||||
|
contributions=[
|
||||||
|
CeremonyContribution.from_dict(c)
|
||||||
|
for c in data.get("contributions", [])
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ZkConfig:
|
||||||
|
"""ZK SDK configuration"""
|
||||||
|
api_key: str
|
||||||
|
endpoint: str = "https://zk.synor.io/v1"
|
||||||
|
ws_endpoint: str = "wss://zk.synor.io/v1/ws"
|
||||||
|
timeout: int = 60 # Seconds (ZK proofs take longer)
|
||||||
|
retries: int = 3
|
||||||
|
default_proof_system: ProofSystem = ProofSystem.GROTH16
|
||||||
|
debug: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class ZkError(Exception):
|
||||||
|
"""ZK SDK error"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
message: str,
|
||||||
|
code: Optional[str] = None,
|
||||||
|
status: Optional[int] = None,
|
||||||
|
):
|
||||||
|
super().__init__(message)
|
||||||
|
self.code = code
|
||||||
|
self.status = status
|
||||||
|
|
||||||
|
|
||||||
|
# Default configuration
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
"endpoint": "https://zk.synor.io/v1",
|
||||||
|
"ws_endpoint": "wss://zk.synor.io/v1/ws",
|
||||||
|
"timeout": 60,
|
||||||
|
"retries": 3,
|
||||||
|
"default_proof_system": ProofSystem.GROTH16,
|
||||||
|
"debug": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
MAX_BATCH_SIZE = 1000
|
||||||
|
STATE_TREE_DEPTH = 32
|
||||||
|
PROOF_EXPIRY_BLOCKS = 100
|
||||||
|
|
||||||
|
# Proof system characteristics
|
||||||
|
PROOF_SYSTEM_INFO = {
|
||||||
|
ProofSystem.GROTH16: {
|
||||||
|
"name": "Groth16",
|
||||||
|
"proof_size": 192,
|
||||||
|
"verification_time_ms": 10,
|
||||||
|
"trusted_setup": True,
|
||||||
|
"universal": False,
|
||||||
|
},
|
||||||
|
ProofSystem.PLONK: {
|
||||||
|
"name": "PLONK",
|
||||||
|
"proof_size": 512,
|
||||||
|
"verification_time_ms": 15,
|
||||||
|
"trusted_setup": True,
|
||||||
|
"universal": True,
|
||||||
|
},
|
||||||
|
ProofSystem.STARK: {
|
||||||
|
"name": "STARK",
|
||||||
|
"proof_size": 50000,
|
||||||
|
"verification_time_ms": 30,
|
||||||
|
"trusted_setup": False,
|
||||||
|
"universal": True,
|
||||||
|
},
|
||||||
|
}
|
||||||
770
sdk/ruby/lib/synor/zk.rb
Normal file
770
sdk/ruby/lib/synor/zk.rb
Normal file
|
|
@ -0,0 +1,770 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'net/http'
|
||||||
|
require 'uri'
|
||||||
|
require 'json'
|
||||||
|
require 'base64'
|
||||||
|
|
||||||
|
module Synor
|
||||||
|
# ZK SDK for Ruby
|
||||||
|
#
|
||||||
|
# Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
module Zk
|
||||||
|
VERSION = '0.1.0'
|
||||||
|
|
||||||
|
# Proof system backends
|
||||||
|
module ProofSystem
|
||||||
|
GROTH16 = 'groth16' # Smallest proofs (~192 bytes), fastest verification
|
||||||
|
PLONK = 'plonk' # Universal trusted setup, medium proofs (~512 bytes)
|
||||||
|
STARK = 'stark' # No trusted setup, largest proofs (~50KB)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Circuit types for different operations
|
||||||
|
module CircuitType
|
||||||
|
TRANSFER = 'transfer' # Single transfer between accounts
|
||||||
|
BATCH = 'batch' # Batch of multiple transfers
|
||||||
|
DEPOSIT = 'deposit' # Deposit from L1 to L2
|
||||||
|
WITHDRAW = 'withdraw' # Withdrawal from L2 to L1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rollup state
|
||||||
|
module RollupState
|
||||||
|
ACTIVE = 'active'
|
||||||
|
PAUSED = 'paused'
|
||||||
|
FINALIZING = 'finalizing'
|
||||||
|
FINALIZED = 'finalized'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Proof status
|
||||||
|
module ProofStatus
|
||||||
|
GENERATING = 'generating'
|
||||||
|
COMPLETED = 'completed'
|
||||||
|
FAILED = 'failed'
|
||||||
|
VERIFIED = 'verified'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Zero-knowledge proof
|
||||||
|
class Proof
|
||||||
|
attr_reader :id, :system, :circuit_type, :data, :public_inputs,
|
||||||
|
:size, :generation_time_ms, :created_at
|
||||||
|
|
||||||
|
def initialize(id:, system:, circuit_type:, data:, public_inputs:,
|
||||||
|
size:, generation_time_ms:, created_at:)
|
||||||
|
@id = id
|
||||||
|
@system = system
|
||||||
|
@circuit_type = circuit_type
|
||||||
|
@data = data
|
||||||
|
@public_inputs = public_inputs
|
||||||
|
@size = size
|
||||||
|
@generation_time_ms = generation_time_ms
|
||||||
|
@created_at = created_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
Proof.new(
|
||||||
|
id: json['id'],
|
||||||
|
system: json['system'],
|
||||||
|
circuit_type: json['circuit_type'],
|
||||||
|
data: json['data'],
|
||||||
|
public_inputs: json['public_inputs'] || [],
|
||||||
|
size: json['size'] || 0,
|
||||||
|
generation_time_ms: json['generation_time_ms'] || 0,
|
||||||
|
created_at: json['created_at'] || 0
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
{
|
||||||
|
'id' => @id,
|
||||||
|
'system' => @system,
|
||||||
|
'circuit_type' => @circuit_type,
|
||||||
|
'data' => @data,
|
||||||
|
'public_inputs' => @public_inputs,
|
||||||
|
'size' => @size,
|
||||||
|
'generation_time_ms' => @generation_time_ms,
|
||||||
|
'created_at' => @created_at
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verification key
|
||||||
|
class VerificationKey
|
||||||
|
attr_reader :circuit_id, :circuit_type, :system, :data, :size
|
||||||
|
|
||||||
|
def initialize(circuit_id:, circuit_type:, system:, data:, size:)
|
||||||
|
@circuit_id = circuit_id
|
||||||
|
@circuit_type = circuit_type
|
||||||
|
@system = system
|
||||||
|
@data = data
|
||||||
|
@size = size
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
VerificationKey.new(
|
||||||
|
circuit_id: json['circuit_id'],
|
||||||
|
circuit_type: json['circuit_type'],
|
||||||
|
system: json['system'],
|
||||||
|
data: json['data'],
|
||||||
|
size: json['size'] || 0
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Proving key
|
||||||
|
class ProvingKey
|
||||||
|
attr_reader :circuit_id, :circuit_type, :system, :data, :size
|
||||||
|
|
||||||
|
def initialize(circuit_id:, circuit_type:, system:, data:, size:)
|
||||||
|
@circuit_id = circuit_id
|
||||||
|
@circuit_type = circuit_type
|
||||||
|
@system = system
|
||||||
|
@data = data
|
||||||
|
@size = size
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
ProvingKey.new(
|
||||||
|
circuit_id: json['circuit_id'],
|
||||||
|
circuit_type: json['circuit_type'],
|
||||||
|
system: json['system'],
|
||||||
|
data: json['data'],
|
||||||
|
size: json['size'] || 0
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Circuit configuration
|
||||||
|
class CircuitConfig
|
||||||
|
attr_reader :type, :max_batch_size, :tree_depth, :verify_signatures, :custom_constraints
|
||||||
|
|
||||||
|
def initialize(type:, max_batch_size: nil, tree_depth: nil,
|
||||||
|
verify_signatures: nil, custom_constraints: nil)
|
||||||
|
@type = type
|
||||||
|
@max_batch_size = max_batch_size
|
||||||
|
@tree_depth = tree_depth
|
||||||
|
@verify_signatures = verify_signatures
|
||||||
|
@custom_constraints = custom_constraints
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
CircuitConfig.new(
|
||||||
|
type: json['type'],
|
||||||
|
max_batch_size: json['max_batch_size'],
|
||||||
|
tree_depth: json['tree_depth'],
|
||||||
|
verify_signatures: json['verify_signatures'],
|
||||||
|
custom_constraints: json['custom_constraints']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
result = { 'type' => @type }
|
||||||
|
result['max_batch_size'] = @max_batch_size if @max_batch_size
|
||||||
|
result['tree_depth'] = @tree_depth if @tree_depth
|
||||||
|
result['verify_signatures'] = @verify_signatures unless @verify_signatures.nil?
|
||||||
|
result['custom_constraints'] = @custom_constraints if @custom_constraints
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Account state
|
||||||
|
class AccountState
|
||||||
|
attr_reader :address, :balance, :nonce, :pubkey_hash
|
||||||
|
|
||||||
|
def initialize(address:, balance:, nonce:, pubkey_hash:)
|
||||||
|
@address = address
|
||||||
|
@balance = balance
|
||||||
|
@nonce = nonce
|
||||||
|
@pubkey_hash = pubkey_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
AccountState.new(
|
||||||
|
address: json['address'],
|
||||||
|
balance: json['balance'],
|
||||||
|
nonce: json['nonce'] || 0,
|
||||||
|
pubkey_hash: json['pubkey_hash'] || ''
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Transfer operation
|
||||||
|
class Transfer
|
||||||
|
attr_reader :from, :to, :amount, :fee, :nonce, :signature
|
||||||
|
|
||||||
|
def initialize(from:, to:, amount:, fee:, nonce:, signature: nil)
|
||||||
|
@from = from
|
||||||
|
@to = to
|
||||||
|
@amount = amount
|
||||||
|
@fee = fee
|
||||||
|
@nonce = nonce
|
||||||
|
@signature = signature
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
Transfer.new(
|
||||||
|
from: json['from'],
|
||||||
|
to: json['to'],
|
||||||
|
amount: json['amount'],
|
||||||
|
fee: json['fee'],
|
||||||
|
nonce: json['nonce'] || 0,
|
||||||
|
signature: json['signature']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
result = { 'from' => @from, 'to' => @to, 'amount' => @amount, 'fee' => @fee, 'nonce' => @nonce }
|
||||||
|
result['signature'] = @signature if @signature
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deposit operation
|
||||||
|
class Deposit
|
||||||
|
attr_reader :l1_tx_hash, :recipient, :amount, :token
|
||||||
|
|
||||||
|
def initialize(l1_tx_hash:, recipient:, amount:, token: nil)
|
||||||
|
@l1_tx_hash = l1_tx_hash
|
||||||
|
@recipient = recipient
|
||||||
|
@amount = amount
|
||||||
|
@token = token
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
result = { 'l1_tx_hash' => @l1_tx_hash, 'recipient' => @recipient, 'amount' => @amount }
|
||||||
|
result['token'] = @token if @token
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Withdrawal operation
|
||||||
|
class Withdrawal
|
||||||
|
attr_reader :sender, :recipient, :amount, :token, :nonce, :signature
|
||||||
|
|
||||||
|
def initialize(sender:, recipient:, amount:, nonce:, token: nil, signature: nil)
|
||||||
|
@sender = sender
|
||||||
|
@recipient = recipient
|
||||||
|
@amount = amount
|
||||||
|
@token = token
|
||||||
|
@nonce = nonce
|
||||||
|
@signature = signature
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
result = { 'sender' => @sender, 'recipient' => @recipient, 'amount' => @amount, 'nonce' => @nonce }
|
||||||
|
result['token'] = @token if @token
|
||||||
|
result['signature'] = @signature if @signature
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rollup batch
|
||||||
|
class Batch
|
||||||
|
attr_reader :batch_number, :prev_state_root, :new_state_root,
|
||||||
|
:transfers, :deposits, :withdrawals, :proof, :timestamp
|
||||||
|
|
||||||
|
def initialize(batch_number:, prev_state_root:, new_state_root:, transfers:,
|
||||||
|
deposits:, withdrawals:, proof: nil, timestamp:)
|
||||||
|
@batch_number = batch_number
|
||||||
|
@prev_state_root = prev_state_root
|
||||||
|
@new_state_root = new_state_root
|
||||||
|
@transfers = transfers
|
||||||
|
@deposits = deposits
|
||||||
|
@withdrawals = withdrawals
|
||||||
|
@proof = proof
|
||||||
|
@timestamp = timestamp
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
Batch.new(
|
||||||
|
batch_number: json['batch_number'],
|
||||||
|
prev_state_root: json['prev_state_root'],
|
||||||
|
new_state_root: json['new_state_root'],
|
||||||
|
transfers: (json['transfers'] || []).map { |t| Transfer.from_json(t) },
|
||||||
|
deposits: json['deposits'] || [],
|
||||||
|
withdrawals: json['withdrawals'] || [],
|
||||||
|
proof: json['proof'] ? Proof.from_json(json['proof']) : nil,
|
||||||
|
timestamp: json['timestamp'] || 0
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rollup statistics
|
||||||
|
class RollupStats
|
||||||
|
attr_reader :current_batch, :total_transactions, :total_proofs,
|
||||||
|
:avg_proof_time_ms, :state_root, :account_count, :tvl
|
||||||
|
|
||||||
|
def initialize(current_batch:, total_transactions:, total_proofs:,
|
||||||
|
avg_proof_time_ms:, state_root:, account_count:, tvl:)
|
||||||
|
@current_batch = current_batch
|
||||||
|
@total_transactions = total_transactions
|
||||||
|
@total_proofs = total_proofs
|
||||||
|
@avg_proof_time_ms = avg_proof_time_ms
|
||||||
|
@state_root = state_root
|
||||||
|
@account_count = account_count
|
||||||
|
@tvl = tvl
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
RollupStats.new(
|
||||||
|
current_batch: json['current_batch'],
|
||||||
|
total_transactions: json['total_transactions'] || 0,
|
||||||
|
total_proofs: json['total_proofs'] || 0,
|
||||||
|
avg_proof_time_ms: json['avg_proof_time_ms'] || 0,
|
||||||
|
state_root: json['state_root'],
|
||||||
|
account_count: json['account_count'] || 0,
|
||||||
|
tvl: json['tvl'] || '0'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Proof request
|
||||||
|
class ProofRequest
|
||||||
|
attr_reader :circuit_type, :public_inputs, :private_inputs, :system
|
||||||
|
|
||||||
|
def initialize(circuit_type:, public_inputs:, private_inputs:, system: nil)
|
||||||
|
@circuit_type = circuit_type
|
||||||
|
@public_inputs = public_inputs
|
||||||
|
@private_inputs = private_inputs
|
||||||
|
@system = system
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
result = {
|
||||||
|
'circuit_type' => @circuit_type,
|
||||||
|
'public_inputs' => @public_inputs,
|
||||||
|
'private_inputs' => @private_inputs
|
||||||
|
}
|
||||||
|
result['system'] = @system if @system
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verification result
|
||||||
|
class VerificationResult
|
||||||
|
attr_reader :valid, :verification_time_ms, :error
|
||||||
|
|
||||||
|
def initialize(valid:, verification_time_ms:, error: nil)
|
||||||
|
@valid = valid
|
||||||
|
@verification_time_ms = verification_time_ms
|
||||||
|
@error = error
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
VerificationResult.new(
|
||||||
|
valid: json['valid'],
|
||||||
|
verification_time_ms: json['verification_time_ms'] || 0,
|
||||||
|
error: json['error']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Merkle proof
|
||||||
|
class MerkleProof
|
||||||
|
attr_reader :leaf, :path, :indices, :root
|
||||||
|
|
||||||
|
def initialize(leaf:, path:, indices:, root:)
|
||||||
|
@leaf = leaf
|
||||||
|
@path = path
|
||||||
|
@indices = indices
|
||||||
|
@root = root
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
MerkleProof.new(
|
||||||
|
leaf: json['leaf'],
|
||||||
|
path: json['path'],
|
||||||
|
indices: json['indices'],
|
||||||
|
root: json['root']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
{ 'leaf' => @leaf, 'path' => @path, 'indices' => @indices, 'root' => @root }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Ceremony contribution
|
||||||
|
class CeremonyContribution
|
||||||
|
attr_reader :contributor_id, :hash, :timestamp, :verified
|
||||||
|
|
||||||
|
def initialize(contributor_id:, hash:, timestamp:, verified:)
|
||||||
|
@contributor_id = contributor_id
|
||||||
|
@hash = hash
|
||||||
|
@timestamp = timestamp
|
||||||
|
@verified = verified
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
CeremonyContribution.new(
|
||||||
|
contributor_id: json['contributor_id'],
|
||||||
|
hash: json['hash'],
|
||||||
|
timestamp: json['timestamp'] || 0,
|
||||||
|
verified: json['verified'] || false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Trusted setup ceremony
|
||||||
|
class TrustedSetup
|
||||||
|
attr_reader :id, :circuit_type, :system, :contribution_count,
|
||||||
|
:latest_hash, :complete, :contributions
|
||||||
|
|
||||||
|
def initialize(id:, circuit_type:, system:, contribution_count:,
|
||||||
|
latest_hash:, complete:, contributions:)
|
||||||
|
@id = id
|
||||||
|
@circuit_type = circuit_type
|
||||||
|
@system = system
|
||||||
|
@contribution_count = contribution_count
|
||||||
|
@latest_hash = latest_hash
|
||||||
|
@complete = complete
|
||||||
|
@contributions = contributions
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(json)
|
||||||
|
TrustedSetup.new(
|
||||||
|
id: json['id'],
|
||||||
|
circuit_type: json['circuit_type'],
|
||||||
|
system: json['system'],
|
||||||
|
contribution_count: json['contribution_count'] || 0,
|
||||||
|
latest_hash: json['latest_hash'] || '',
|
||||||
|
complete: json['complete'] || false,
|
||||||
|
contributions: (json['contributions'] || []).map { |c| CeremonyContribution.from_json(c) }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ZK SDK configuration
|
||||||
|
class Config
|
||||||
|
attr_accessor :api_key, :endpoint, :ws_endpoint, :timeout, :retries,
|
||||||
|
:default_proof_system, :debug
|
||||||
|
|
||||||
|
def initialize(
|
||||||
|
api_key:,
|
||||||
|
endpoint: 'https://zk.synor.io/v1',
|
||||||
|
ws_endpoint: 'wss://zk.synor.io/v1/ws',
|
||||||
|
timeout: 60,
|
||||||
|
retries: 3,
|
||||||
|
default_proof_system: ProofSystem::GROTH16,
|
||||||
|
debug: false
|
||||||
|
)
|
||||||
|
@api_key = api_key
|
||||||
|
@endpoint = endpoint
|
||||||
|
@ws_endpoint = ws_endpoint
|
||||||
|
@timeout = timeout
|
||||||
|
@retries = retries
|
||||||
|
@default_proof_system = default_proof_system
|
||||||
|
@debug = debug
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ZK exception
|
||||||
|
class ZkError < StandardError
|
||||||
|
attr_reader :code, :status
|
||||||
|
|
||||||
|
def initialize(message, code: nil, status: nil)
|
||||||
|
super(message)
|
||||||
|
@code = code
|
||||||
|
@status = status
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Proof system info
|
||||||
|
ProofSystemInfo = Struct.new(:name, :proof_size, :verification_time_ms, :trusted_setup, :universal)
|
||||||
|
|
||||||
|
PROOF_SYSTEM_INFO = {
|
||||||
|
ProofSystem::GROTH16 => ProofSystemInfo.new('Groth16', 192, 10, true, false),
|
||||||
|
ProofSystem::PLONK => ProofSystemInfo.new('PLONK', 512, 15, true, true),
|
||||||
|
ProofSystem::STARK => ProofSystemInfo.new('STARK', 50_000, 30, false, true)
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
MAX_BATCH_SIZE = 1000
|
||||||
|
STATE_TREE_DEPTH = 32
|
||||||
|
PROOF_EXPIRY_BLOCKS = 100
|
||||||
|
|
||||||
|
# Main ZK client
|
||||||
|
class Client
|
||||||
|
attr_reader :proofs, :circuits, :rollup, :state, :ceremony
|
||||||
|
|
||||||
|
def initialize(config)
|
||||||
|
@config = config
|
||||||
|
@closed = false
|
||||||
|
|
||||||
|
@proofs = ProofsClient.new(self)
|
||||||
|
@circuits = CircuitsClient.new(self)
|
||||||
|
@rollup = RollupClient.new(self)
|
||||||
|
@state = StateClient.new(self)
|
||||||
|
@ceremony = CeremonyClient.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_proof_system
|
||||||
|
@config.default_proof_system
|
||||||
|
end
|
||||||
|
|
||||||
|
def health_check
|
||||||
|
result = get('/health')
|
||||||
|
result['status'] == 'healthy'
|
||||||
|
rescue StandardError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_info
|
||||||
|
get('/info')
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
@closed = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def closed?
|
||||||
|
@closed
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(path)
|
||||||
|
request(:get, path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def post(path, body)
|
||||||
|
request(:post, path, body)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def request(method, path, body = nil)
|
||||||
|
raise ZkError.new('Client has been closed', code: 'CLIENT_CLOSED') if @closed
|
||||||
|
|
||||||
|
uri = URI.parse("#{@config.endpoint}#{path}")
|
||||||
|
|
||||||
|
http = Net::HTTP.new(uri.host, uri.port)
|
||||||
|
http.use_ssl = uri.scheme == 'https'
|
||||||
|
http.read_timeout = @config.timeout
|
||||||
|
|
||||||
|
request = case method
|
||||||
|
when :get
|
||||||
|
Net::HTTP::Get.new(uri.request_uri)
|
||||||
|
when :post
|
||||||
|
req = Net::HTTP::Post.new(uri.request_uri)
|
||||||
|
req.body = body.to_json if body
|
||||||
|
req
|
||||||
|
end
|
||||||
|
|
||||||
|
request['Content-Type'] = 'application/json'
|
||||||
|
request['Authorization'] = "Bearer #{@config.api_key}"
|
||||||
|
request['X-SDK-Version'] = 'ruby/0.1.0'
|
||||||
|
|
||||||
|
response = http.request(request)
|
||||||
|
|
||||||
|
unless response.is_a?(Net::HTTPSuccess)
|
||||||
|
error = JSON.parse(response.body) rescue {}
|
||||||
|
raise ZkError.new(
|
||||||
|
error['message'] || "HTTP #{response.code}",
|
||||||
|
code: error['code'],
|
||||||
|
status: response.code.to_i
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
JSON.parse(response.body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Proofs sub-client
|
||||||
|
class ProofsClient
|
||||||
|
def initialize(zk)
|
||||||
|
@zk = zk
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate(request)
|
||||||
|
body = request.to_json
|
||||||
|
body['system'] ||= @zk.default_proof_system
|
||||||
|
result = @zk.post('/proofs/generate', body)
|
||||||
|
Proof.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify(proof)
|
||||||
|
result = @zk.post('/proofs/verify', {
|
||||||
|
'proof_id' => proof.id,
|
||||||
|
'data' => proof.data,
|
||||||
|
'public_inputs' => proof.public_inputs,
|
||||||
|
'system' => proof.system,
|
||||||
|
'circuit_type' => proof.circuit_type
|
||||||
|
})
|
||||||
|
VerificationResult.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(proof_id)
|
||||||
|
result = @zk.get("/proofs/#{proof_id}")
|
||||||
|
Proof.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list(limit: nil, offset: nil)
|
||||||
|
params = []
|
||||||
|
params << "limit=#{limit}" if limit
|
||||||
|
params << "offset=#{offset}" if offset
|
||||||
|
path = params.empty? ? '/proofs' : "/proofs?#{params.join('&')}"
|
||||||
|
result = @zk.get(path)
|
||||||
|
(result['proofs'] || []).map { |p| Proof.from_json(p) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize(proof)
|
||||||
|
result = @zk.post('/proofs/serialize', { 'proof_id' => proof.id })
|
||||||
|
Base64.strict_decode64(result['data'])
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize(data, system)
|
||||||
|
result = @zk.post('/proofs/deserialize', {
|
||||||
|
'data' => Base64.strict_encode64(data),
|
||||||
|
'system' => system
|
||||||
|
})
|
||||||
|
Proof.from_json(result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Circuits sub-client
|
||||||
|
class CircuitsClient
|
||||||
|
def initialize(zk)
|
||||||
|
@zk = zk
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_verification_key(circuit_type, system = nil)
|
||||||
|
sys = system || @zk.default_proof_system
|
||||||
|
result = @zk.get("/circuits/#{circuit_type}/vk?system=#{sys}")
|
||||||
|
VerificationKey.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_proving_key(circuit_type, system = nil)
|
||||||
|
sys = system || @zk.default_proof_system
|
||||||
|
result = @zk.get("/circuits/#{circuit_type}/pk?system=#{sys}")
|
||||||
|
ProvingKey.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list
|
||||||
|
result = @zk.get('/circuits')
|
||||||
|
(result['circuits'] || []).map { |c| CircuitConfig.from_json(c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_config(circuit_type)
|
||||||
|
result = @zk.get("/circuits/#{circuit_type}/config")
|
||||||
|
CircuitConfig.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile(config)
|
||||||
|
result = @zk.post('/circuits/compile', config.to_json)
|
||||||
|
result['circuit_id']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rollup sub-client
|
||||||
|
class RollupClient
|
||||||
|
def initialize(zk)
|
||||||
|
@zk = zk
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_stats
|
||||||
|
result = @zk.get('/rollup/stats')
|
||||||
|
RollupStats.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_current_batch
|
||||||
|
result = @zk.get('/rollup/batch/current')
|
||||||
|
Batch.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_batch(batch_number)
|
||||||
|
result = @zk.get("/rollup/batch/#{batch_number}")
|
||||||
|
Batch.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def submit_transfer(transfer)
|
||||||
|
result = @zk.post('/rollup/transfer', transfer.to_json)
|
||||||
|
result['tx_id']
|
||||||
|
end
|
||||||
|
|
||||||
|
def submit_deposit(deposit)
|
||||||
|
result = @zk.post('/rollup/deposit', deposit.to_json)
|
||||||
|
result['tx_id']
|
||||||
|
end
|
||||||
|
|
||||||
|
def submit_withdrawal(withdrawal)
|
||||||
|
result = @zk.post('/rollup/withdraw', withdrawal.to_json)
|
||||||
|
result['tx_id']
|
||||||
|
end
|
||||||
|
|
||||||
|
def finalize_batch
|
||||||
|
result = @zk.post('/rollup/batch/finalize', {})
|
||||||
|
Batch.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_pending_transactions
|
||||||
|
result = @zk.get('/rollup/pending')
|
||||||
|
(result['transactions'] || []).map { |t| Transfer.from_json(t) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# State sub-client
|
||||||
|
class StateClient
|
||||||
|
def initialize(zk)
|
||||||
|
@zk = zk
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_root
|
||||||
|
result = @zk.get('/state/root')
|
||||||
|
result['root']
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_account(address)
|
||||||
|
result = @zk.get("/state/account/#{address}")
|
||||||
|
AccountState.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_merkle_proof(address)
|
||||||
|
result = @zk.get("/state/proof/#{address}")
|
||||||
|
MerkleProof.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_merkle_proof(proof)
|
||||||
|
result = @zk.post('/state/proof/verify', proof.to_json)
|
||||||
|
result['valid']
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_state_at_batch(batch_number)
|
||||||
|
@zk.get("/state/batch/#{batch_number}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Ceremony sub-client
|
||||||
|
class CeremonyClient
|
||||||
|
def initialize(zk)
|
||||||
|
@zk = zk
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_status(circuit_type, system = nil)
|
||||||
|
sys = system || @zk.default_proof_system
|
||||||
|
result = @zk.get("/ceremony/#{circuit_type}?system=#{sys}")
|
||||||
|
TrustedSetup.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def contribute(circuit_type, entropy, system = nil)
|
||||||
|
sys = system || @zk.default_proof_system
|
||||||
|
result = @zk.post('/ceremony/contribute', {
|
||||||
|
'circuit_type' => circuit_type,
|
||||||
|
'entropy' => Base64.strict_encode64(entropy.pack('C*')),
|
||||||
|
'system' => sys
|
||||||
|
})
|
||||||
|
CeremonyContribution.from_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_contribution(circuit_type, contribution_hash)
|
||||||
|
result = @zk.post('/ceremony/verify', {
|
||||||
|
'circuit_type' => circuit_type,
|
||||||
|
'contribution_hash' => contribution_hash
|
||||||
|
})
|
||||||
|
result['valid']
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_contributions(circuit_type)
|
||||||
|
result = @zk.get("/ceremony/#{circuit_type}/contributions")
|
||||||
|
(result['contributions'] || []).map { |c| CeremonyContribution.from_json(c) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
376
sdk/rust/src/zk/client.rs
Normal file
376
sdk/rust/src/zk/client.rs
Normal file
|
|
@ -0,0 +1,376 @@
|
||||||
|
//! ZK SDK Client
|
||||||
|
|
||||||
|
use crate::zk::types::*;
|
||||||
|
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Synor ZK SDK Client
|
||||||
|
pub struct SynorZk {
|
||||||
|
config: ZkConfig,
|
||||||
|
client: Client,
|
||||||
|
closed: Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SynorZk {
|
||||||
|
/// Create a new ZK SDK client
|
||||||
|
pub fn new(config: ZkConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
config,
|
||||||
|
client: Client::new(),
|
||||||
|
closed: Arc::new(AtomicBool::new(false)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the default proof system
|
||||||
|
pub fn default_proof_system(&self) -> ProofSystem {
|
||||||
|
self.config.default_proof_system
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Health check
|
||||||
|
pub async fn health_check(&self) -> bool {
|
||||||
|
match self.get::<serde_json::Value>("/health").await {
|
||||||
|
Ok(v) => v.get("status").and_then(|s| s.as_str()) == Some("healthy"),
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get service info
|
||||||
|
pub async fn get_info(&self) -> ZkResult<serde_json::Value> {
|
||||||
|
self.get("/info").await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Close the client
|
||||||
|
pub fn close(&self) {
|
||||||
|
self.closed.store(true, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if client is closed
|
||||||
|
pub fn is_closed(&self) -> bool {
|
||||||
|
self.closed.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Proof Operations
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
/// Generate a zero-knowledge proof
|
||||||
|
pub async fn generate_proof(&self, request: ProofRequest) -> ZkResult<Proof> {
|
||||||
|
let system = request.system.unwrap_or(self.default_proof_system());
|
||||||
|
self.post("/proofs/generate", &serde_json::json!({
|
||||||
|
"circuit_type": request.circuit_type,
|
||||||
|
"public_inputs": request.public_inputs,
|
||||||
|
"private_inputs": request.private_inputs,
|
||||||
|
"system": system,
|
||||||
|
})).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a proof
|
||||||
|
pub async fn verify_proof(&self, proof: &Proof) -> ZkResult<VerificationResult> {
|
||||||
|
self.post("/proofs/verify", &serde_json::json!({
|
||||||
|
"proof_id": proof.id,
|
||||||
|
"data": proof.data,
|
||||||
|
"public_inputs": proof.public_inputs,
|
||||||
|
"system": proof.system,
|
||||||
|
"circuit_type": proof.circuit_type,
|
||||||
|
})).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a proof by ID
|
||||||
|
pub async fn get_proof(&self, proof_id: &str) -> ZkResult<Proof> {
|
||||||
|
self.get(&format!("/proofs/{}", proof_id)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List recent proofs
|
||||||
|
pub async fn list_proofs(&self, limit: Option<usize>, offset: Option<usize>) -> ZkResult<Vec<Proof>> {
|
||||||
|
let mut path = "/proofs".to_string();
|
||||||
|
if limit.is_some() || offset.is_some() {
|
||||||
|
path = format!("/proofs?limit={}&offset={}", limit.unwrap_or(10), offset.unwrap_or(0));
|
||||||
|
}
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { proofs: Vec<Proof> }
|
||||||
|
let resp: Response = self.get(&path).await?;
|
||||||
|
Ok(resp.proofs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize a proof to bytes
|
||||||
|
pub async fn serialize_proof(&self, proof: &Proof) -> ZkResult<Vec<u8>> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { data: String }
|
||||||
|
let resp: Response = self.post("/proofs/serialize", &serde_json::json!({
|
||||||
|
"proof_id": proof.id,
|
||||||
|
})).await?;
|
||||||
|
STANDARD.decode(&resp.data).map_err(|e| ZkError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: None,
|
||||||
|
status: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize bytes to a proof
|
||||||
|
pub async fn deserialize_proof(&self, data: &[u8], system: ProofSystem) -> ZkResult<Proof> {
|
||||||
|
self.post("/proofs/deserialize", &serde_json::json!({
|
||||||
|
"data": STANDARD.encode(data),
|
||||||
|
"system": system,
|
||||||
|
})).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Circuit Operations
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
/// Get verification key for a circuit
|
||||||
|
pub async fn get_verification_key(&self, circuit_type: CircuitType, system: Option<ProofSystem>) -> ZkResult<VerificationKey> {
|
||||||
|
let sys = system.unwrap_or(self.default_proof_system());
|
||||||
|
self.get(&format!("/circuits/{:?}/vk?system={:?}", circuit_type, sys).to_lowercase()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get proving key for a circuit
|
||||||
|
pub async fn get_proving_key(&self, circuit_type: CircuitType, system: Option<ProofSystem>) -> ZkResult<ProvingKey> {
|
||||||
|
let sys = system.unwrap_or(self.default_proof_system());
|
||||||
|
self.get(&format!("/circuits/{:?}/pk?system={:?}", circuit_type, sys).to_lowercase()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List available circuits
|
||||||
|
pub async fn list_circuits(&self) -> ZkResult<Vec<CircuitConfig>> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { circuits: Vec<CircuitConfig> }
|
||||||
|
let resp: Response = self.get("/circuits").await?;
|
||||||
|
Ok(resp.circuits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get circuit configuration
|
||||||
|
pub async fn get_circuit_config(&self, circuit_type: CircuitType) -> ZkResult<CircuitConfig> {
|
||||||
|
self.get(&format!("/circuits/{:?}/config", circuit_type).to_lowercase()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile a custom circuit
|
||||||
|
pub async fn compile_circuit(&self, config: CircuitConfig) -> ZkResult<String> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { circuit_id: String }
|
||||||
|
let resp: Response = self.post("/circuits/compile", &config).await?;
|
||||||
|
Ok(resp.circuit_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Rollup Operations
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
/// Get rollup statistics
|
||||||
|
pub async fn get_rollup_stats(&self) -> ZkResult<RollupStats> {
|
||||||
|
self.get("/rollup/stats").await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current batch
|
||||||
|
pub async fn get_current_batch(&self) -> ZkResult<Batch> {
|
||||||
|
self.get("/rollup/batch/current").await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get batch by number
|
||||||
|
pub async fn get_batch(&self, batch_number: u64) -> ZkResult<Batch> {
|
||||||
|
self.get(&format!("/rollup/batch/{}", batch_number)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit a transfer
|
||||||
|
pub async fn submit_transfer(&self, transfer: Transfer) -> ZkResult<String> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { tx_id: String }
|
||||||
|
let resp: Response = self.post("/rollup/transfer", &transfer).await?;
|
||||||
|
Ok(resp.tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit a deposit
|
||||||
|
pub async fn submit_deposit(&self, deposit: Deposit) -> ZkResult<String> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { tx_id: String }
|
||||||
|
let resp: Response = self.post("/rollup/deposit", &deposit).await?;
|
||||||
|
Ok(resp.tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit a withdrawal
|
||||||
|
pub async fn submit_withdrawal(&self, withdrawal: Withdrawal) -> ZkResult<String> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { tx_id: String }
|
||||||
|
let resp: Response = self.post("/rollup/withdraw", &withdrawal).await?;
|
||||||
|
Ok(resp.tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finalize current batch
|
||||||
|
pub async fn finalize_batch(&self) -> ZkResult<Batch> {
|
||||||
|
self.post("/rollup/batch/finalize", &()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get pending transactions
|
||||||
|
pub async fn get_pending_transactions(&self) -> ZkResult<Vec<Transfer>> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { transactions: Vec<Transfer> }
|
||||||
|
let resp: Response = self.get("/rollup/pending").await?;
|
||||||
|
Ok(resp.transactions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// State Operations
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
/// Get current state root
|
||||||
|
pub async fn get_state_root(&self) -> ZkResult<String> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { root: String }
|
||||||
|
let resp: Response = self.get("/state/root").await?;
|
||||||
|
Ok(resp.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get account state
|
||||||
|
pub async fn get_account(&self, address: &str) -> ZkResult<AccountState> {
|
||||||
|
self.get(&format!("/state/account/{}", address)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get merkle proof for account inclusion
|
||||||
|
pub async fn get_merkle_proof(&self, address: &str) -> ZkResult<MerkleProof> {
|
||||||
|
self.get(&format!("/state/proof/{}", address)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify merkle proof
|
||||||
|
pub async fn verify_merkle_proof(&self, proof: &MerkleProof) -> ZkResult<bool> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { valid: bool }
|
||||||
|
let resp: Response = self.post("/state/proof/verify", proof).await?;
|
||||||
|
Ok(resp.valid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get state at specific batch
|
||||||
|
pub async fn get_state_at_batch(&self, batch_number: u64) -> ZkResult<serde_json::Value> {
|
||||||
|
self.get(&format!("/state/batch/{}", batch_number)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Ceremony Operations
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
/// Get ceremony status
|
||||||
|
pub async fn get_ceremony_status(&self, circuit_type: CircuitType, system: Option<ProofSystem>) -> ZkResult<TrustedSetup> {
|
||||||
|
let sys = system.unwrap_or(self.default_proof_system());
|
||||||
|
self.get(&format!("/ceremony/{:?}?system={:?}", circuit_type, sys).to_lowercase()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contribute to ceremony
|
||||||
|
pub async fn contribute_to_ceremony(
|
||||||
|
&self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
entropy: &[u8],
|
||||||
|
system: Option<ProofSystem>,
|
||||||
|
) -> ZkResult<CeremonyContribution> {
|
||||||
|
let sys = system.unwrap_or(self.default_proof_system());
|
||||||
|
self.post("/ceremony/contribute", &serde_json::json!({
|
||||||
|
"circuit_type": circuit_type,
|
||||||
|
"entropy": STANDARD.encode(entropy),
|
||||||
|
"system": sys,
|
||||||
|
})).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a contribution
|
||||||
|
pub async fn verify_contribution(
|
||||||
|
&self,
|
||||||
|
circuit_type: CircuitType,
|
||||||
|
contribution_hash: &str,
|
||||||
|
) -> ZkResult<bool> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { valid: bool }
|
||||||
|
let resp: Response = self.post("/ceremony/verify", &serde_json::json!({
|
||||||
|
"circuit_type": circuit_type,
|
||||||
|
"contribution_hash": contribution_hash,
|
||||||
|
})).await?;
|
||||||
|
Ok(resp.valid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List contributions
|
||||||
|
pub async fn list_contributions(&self, circuit_type: CircuitType) -> ZkResult<Vec<CeremonyContribution>> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Response { contributions: Vec<CeremonyContribution> }
|
||||||
|
let resp: Response = self.get(&format!("/ceremony/{:?}/contributions", circuit_type).to_lowercase()).await?;
|
||||||
|
Ok(resp.contributions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// HTTP Methods
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
async fn get<T: DeserializeOwned>(&self, path: &str) -> ZkResult<T> {
|
||||||
|
self.request("GET", path, Option::<&()>::None).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post<T: DeserializeOwned, B: Serialize>(&self, path: &str, body: &B) -> ZkResult<T> {
|
||||||
|
self.request("POST", path, Some(body)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn request<T: DeserializeOwned, B: Serialize>(
|
||||||
|
&self,
|
||||||
|
method: &str,
|
||||||
|
path: &str,
|
||||||
|
body: Option<&B>,
|
||||||
|
) -> ZkResult<T> {
|
||||||
|
if self.is_closed() {
|
||||||
|
return Err(ZkError {
|
||||||
|
message: "Client has been closed".to_string(),
|
||||||
|
code: Some("CLIENT_CLOSED".to_string()),
|
||||||
|
status: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = format!("{}{}", self.config.endpoint, path);
|
||||||
|
let mut last_error = None;
|
||||||
|
|
||||||
|
for attempt in 0..=self.config.retries {
|
||||||
|
let mut req = match method {
|
||||||
|
"GET" => self.client.get(&url),
|
||||||
|
"POST" => self.client.post(&url),
|
||||||
|
"DELETE" => self.client.delete(&url),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
req = req
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", format!("Bearer {}", self.config.api_key))
|
||||||
|
.header("X-SDK-Version", "rust/0.1.0")
|
||||||
|
.timeout(self.config.timeout);
|
||||||
|
|
||||||
|
if let Some(b) = body {
|
||||||
|
req = req.json(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
match req.send().await {
|
||||||
|
Ok(resp) => {
|
||||||
|
let status = resp.status();
|
||||||
|
if status.is_success() {
|
||||||
|
return resp.json().await.map_err(|e| ZkError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: None,
|
||||||
|
status: None,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let error: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||||
|
return Err(ZkError {
|
||||||
|
message: error["message"].as_str().unwrap_or(&format!("HTTP {}", status)).to_string(),
|
||||||
|
code: error["code"].as_str().map(String::from),
|
||||||
|
status: Some(status.as_u16()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
last_error = Some(e.to_string());
|
||||||
|
if attempt < self.config.retries {
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(100 * 2u64.pow(attempt))).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(ZkError {
|
||||||
|
message: last_error.unwrap_or_else(|| "Request failed".to_string()),
|
||||||
|
code: Some("NETWORK_ERROR".to_string()),
|
||||||
|
status: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
35
sdk/rust/src/zk/mod.rs
Normal file
35
sdk/rust/src/zk/mod.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
//! Synor ZK SDK for Rust
|
||||||
|
//!
|
||||||
|
//! Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! use synor_sdk::zk::{SynorZk, ZkConfig, ProofRequest, CircuitType, ProofSystem};
|
||||||
|
//!
|
||||||
|
//! #[tokio::main]
|
||||||
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
//! let config = ZkConfig::new("your-api-key");
|
||||||
|
//! let zk = SynorZk::new(config);
|
||||||
|
//!
|
||||||
|
//! // Generate a proof
|
||||||
|
//! let proof = zk.generate_proof(ProofRequest {
|
||||||
|
//! circuit_type: CircuitType::Transfer,
|
||||||
|
//! public_inputs: vec![],
|
||||||
|
//! private_inputs: vec![],
|
||||||
|
//! system: Some(ProofSystem::Groth16),
|
||||||
|
//! }).await?;
|
||||||
|
//!
|
||||||
|
//! // Verify the proof
|
||||||
|
//! let result = zk.verify_proof(&proof).await?;
|
||||||
|
//! println!("Valid: {}", result.valid);
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
mod types;
|
||||||
|
mod client;
|
||||||
|
|
||||||
|
pub use types::*;
|
||||||
|
pub use client::*;
|
||||||
312
sdk/rust/src/zk/types.rs
Normal file
312
sdk/rust/src/zk/types.rs
Normal file
|
|
@ -0,0 +1,312 @@
|
||||||
|
//! ZK SDK Types
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Proof system backends
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum ProofSystem {
|
||||||
|
/// Groth16 - smallest proofs (~192 bytes), fastest verification
|
||||||
|
Groth16,
|
||||||
|
/// PLONK - universal trusted setup, medium proofs (~512 bytes)
|
||||||
|
Plonk,
|
||||||
|
/// STARK - no trusted setup, largest proofs (~50KB)
|
||||||
|
Stark,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ProofSystem {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Groth16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuit types for different operations
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum CircuitType {
|
||||||
|
/// Single transfer between accounts
|
||||||
|
Transfer,
|
||||||
|
/// Batch of multiple transfers
|
||||||
|
Batch,
|
||||||
|
/// Deposit from L1 to L2
|
||||||
|
Deposit,
|
||||||
|
/// Withdrawal from L2 to L1
|
||||||
|
Withdraw,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup state
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum RollupState {
|
||||||
|
Active,
|
||||||
|
Paused,
|
||||||
|
Finalizing,
|
||||||
|
Finalized,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof status
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum ProofStatus {
|
||||||
|
Generating,
|
||||||
|
Completed,
|
||||||
|
Failed,
|
||||||
|
Verified,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Zero-knowledge proof
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Proof {
|
||||||
|
pub id: String,
|
||||||
|
pub system: ProofSystem,
|
||||||
|
pub circuit_type: CircuitType,
|
||||||
|
/// Base64 encoded proof data
|
||||||
|
pub data: String,
|
||||||
|
pub public_inputs: Vec<String>,
|
||||||
|
pub size: usize,
|
||||||
|
pub generation_time_ms: u64,
|
||||||
|
pub created_at: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verification key for a circuit
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct VerificationKey {
|
||||||
|
pub circuit_id: String,
|
||||||
|
pub circuit_type: CircuitType,
|
||||||
|
pub system: ProofSystem,
|
||||||
|
/// Base64 encoded verification key
|
||||||
|
pub data: String,
|
||||||
|
pub size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proving key for generating proofs
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvingKey {
|
||||||
|
pub circuit_id: String,
|
||||||
|
pub circuit_type: CircuitType,
|
||||||
|
pub system: ProofSystem,
|
||||||
|
/// Base64 encoded proving key
|
||||||
|
pub data: String,
|
||||||
|
pub size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuit configuration
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct CircuitConfig {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub circuit_type: CircuitType,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub max_batch_size: Option<usize>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub tree_depth: Option<usize>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub verify_signatures: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub custom_constraints: Option<serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Account state in the rollup
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct AccountState {
|
||||||
|
pub address: String,
|
||||||
|
pub balance: String,
|
||||||
|
pub nonce: u64,
|
||||||
|
pub pubkey_hash: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transfer operation
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Transfer {
|
||||||
|
pub from: String,
|
||||||
|
pub to: String,
|
||||||
|
pub amount: String,
|
||||||
|
pub fee: String,
|
||||||
|
pub nonce: u64,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub signature: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deposit operation (L1 -> L2)
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Deposit {
|
||||||
|
pub l1_tx_hash: String,
|
||||||
|
pub recipient: String,
|
||||||
|
pub amount: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub token: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Withdrawal operation (L2 -> L1)
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Withdrawal {
|
||||||
|
pub sender: String,
|
||||||
|
pub recipient: String,
|
||||||
|
pub amount: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub token: Option<String>,
|
||||||
|
pub nonce: u64,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub signature: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup batch
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Batch {
|
||||||
|
pub batch_number: u64,
|
||||||
|
pub prev_state_root: String,
|
||||||
|
pub new_state_root: String,
|
||||||
|
pub transfers: Vec<Transfer>,
|
||||||
|
pub deposits: Vec<Deposit>,
|
||||||
|
pub withdrawals: Vec<Withdrawal>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub proof: Option<Proof>,
|
||||||
|
pub timestamp: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup statistics
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct RollupStats {
|
||||||
|
pub current_batch: u64,
|
||||||
|
pub total_transactions: u64,
|
||||||
|
pub total_proofs: u64,
|
||||||
|
pub avg_proof_time_ms: u64,
|
||||||
|
pub state_root: String,
|
||||||
|
pub account_count: u64,
|
||||||
|
pub tvl: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof generation request
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProofRequest {
|
||||||
|
pub circuit_type: CircuitType,
|
||||||
|
pub public_inputs: Vec<String>,
|
||||||
|
pub private_inputs: Vec<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub system: Option<ProofSystem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof verification result
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct VerificationResult {
|
||||||
|
pub valid: bool,
|
||||||
|
pub verification_time_ms: u64,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub error: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merkle proof for state inclusion
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct MerkleProof {
|
||||||
|
pub leaf: String,
|
||||||
|
pub path: Vec<String>,
|
||||||
|
pub indices: Vec<u8>,
|
||||||
|
pub root: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trusted setup ceremony contribution
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct CeremonyContribution {
|
||||||
|
pub contributor_id: String,
|
||||||
|
pub hash: String,
|
||||||
|
pub timestamp: u64,
|
||||||
|
pub verified: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trusted setup ceremony
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct TrustedSetup {
|
||||||
|
pub id: String,
|
||||||
|
pub circuit_type: CircuitType,
|
||||||
|
pub system: ProofSystem,
|
||||||
|
pub contribution_count: usize,
|
||||||
|
pub latest_hash: String,
|
||||||
|
pub complete: bool,
|
||||||
|
pub contributions: Vec<CeremonyContribution>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ZK SDK configuration
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ZkConfig {
|
||||||
|
pub api_key: String,
|
||||||
|
pub endpoint: String,
|
||||||
|
pub ws_endpoint: String,
|
||||||
|
pub timeout: std::time::Duration,
|
||||||
|
pub retries: u32,
|
||||||
|
pub default_proof_system: ProofSystem,
|
||||||
|
pub debug: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZkConfig {
|
||||||
|
pub fn new(api_key: impl Into<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
api_key: api_key.into(),
|
||||||
|
endpoint: "https://zk.synor.io/v1".to_string(),
|
||||||
|
ws_endpoint: "wss://zk.synor.io/v1/ws".to_string(),
|
||||||
|
timeout: std::time::Duration::from_secs(60),
|
||||||
|
retries: 3,
|
||||||
|
default_proof_system: ProofSystem::Groth16,
|
||||||
|
debug: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ZK SDK error
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ZkError {
|
||||||
|
pub message: String,
|
||||||
|
pub code: Option<String>,
|
||||||
|
pub status: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ZkError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ZkError {}
|
||||||
|
|
||||||
|
pub type ZkResult<T> = Result<T, ZkError>;
|
||||||
|
|
||||||
|
/// Proof system characteristics
|
||||||
|
pub struct ProofSystemInfo {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub proof_size: usize,
|
||||||
|
pub verification_time_ms: u64,
|
||||||
|
pub trusted_setup: bool,
|
||||||
|
pub universal: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProofSystem {
|
||||||
|
pub fn info(&self) -> ProofSystemInfo {
|
||||||
|
match self {
|
||||||
|
ProofSystem::Groth16 => ProofSystemInfo {
|
||||||
|
name: "Groth16",
|
||||||
|
proof_size: 192,
|
||||||
|
verification_time_ms: 10,
|
||||||
|
trusted_setup: true,
|
||||||
|
universal: false,
|
||||||
|
},
|
||||||
|
ProofSystem::Plonk => ProofSystemInfo {
|
||||||
|
name: "PLONK",
|
||||||
|
proof_size: 512,
|
||||||
|
verification_time_ms: 15,
|
||||||
|
trusted_setup: true,
|
||||||
|
universal: true,
|
||||||
|
},
|
||||||
|
ProofSystem::Stark => ProofSystemInfo {
|
||||||
|
name: "STARK",
|
||||||
|
proof_size: 50000,
|
||||||
|
verification_time_ms: 30,
|
||||||
|
trusted_setup: false,
|
||||||
|
universal: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constants
|
||||||
|
pub const MAX_BATCH_SIZE: usize = 1000;
|
||||||
|
pub const STATE_TREE_DEPTH: usize = 32;
|
||||||
|
pub const PROOF_EXPIRY_BLOCKS: u64 = 100;
|
||||||
337
sdk/swift/Sources/SynorZk/SynorZk.swift
Normal file
337
sdk/swift/Sources/SynorZk/SynorZk.swift
Normal file
|
|
@ -0,0 +1,337 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Synor ZK SDK for Swift
|
||||||
|
///
|
||||||
|
/// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
public class SynorZk {
|
||||||
|
private let config: ZkConfig
|
||||||
|
private let session: URLSession
|
||||||
|
private var _closed = false
|
||||||
|
|
||||||
|
public lazy var proofs = ProofsClient(zk: self)
|
||||||
|
public lazy var circuits = CircuitsClient(zk: self)
|
||||||
|
public lazy var rollup = RollupClient(zk: self)
|
||||||
|
public lazy var state = StateClient(zk: self)
|
||||||
|
public lazy var ceremony = CeremonyClient(zk: self)
|
||||||
|
|
||||||
|
public init(config: ZkConfig) {
|
||||||
|
self.config = config
|
||||||
|
let sessionConfig = URLSessionConfiguration.default
|
||||||
|
sessionConfig.timeoutIntervalForRequest = TimeInterval(config.timeout)
|
||||||
|
self.session = URLSession(configuration: sessionConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var defaultProofSystem: ProofSystem { config.defaultProofSystem }
|
||||||
|
|
||||||
|
public func healthCheck() async -> Bool {
|
||||||
|
do {
|
||||||
|
let result = try await get("/health")
|
||||||
|
return result["status"] as? String == "healthy"
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getInfo() async throws -> [String: Any] {
|
||||||
|
try await get("/info")
|
||||||
|
}
|
||||||
|
|
||||||
|
public func close() {
|
||||||
|
_closed = true
|
||||||
|
session.invalidateAndCancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
public var isClosed: Bool { _closed }
|
||||||
|
|
||||||
|
// Internal HTTP methods
|
||||||
|
func get(_ path: String) async throws -> [String: Any] {
|
||||||
|
try checkClosed()
|
||||||
|
var request = URLRequest(url: URL(string: "\(config.endpoint)\(path)")!)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
addHeaders(&request)
|
||||||
|
return try await performRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func post(_ path: String, body: [String: Any]) async throws -> [String: Any] {
|
||||||
|
try checkClosed()
|
||||||
|
var request = URLRequest(url: URL(string: "\(config.endpoint)\(path)")!)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
request.httpBody = try JSONSerialization.data(withJSONObject: body)
|
||||||
|
addHeaders(&request)
|
||||||
|
return try await performRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func addHeaders(_ request: inout URLRequest) {
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
|
request.setValue("Bearer \(config.apiKey)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.setValue("swift/0.1.0", forHTTPHeaderField: "X-SDK-Version")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func performRequest(_ request: URLRequest) async throws -> [String: Any] {
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
guard let httpResponse = response as? HTTPURLResponse else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
if httpResponse.statusCode >= 400 {
|
||||||
|
let error = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
|
||||||
|
throw ZkError(
|
||||||
|
error?["message"] as? String ?? "HTTP \(httpResponse.statusCode)",
|
||||||
|
code: error?["code"] as? String,
|
||||||
|
status: httpResponse.statusCode
|
||||||
|
)
|
||||||
|
}
|
||||||
|
guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
|
||||||
|
throw ZkError("Invalid JSON response")
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkClosed() throws {
|
||||||
|
if _closed {
|
||||||
|
throw ZkError("Client has been closed", code: "CLIENT_CLOSED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proofs sub-client
|
||||||
|
public class ProofsClient {
|
||||||
|
private let zk: SynorZk
|
||||||
|
|
||||||
|
init(zk: SynorZk) {
|
||||||
|
self.zk = zk
|
||||||
|
}
|
||||||
|
|
||||||
|
public func generate(_ request: ProofRequest) async throws -> Proof {
|
||||||
|
var body: [String: Any] = [
|
||||||
|
"circuit_type": request.circuitType.rawValue,
|
||||||
|
"public_inputs": request.publicInputs,
|
||||||
|
"private_inputs": request.privateInputs,
|
||||||
|
"system": (request.system ?? zk.defaultProofSystem).rawValue
|
||||||
|
]
|
||||||
|
let result = try await zk.post("/proofs/generate", body: body)
|
||||||
|
return try Proof.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func verify(_ proof: Proof) async throws -> VerificationResult {
|
||||||
|
let body: [String: Any] = [
|
||||||
|
"proof_id": proof.id,
|
||||||
|
"data": proof.data,
|
||||||
|
"public_inputs": proof.publicInputs,
|
||||||
|
"system": proof.system.rawValue,
|
||||||
|
"circuit_type": proof.circuitType.rawValue
|
||||||
|
]
|
||||||
|
let result = try await zk.post("/proofs/verify", body: body)
|
||||||
|
return VerificationResult.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func get(proofId: String) async throws -> Proof {
|
||||||
|
let result = try await zk.get("/proofs/\(proofId)")
|
||||||
|
return try Proof.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func list(limit: Int? = nil, offset: Int? = nil) async throws -> [Proof] {
|
||||||
|
var path = "/proofs"
|
||||||
|
var params: [String] = []
|
||||||
|
if let limit = limit { params.append("limit=\(limit)") }
|
||||||
|
if let offset = offset { params.append("offset=\(offset)") }
|
||||||
|
if !params.isEmpty { path += "?\(params.joined(separator: "&"))" }
|
||||||
|
|
||||||
|
let result = try await zk.get(path)
|
||||||
|
guard let proofs = result["proofs"] as? [[String: Any]] else { return [] }
|
||||||
|
return try proofs.map { try Proof.fromJson($0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public func serialize(_ proof: Proof) async throws -> Data {
|
||||||
|
let result = try await zk.post("/proofs/serialize", body: ["proof_id": proof.id])
|
||||||
|
guard let dataStr = result["data"] as? String,
|
||||||
|
let data = Data(base64Encoded: dataStr) else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
public func deserialize(_ data: Data, system: ProofSystem) async throws -> Proof {
|
||||||
|
let result = try await zk.post("/proofs/deserialize", body: [
|
||||||
|
"data": data.base64EncodedString(),
|
||||||
|
"system": system.rawValue
|
||||||
|
])
|
||||||
|
return try Proof.fromJson(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuits sub-client
|
||||||
|
public class CircuitsClient {
|
||||||
|
private let zk: SynorZk
|
||||||
|
|
||||||
|
init(zk: SynorZk) {
|
||||||
|
self.zk = zk
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getVerificationKey(circuitType: CircuitType, system: ProofSystem? = nil) async throws -> VerificationKey {
|
||||||
|
let sys = system ?? zk.defaultProofSystem
|
||||||
|
let result = try await zk.get("/circuits/\(circuitType.rawValue)/vk?system=\(sys.rawValue)")
|
||||||
|
return try VerificationKey.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getProvingKey(circuitType: CircuitType, system: ProofSystem? = nil) async throws -> ProvingKey {
|
||||||
|
let sys = system ?? zk.defaultProofSystem
|
||||||
|
let result = try await zk.get("/circuits/\(circuitType.rawValue)/pk?system=\(sys.rawValue)")
|
||||||
|
return try ProvingKey.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func list() async throws -> [CircuitConfig] {
|
||||||
|
let result = try await zk.get("/circuits")
|
||||||
|
guard let circuits = result["circuits"] as? [[String: Any]] else { return [] }
|
||||||
|
return circuits.compactMap { CircuitConfig.fromJson($0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getConfig(circuitType: CircuitType) async throws -> CircuitConfig {
|
||||||
|
let result = try await zk.get("/circuits/\(circuitType.rawValue)/config")
|
||||||
|
guard let config = CircuitConfig.fromJson(result) else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
public func compile(_ config: CircuitConfig) async throws -> String {
|
||||||
|
let result = try await zk.post("/circuits/compile", body: config.toJson())
|
||||||
|
guard let circuitId = result["circuit_id"] as? String else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
return circuitId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup sub-client
|
||||||
|
public class RollupClient {
|
||||||
|
private let zk: SynorZk
|
||||||
|
|
||||||
|
init(zk: SynorZk) {
|
||||||
|
self.zk = zk
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getStats() async throws -> RollupStats {
|
||||||
|
let result = try await zk.get("/rollup/stats")
|
||||||
|
return RollupStats.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getCurrentBatch() async throws -> Batch {
|
||||||
|
let result = try await zk.get("/rollup/batch/current")
|
||||||
|
return try Batch.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getBatch(_ batchNumber: Int) async throws -> Batch {
|
||||||
|
let result = try await zk.get("/rollup/batch/\(batchNumber)")
|
||||||
|
return try Batch.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func submitTransfer(_ transfer: Transfer) async throws -> String {
|
||||||
|
let result = try await zk.post("/rollup/transfer", body: transfer.toJson())
|
||||||
|
guard let txId = result["tx_id"] as? String else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
return txId
|
||||||
|
}
|
||||||
|
|
||||||
|
public func submitDeposit(_ deposit: Deposit) async throws -> String {
|
||||||
|
let result = try await zk.post("/rollup/deposit", body: deposit.toJson())
|
||||||
|
guard let txId = result["tx_id"] as? String else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
return txId
|
||||||
|
}
|
||||||
|
|
||||||
|
public func submitWithdrawal(_ withdrawal: Withdrawal) async throws -> String {
|
||||||
|
let result = try await zk.post("/rollup/withdraw", body: withdrawal.toJson())
|
||||||
|
guard let txId = result["tx_id"] as? String else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
return txId
|
||||||
|
}
|
||||||
|
|
||||||
|
public func finalizeBatch() async throws -> Batch {
|
||||||
|
let result = try await zk.post("/rollup/batch/finalize", body: [:])
|
||||||
|
return try Batch.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getPendingTransactions() async throws -> [Transfer] {
|
||||||
|
let result = try await zk.get("/rollup/pending")
|
||||||
|
guard let transactions = result["transactions"] as? [[String: Any]] else { return [] }
|
||||||
|
return transactions.compactMap { Transfer.fromJson($0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State sub-client
|
||||||
|
public class StateClient {
|
||||||
|
private let zk: SynorZk
|
||||||
|
|
||||||
|
init(zk: SynorZk) {
|
||||||
|
self.zk = zk
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getRoot() async throws -> String {
|
||||||
|
let result = try await zk.get("/state/root")
|
||||||
|
guard let root = result["root"] as? String else {
|
||||||
|
throw ZkError("Invalid response")
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getAccount(address: String) async throws -> AccountState {
|
||||||
|
let result = try await zk.get("/state/account/\(address)")
|
||||||
|
return AccountState.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getMerkleProof(address: String) async throws -> MerkleProof {
|
||||||
|
let result = try await zk.get("/state/proof/\(address)")
|
||||||
|
return MerkleProof.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func verifyMerkleProof(_ proof: MerkleProof) async throws -> Bool {
|
||||||
|
let result = try await zk.post("/state/proof/verify", body: proof.toJson())
|
||||||
|
return result["valid"] as? Bool ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getStateAtBatch(_ batchNumber: Int) async throws -> [String: Any] {
|
||||||
|
try await zk.get("/state/batch/\(batchNumber)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ceremony sub-client
|
||||||
|
public class CeremonyClient {
|
||||||
|
private let zk: SynorZk
|
||||||
|
|
||||||
|
init(zk: SynorZk) {
|
||||||
|
self.zk = zk
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getStatus(circuitType: CircuitType, system: ProofSystem? = nil) async throws -> TrustedSetup {
|
||||||
|
let sys = system ?? zk.defaultProofSystem
|
||||||
|
let result = try await zk.get("/ceremony/\(circuitType.rawValue)?system=\(sys.rawValue)")
|
||||||
|
return TrustedSetup.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func contribute(circuitType: CircuitType, entropy: Data, system: ProofSystem? = nil) async throws -> CeremonyContribution {
|
||||||
|
let sys = system ?? zk.defaultProofSystem
|
||||||
|
let result = try await zk.post("/ceremony/contribute", body: [
|
||||||
|
"circuit_type": circuitType.rawValue,
|
||||||
|
"entropy": entropy.base64EncodedString(),
|
||||||
|
"system": sys.rawValue
|
||||||
|
])
|
||||||
|
return CeremonyContribution.fromJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func verifyContribution(circuitType: CircuitType, contributionHash: String) async throws -> Bool {
|
||||||
|
let result = try await zk.post("/ceremony/verify", body: [
|
||||||
|
"circuit_type": circuitType.rawValue,
|
||||||
|
"contribution_hash": contributionHash
|
||||||
|
])
|
||||||
|
return result["valid"] as? Bool ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func listContributions(circuitType: CircuitType) async throws -> [CeremonyContribution] {
|
||||||
|
let result = try await zk.get("/ceremony/\(circuitType.rawValue)/contributions")
|
||||||
|
guard let contributions = result["contributions"] as? [[String: Any]] else { return [] }
|
||||||
|
return contributions.map { CeremonyContribution.fromJson($0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
496
sdk/swift/Sources/SynorZk/Types.swift
Normal file
496
sdk/swift/Sources/SynorZk/Types.swift
Normal file
|
|
@ -0,0 +1,496 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Synor ZK SDK Types for Swift
|
||||||
|
///
|
||||||
|
/// Zero-Knowledge proof systems for ZK-Rollups and privacy.
|
||||||
|
|
||||||
|
/// Proof system backends
|
||||||
|
public enum ProofSystem: String, Codable {
|
||||||
|
case groth16
|
||||||
|
case plonk
|
||||||
|
case stark
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuit types for different operations
|
||||||
|
public enum CircuitType: String, Codable {
|
||||||
|
case transfer
|
||||||
|
case batch
|
||||||
|
case deposit
|
||||||
|
case withdraw
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup state
|
||||||
|
public enum RollupState: String, Codable {
|
||||||
|
case active
|
||||||
|
case paused
|
||||||
|
case finalizing
|
||||||
|
case finalized
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof status
|
||||||
|
public enum ProofStatus: String, Codable {
|
||||||
|
case generating
|
||||||
|
case completed
|
||||||
|
case failed
|
||||||
|
case verified
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Zero-knowledge proof
|
||||||
|
public struct Proof {
|
||||||
|
public let id: String
|
||||||
|
public let system: ProofSystem
|
||||||
|
public let circuitType: CircuitType
|
||||||
|
public let data: String
|
||||||
|
public let publicInputs: [String]
|
||||||
|
public let size: Int
|
||||||
|
public let generationTimeMs: Int
|
||||||
|
public let createdAt: Int
|
||||||
|
|
||||||
|
public init(id: String, system: ProofSystem, circuitType: CircuitType, data: String,
|
||||||
|
publicInputs: [String], size: Int, generationTimeMs: Int, createdAt: Int) {
|
||||||
|
self.id = id
|
||||||
|
self.system = system
|
||||||
|
self.circuitType = circuitType
|
||||||
|
self.data = data
|
||||||
|
self.publicInputs = publicInputs
|
||||||
|
self.size = size
|
||||||
|
self.generationTimeMs = generationTimeMs
|
||||||
|
self.createdAt = createdAt
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) throws -> Proof {
|
||||||
|
guard let id = json["id"] as? String,
|
||||||
|
let systemStr = json["system"] as? String,
|
||||||
|
let system = ProofSystem(rawValue: systemStr),
|
||||||
|
let circuitTypeStr = json["circuit_type"] as? String,
|
||||||
|
let circuitType = CircuitType(rawValue: circuitTypeStr),
|
||||||
|
let data = json["data"] as? String else {
|
||||||
|
throw ZkError("Invalid proof JSON")
|
||||||
|
}
|
||||||
|
return Proof(
|
||||||
|
id: id,
|
||||||
|
system: system,
|
||||||
|
circuitType: circuitType,
|
||||||
|
data: data,
|
||||||
|
publicInputs: json["public_inputs"] as? [String] ?? [],
|
||||||
|
size: json["size"] as? Int ?? 0,
|
||||||
|
generationTimeMs: json["generation_time_ms"] as? Int ?? 0,
|
||||||
|
createdAt: json["created_at"] as? Int ?? 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verification key for a circuit
|
||||||
|
public struct VerificationKey {
|
||||||
|
public let circuitId: String
|
||||||
|
public let circuitType: CircuitType
|
||||||
|
public let system: ProofSystem
|
||||||
|
public let data: String
|
||||||
|
public let size: Int
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) throws -> VerificationKey {
|
||||||
|
guard let circuitId = json["circuit_id"] as? String,
|
||||||
|
let circuitTypeStr = json["circuit_type"] as? String,
|
||||||
|
let circuitType = CircuitType(rawValue: circuitTypeStr),
|
||||||
|
let systemStr = json["system"] as? String,
|
||||||
|
let system = ProofSystem(rawValue: systemStr),
|
||||||
|
let data = json["data"] as? String else {
|
||||||
|
throw ZkError("Invalid verification key JSON")
|
||||||
|
}
|
||||||
|
return VerificationKey(
|
||||||
|
circuitId: circuitId,
|
||||||
|
circuitType: circuitType,
|
||||||
|
system: system,
|
||||||
|
data: data,
|
||||||
|
size: json["size"] as? Int ?? 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proving key for generating proofs
|
||||||
|
public struct ProvingKey {
|
||||||
|
public let circuitId: String
|
||||||
|
public let circuitType: CircuitType
|
||||||
|
public let system: ProofSystem
|
||||||
|
public let data: String
|
||||||
|
public let size: Int
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) throws -> ProvingKey {
|
||||||
|
guard let circuitId = json["circuit_id"] as? String,
|
||||||
|
let circuitTypeStr = json["circuit_type"] as? String,
|
||||||
|
let circuitType = CircuitType(rawValue: circuitTypeStr),
|
||||||
|
let systemStr = json["system"] as? String,
|
||||||
|
let system = ProofSystem(rawValue: systemStr),
|
||||||
|
let data = json["data"] as? String else {
|
||||||
|
throw ZkError("Invalid proving key JSON")
|
||||||
|
}
|
||||||
|
return ProvingKey(
|
||||||
|
circuitId: circuitId,
|
||||||
|
circuitType: circuitType,
|
||||||
|
system: system,
|
||||||
|
data: data,
|
||||||
|
size: json["size"] as? Int ?? 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Circuit configuration
|
||||||
|
public struct CircuitConfig {
|
||||||
|
public let type: CircuitType
|
||||||
|
public let maxBatchSize: Int?
|
||||||
|
public let treeDepth: Int?
|
||||||
|
public let verifySignatures: Bool?
|
||||||
|
public let customConstraints: [String: Any]?
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> CircuitConfig? {
|
||||||
|
guard let typeStr = json["type"] as? String,
|
||||||
|
let type = CircuitType(rawValue: typeStr) else { return nil }
|
||||||
|
return CircuitConfig(
|
||||||
|
type: type,
|
||||||
|
maxBatchSize: json["max_batch_size"] as? Int,
|
||||||
|
treeDepth: json["tree_depth"] as? Int,
|
||||||
|
verifySignatures: json["verify_signatures"] as? Bool,
|
||||||
|
customConstraints: json["custom_constraints"] as? [String: Any]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toJson() -> [String: Any] {
|
||||||
|
var result: [String: Any] = ["type": type.rawValue]
|
||||||
|
if let v = maxBatchSize { result["max_batch_size"] = v }
|
||||||
|
if let v = treeDepth { result["tree_depth"] = v }
|
||||||
|
if let v = verifySignatures { result["verify_signatures"] = v }
|
||||||
|
if let v = customConstraints { result["custom_constraints"] = v }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Account state in the rollup
|
||||||
|
public struct AccountState {
|
||||||
|
public let address: String
|
||||||
|
public let balance: String
|
||||||
|
public let nonce: Int
|
||||||
|
public let pubkeyHash: String
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> AccountState {
|
||||||
|
AccountState(
|
||||||
|
address: json["address"] as? String ?? "",
|
||||||
|
balance: json["balance"] as? String ?? "0",
|
||||||
|
nonce: json["nonce"] as? Int ?? 0,
|
||||||
|
pubkeyHash: json["pubkey_hash"] as? String ?? ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transfer operation
|
||||||
|
public struct Transfer {
|
||||||
|
public let from: String
|
||||||
|
public let to: String
|
||||||
|
public let amount: String
|
||||||
|
public let fee: String
|
||||||
|
public let nonce: Int
|
||||||
|
public let signature: String?
|
||||||
|
|
||||||
|
public init(from: String, to: String, amount: String, fee: String, nonce: Int, signature: String? = nil) {
|
||||||
|
self.from = from
|
||||||
|
self.to = to
|
||||||
|
self.amount = amount
|
||||||
|
self.fee = fee
|
||||||
|
self.nonce = nonce
|
||||||
|
self.signature = signature
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> Transfer? {
|
||||||
|
guard let from = json["from"] as? String,
|
||||||
|
let to = json["to"] as? String,
|
||||||
|
let amount = json["amount"] as? String,
|
||||||
|
let fee = json["fee"] as? String else { return nil }
|
||||||
|
return Transfer(
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
amount: amount,
|
||||||
|
fee: fee,
|
||||||
|
nonce: json["nonce"] as? Int ?? 0,
|
||||||
|
signature: json["signature"] as? String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toJson() -> [String: Any] {
|
||||||
|
var result: [String: Any] = [
|
||||||
|
"from": from,
|
||||||
|
"to": to,
|
||||||
|
"amount": amount,
|
||||||
|
"fee": fee,
|
||||||
|
"nonce": nonce
|
||||||
|
]
|
||||||
|
if let sig = signature { result["signature"] = sig }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deposit operation (L1 -> L2)
|
||||||
|
public struct Deposit {
|
||||||
|
public let l1TxHash: String
|
||||||
|
public let recipient: String
|
||||||
|
public let amount: String
|
||||||
|
public let token: String?
|
||||||
|
|
||||||
|
public init(l1TxHash: String, recipient: String, amount: String, token: String? = nil) {
|
||||||
|
self.l1TxHash = l1TxHash
|
||||||
|
self.recipient = recipient
|
||||||
|
self.amount = amount
|
||||||
|
self.token = token
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toJson() -> [String: Any] {
|
||||||
|
var result: [String: Any] = [
|
||||||
|
"l1_tx_hash": l1TxHash,
|
||||||
|
"recipient": recipient,
|
||||||
|
"amount": amount
|
||||||
|
]
|
||||||
|
if let t = token { result["token"] = t }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Withdrawal operation (L2 -> L1)
|
||||||
|
public struct Withdrawal {
|
||||||
|
public let sender: String
|
||||||
|
public let recipient: String
|
||||||
|
public let amount: String
|
||||||
|
public let token: String?
|
||||||
|
public let nonce: Int
|
||||||
|
public let signature: String?
|
||||||
|
|
||||||
|
public init(sender: String, recipient: String, amount: String, token: String? = nil, nonce: Int, signature: String? = nil) {
|
||||||
|
self.sender = sender
|
||||||
|
self.recipient = recipient
|
||||||
|
self.amount = amount
|
||||||
|
self.token = token
|
||||||
|
self.nonce = nonce
|
||||||
|
self.signature = signature
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toJson() -> [String: Any] {
|
||||||
|
var result: [String: Any] = [
|
||||||
|
"sender": sender,
|
||||||
|
"recipient": recipient,
|
||||||
|
"amount": amount,
|
||||||
|
"nonce": nonce
|
||||||
|
]
|
||||||
|
if let t = token { result["token"] = t }
|
||||||
|
if let sig = signature { result["signature"] = sig }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup batch
|
||||||
|
public struct Batch {
|
||||||
|
public let batchNumber: Int
|
||||||
|
public let prevStateRoot: String
|
||||||
|
public let newStateRoot: String
|
||||||
|
public let transfers: [Transfer]
|
||||||
|
public let deposits: [Deposit]
|
||||||
|
public let withdrawals: [Withdrawal]
|
||||||
|
public let proof: Proof?
|
||||||
|
public let timestamp: Int
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) throws -> Batch {
|
||||||
|
let transfers = (json["transfers"] as? [[String: Any]] ?? []).compactMap { Transfer.fromJson($0) }
|
||||||
|
return Batch(
|
||||||
|
batchNumber: json["batch_number"] as? Int ?? 0,
|
||||||
|
prevStateRoot: json["prev_state_root"] as? String ?? "",
|
||||||
|
newStateRoot: json["new_state_root"] as? String ?? "",
|
||||||
|
transfers: transfers,
|
||||||
|
deposits: [],
|
||||||
|
withdrawals: [],
|
||||||
|
proof: (json["proof"] as? [String: Any]).flatMap { try? Proof.fromJson($0) },
|
||||||
|
timestamp: json["timestamp"] as? Int ?? 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rollup statistics
|
||||||
|
public struct RollupStats {
|
||||||
|
public let currentBatch: Int
|
||||||
|
public let totalTransactions: Int
|
||||||
|
public let totalProofs: Int
|
||||||
|
public let avgProofTimeMs: Int
|
||||||
|
public let stateRoot: String
|
||||||
|
public let accountCount: Int
|
||||||
|
public let tvl: String
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> RollupStats {
|
||||||
|
RollupStats(
|
||||||
|
currentBatch: json["current_batch"] as? Int ?? 0,
|
||||||
|
totalTransactions: json["total_transactions"] as? Int ?? 0,
|
||||||
|
totalProofs: json["total_proofs"] as? Int ?? 0,
|
||||||
|
avgProofTimeMs: json["avg_proof_time_ms"] as? Int ?? 0,
|
||||||
|
stateRoot: json["state_root"] as? String ?? "",
|
||||||
|
accountCount: json["account_count"] as? Int ?? 0,
|
||||||
|
tvl: json["tvl"] as? String ?? "0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof generation request
|
||||||
|
public struct ProofRequest {
|
||||||
|
public let circuitType: CircuitType
|
||||||
|
public let publicInputs: [String]
|
||||||
|
public let privateInputs: [String]
|
||||||
|
public let system: ProofSystem?
|
||||||
|
|
||||||
|
public init(circuitType: CircuitType, publicInputs: [String], privateInputs: [String], system: ProofSystem? = nil) {
|
||||||
|
self.circuitType = circuitType
|
||||||
|
self.publicInputs = publicInputs
|
||||||
|
self.privateInputs = privateInputs
|
||||||
|
self.system = system
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof verification result
|
||||||
|
public struct VerificationResult {
|
||||||
|
public let valid: Bool
|
||||||
|
public let verificationTimeMs: Int
|
||||||
|
public let error: String?
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> VerificationResult {
|
||||||
|
VerificationResult(
|
||||||
|
valid: json["valid"] as? Bool ?? false,
|
||||||
|
verificationTimeMs: json["verification_time_ms"] as? Int ?? 0,
|
||||||
|
error: json["error"] as? String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merkle proof for state inclusion
|
||||||
|
public struct MerkleProof {
|
||||||
|
public let leaf: String
|
||||||
|
public let path: [String]
|
||||||
|
public let indices: [Int]
|
||||||
|
public let root: String
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> MerkleProof {
|
||||||
|
MerkleProof(
|
||||||
|
leaf: json["leaf"] as? String ?? "",
|
||||||
|
path: json["path"] as? [String] ?? [],
|
||||||
|
indices: json["indices"] as? [Int] ?? [],
|
||||||
|
root: json["root"] as? String ?? ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toJson() -> [String: Any] {
|
||||||
|
["leaf": leaf, "path": path, "indices": indices, "root": root]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trusted setup ceremony contribution
|
||||||
|
public struct CeremonyContribution {
|
||||||
|
public let contributorId: String
|
||||||
|
public let hash: String
|
||||||
|
public let timestamp: Int
|
||||||
|
public let verified: Bool
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> CeremonyContribution {
|
||||||
|
CeremonyContribution(
|
||||||
|
contributorId: json["contributor_id"] as? String ?? "",
|
||||||
|
hash: json["hash"] as? String ?? "",
|
||||||
|
timestamp: json["timestamp"] as? Int ?? 0,
|
||||||
|
verified: json["verified"] as? Bool ?? false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trusted setup ceremony
|
||||||
|
public struct TrustedSetup {
|
||||||
|
public let id: String
|
||||||
|
public let circuitType: CircuitType
|
||||||
|
public let system: ProofSystem
|
||||||
|
public let contributionCount: Int
|
||||||
|
public let latestHash: String
|
||||||
|
public let complete: Bool
|
||||||
|
public let contributions: [CeremonyContribution]
|
||||||
|
|
||||||
|
public static func fromJson(_ json: [String: Any]) -> TrustedSetup {
|
||||||
|
let contributions = (json["contributions"] as? [[String: Any]] ?? []).map { CeremonyContribution.fromJson($0) }
|
||||||
|
return TrustedSetup(
|
||||||
|
id: json["id"] as? String ?? "",
|
||||||
|
circuitType: CircuitType(rawValue: json["circuit_type"] as? String ?? "transfer") ?? .transfer,
|
||||||
|
system: ProofSystem(rawValue: json["system"] as? String ?? "groth16") ?? .groth16,
|
||||||
|
contributionCount: json["contribution_count"] as? Int ?? 0,
|
||||||
|
latestHash: json["latest_hash"] as? String ?? "",
|
||||||
|
complete: json["complete"] as? Bool ?? false,
|
||||||
|
contributions: contributions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ZK SDK configuration
|
||||||
|
public struct ZkConfig {
|
||||||
|
public let apiKey: String
|
||||||
|
public let endpoint: String
|
||||||
|
public let wsEndpoint: String
|
||||||
|
public let timeout: Int
|
||||||
|
public let retries: Int
|
||||||
|
public let defaultProofSystem: ProofSystem
|
||||||
|
public let debug: Bool
|
||||||
|
|
||||||
|
public init(
|
||||||
|
apiKey: String,
|
||||||
|
endpoint: String = "https://zk.synor.io/v1",
|
||||||
|
wsEndpoint: String = "wss://zk.synor.io/v1/ws",
|
||||||
|
timeout: Int = 60,
|
||||||
|
retries: Int = 3,
|
||||||
|
defaultProofSystem: ProofSystem = .groth16,
|
||||||
|
debug: Bool = false
|
||||||
|
) {
|
||||||
|
self.apiKey = apiKey
|
||||||
|
self.endpoint = endpoint
|
||||||
|
self.wsEndpoint = wsEndpoint
|
||||||
|
self.timeout = timeout
|
||||||
|
self.retries = retries
|
||||||
|
self.defaultProofSystem = defaultProofSystem
|
||||||
|
self.debug = debug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ZK SDK error
|
||||||
|
public struct ZkError: Error, CustomStringConvertible {
|
||||||
|
public let message: String
|
||||||
|
public let code: String?
|
||||||
|
public let status: Int?
|
||||||
|
|
||||||
|
public init(_ message: String, code: String? = nil, status: Int? = nil) {
|
||||||
|
self.message = message
|
||||||
|
self.code = code
|
||||||
|
self.status = status
|
||||||
|
}
|
||||||
|
|
||||||
|
public var description: String {
|
||||||
|
"ZkError: \(message)\(code.map { " (\($0))" } ?? "")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proof system characteristics
|
||||||
|
public struct ProofSystemInfo {
|
||||||
|
public let name: String
|
||||||
|
public let proofSize: Int
|
||||||
|
public let verificationTimeMs: Int
|
||||||
|
public let trustedSetup: Bool
|
||||||
|
public let universal: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getProofSystemInfo(_ system: ProofSystem) -> ProofSystemInfo {
|
||||||
|
switch system {
|
||||||
|
case .groth16:
|
||||||
|
return ProofSystemInfo(name: "Groth16", proofSize: 192, verificationTimeMs: 10, trustedSetup: true, universal: false)
|
||||||
|
case .plonk:
|
||||||
|
return ProofSystemInfo(name: "PLONK", proofSize: 512, verificationTimeMs: 15, trustedSetup: true, universal: true)
|
||||||
|
case .stark:
|
||||||
|
return ProofSystemInfo(name: "STARK", proofSize: 50000, verificationTimeMs: 30, trustedSetup: false, universal: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
public let MAX_BATCH_SIZE = 1000
|
||||||
|
public let STATE_TREE_DEPTH = 32
|
||||||
|
public let PROOF_EXPIRY_BLOCKS = 100
|
||||||
Loading…
Add table
Reference in a new issue