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