//! Synor ZK SDK Examples for Rust //! //! Demonstrates Zero-Knowledge proof operations: //! - Circuit compilation //! - Proof generation and verification //! - Groth16, PLONK, and STARK proving systems //! - Recursive proofs //! - On-chain verification use std::collections::HashMap; use std::env; use std::time::Instant; use synor_zk::{ AggregateRequest, BatchVerifyRequest, CircuitFormat, CompileRequest, ContributeRequest, DeployRequest, FormatProofRequest, GenerateProofRequest, GenerateVerifierRequest, OnChainVerifyRequest, ProofData, ProvingSystem, SetupInitRequest, SynorZk, VerifyAggregatedRequest, VerifyRequest, ZkConfig, }; #[tokio::main] async fn main() -> Result<(), Box> { // Initialize client let config = ZkConfig { api_key: env::var("SYNOR_API_KEY").unwrap_or_else(|_| "your-api-key".to_string()), endpoint: "https://zk.synor.io/v1".to_string(), timeout: 120000, // ZK ops can be slow retries: 3, debug: false, default_proving_system: ProvingSystem::Groth16, }; let zk = SynorZk::new(config)?; // Check service health let healthy = zk.health_check().await?; println!("Service healthy: {}\n", healthy); // Run examples circuit_example(&zk).await?; proof_example(&zk).await?; proving_systems_example(&zk).await?; recursive_proof_example(&zk).await?; on_chain_verification_example(&zk).await?; setup_example(&zk).await?; zk.close().await?; Ok(()) } async fn circuit_example(zk: &SynorZk) -> Result<(), Box> { println!("=== Circuit Compilation ==="); // Circom circuit example: prove knowledge of preimage let circom_circuit = r#" pragma circom 2.1.0; template HashPreimage() { signal input preimage; signal input hash; // Simplified hash computation (in reality, use proper hash) signal preimageSquared; preimageSquared <== preimage * preimage; // Constrain that hash matches hash === preimageSquared; } component main {public [hash]} = HashPreimage(); "#; // Compile circuit println!("Compiling Circom circuit..."); let compiled = zk .circuits .compile(CompileRequest { code: circom_circuit.to_string(), format: CircuitFormat::Circom, name: "hash_preimage".to_string(), proving_system: ProvingSystem::Groth16, }) .await?; println!("Circuit compiled:"); println!(" Circuit ID: {}", compiled.circuit_id); println!(" Constraints: {}", compiled.constraint_count); println!(" Public inputs: {}", compiled.public_input_count); println!(" Private inputs: {}", compiled.private_input_count); println!(" Proving key size: {} bytes", compiled.proving_key_size); println!(" Verification key size: {} bytes", compiled.verification_key_size); // List circuits let circuits = zk.circuits.list().await?; println!("\nYour circuits: {}", circuits.len()); for circuit in &circuits { println!(" {} ({})", circuit.name, circuit.circuit_id); } // Get circuit details let details = zk.circuits.get(&compiled.circuit_id).await?; println!("\nCircuit details:"); println!(" Format: {:?}", details.format); println!(" Proving system: {:?}", details.proving_system); println!(" Created: {}", details.created_at); // Download proving key let proving_key = zk.circuits.get_proving_key(&compiled.circuit_id).await?; println!("\nProving key downloaded: {} bytes", proving_key.len()); // Download verification key let verification_key = zk.circuits.get_verification_key(&compiled.circuit_id).await?; println!("Verification key downloaded: {} bytes", verification_key.len()); println!(); Ok(()) } async fn proof_example(zk: &SynorZk) -> Result<(), Box> { println!("=== Proof Generation ==="); // First, compile a simple circuit let circuit = r#" pragma circom 2.1.0; template Multiplier() { signal input a; signal input b; signal output c; c <== a * b; } component main {public [c]} = Multiplier(); "#; let compiled = zk .circuits .compile(CompileRequest { code: circuit.to_string(), format: CircuitFormat::Circom, name: "multiplier".to_string(), proving_system: ProvingSystem::Groth16, }) .await?; // Generate proof println!("Generating proof..."); let start_time = Instant::now(); let mut inputs = HashMap::new(); inputs.insert("a".to_string(), "3".to_string()); inputs.insert("b".to_string(), "7".to_string()); let proof = zk .proofs .generate(GenerateProofRequest { circuit_id: compiled.circuit_id.clone(), inputs, }) .await?; let proof_time = start_time.elapsed(); println!("Proof generated in {:?}", proof_time); println!(" Proof ID: {}", proof.proof_id); println!(" Proof size: {} bytes", proof.proof.len()); println!(" Public signals: {:?}", proof.public_signals); // Verify proof println!("\nVerifying proof..."); let verify_start = Instant::now(); let is_valid = zk .proofs .verify(VerifyRequest { circuit_id: compiled.circuit_id.clone(), proof: proof.proof.clone(), public_signals: proof.public_signals.clone(), }) .await?; let verify_time = verify_start.elapsed(); println!("Verification completed in {:?}", verify_time); println!(" Valid: {}", is_valid); // Verify with wrong public signals (should fail) println!("\nVerifying with wrong signals..."); let invalid_result = zk .proofs .verify(VerifyRequest { circuit_id: compiled.circuit_id.clone(), proof: proof.proof.clone(), public_signals: vec!["42".to_string()], // Wrong answer }) .await?; println!(" Valid: {} (expected false)", invalid_result); // Get proof status let status = zk.proofs.get_status(&proof.proof_id).await?; println!("\nProof status:"); println!(" State: {}", status.state); println!(" Verified: {}", status.verified); println!(" Created: {}", status.created_at); // List proofs let proofs = zk.proofs.list(&compiled.circuit_id).await?; println!("\nProofs for circuit: {}", proofs.len()); println!(); Ok(()) } async fn proving_systems_example(zk: &SynorZk) -> Result<(), Box> { println!("=== Proving Systems Comparison ==="); // Simple circuit for comparison let circuit = r#" pragma circom 2.1.0; template Comparison() { signal input x; signal input y; signal output sum; sum <== x + y; } component main {public [sum]} = Comparison(); "#; let systems = [ (ProvingSystem::Groth16, "GROTH16"), (ProvingSystem::PLONK, "PLONK"), (ProvingSystem::STARK, "STARK"), ]; println!("Comparing proving systems:\n"); for (system, name) in systems { println!("{}:", name); // Compile for this system let compiled = zk .circuits .compile(CompileRequest { code: circuit.to_string(), format: CircuitFormat::Circom, name: format!("comparison_{}", name.to_lowercase()), proving_system: system, }) .await?; // Generate proof let proof_start = Instant::now(); let mut inputs = HashMap::new(); inputs.insert("x".to_string(), "10".to_string()); inputs.insert("y".to_string(), "20".to_string()); let proof = zk .proofs .generate(GenerateProofRequest { circuit_id: compiled.circuit_id.clone(), inputs, }) .await?; let proof_time = proof_start.elapsed(); // Verify proof let verify_start = Instant::now(); zk.proofs .verify(VerifyRequest { circuit_id: compiled.circuit_id.clone(), proof: proof.proof.clone(), public_signals: proof.public_signals.clone(), }) .await?; let verify_time = verify_start.elapsed(); println!(" Setup: {}ms", compiled.setup_time); println!(" Proof time: {:?}", proof_time); println!(" Verify time: {:?}", verify_time); println!(" Proof size: {} bytes", proof.proof.len()); println!(" Verification key: {} bytes", compiled.verification_key_size); println!(); } println!("Summary:"); println!(" Groth16: Smallest proofs, fast verification, trusted setup required"); println!(" PLONK: Universal setup, flexible, moderate proof size"); println!(" STARK: No trusted setup, largest proofs, quantum resistant"); println!(); Ok(()) } async fn recursive_proof_example(zk: &SynorZk) -> Result<(), Box> { println!("=== Recursive Proofs ==="); // Inner circuit let inner_circuit = r#" pragma circom 2.1.0; template Inner() { signal input x; signal output y; y <== x * x; } component main {public [y]} = Inner(); "#; // Compile inner circuit let inner = zk .circuits .compile(CompileRequest { code: inner_circuit.to_string(), format: CircuitFormat::Circom, name: "inner_circuit".to_string(), proving_system: ProvingSystem::Groth16, }) .await?; // Generate multiple proofs to aggregate println!("Generating proofs to aggregate..."); let mut proofs_to_aggregate = Vec::new(); for i in 1..=4 { let mut inputs = HashMap::new(); inputs.insert("x".to_string(), i.to_string()); let proof = zk .proofs .generate(GenerateProofRequest { circuit_id: inner.circuit_id.clone(), inputs, }) .await?; proofs_to_aggregate.push(ProofData { proof: proof.proof, public_signals: proof.public_signals.clone(), }); println!(" Proof {}: y = {}", i, proof.public_signals[0]); } // Aggregate proofs recursively println!("\nAggregating proofs..."); let aggregated = zk .proofs .aggregate(AggregateRequest { circuit_id: inner.circuit_id.clone(), proofs: proofs_to_aggregate.clone(), aggregation_type: "recursive".to_string(), }) .await?; let original_size: usize = proofs_to_aggregate.iter().map(|p| p.proof.len()).sum(); println!("Aggregated proof:"); println!(" Proof ID: {}", aggregated.proof_id); println!(" Aggregated count: {}", aggregated.aggregated_count); println!(" Proof size: {} bytes", aggregated.proof.len()); println!( " Size reduction: {:.1}%", (1.0 - aggregated.proof.len() as f64 / original_size as f64) * 100.0 ); // Verify aggregated proof let public_signals_list: Vec> = proofs_to_aggregate .iter() .map(|p| p.public_signals.clone()) .collect(); let is_valid = zk .proofs .verify_aggregated(VerifyAggregatedRequest { circuit_id: inner.circuit_id.clone(), proof: aggregated.proof, public_signals_list, }) .await?; println!("\nAggregated proof valid: {}", is_valid); // Batch verification (verify multiple proofs in one operation) println!("\nBatch verification..."); let batch_result = zk .proofs .batch_verify(BatchVerifyRequest { circuit_id: inner.circuit_id.clone(), proofs: proofs_to_aggregate, }) .await?; println!(" All valid: {}", batch_result.all_valid); println!(" Results: {:?}", batch_result.results); println!(); Ok(()) } async fn on_chain_verification_example(zk: &SynorZk) -> Result<(), Box> { println!("=== On-Chain Verification ==="); // Compile circuit let circuit = r#" pragma circom 2.1.0; template VoteCommitment() { signal input vote; // Private: actual vote signal input nullifier; // Private: unique identifier signal input commitment; // Public: commitment to verify // Simplified commitment (in practice, use Poseidon hash) signal computed; computed <== vote * nullifier; commitment === computed; } component main {public [commitment]} = VoteCommitment(); "#; let compiled = zk .circuits .compile(CompileRequest { code: circuit.to_string(), format: CircuitFormat::Circom, name: "vote_commitment".to_string(), proving_system: ProvingSystem::Groth16, }) .await?; // Generate Solidity verifier println!("Generating Solidity verifier..."); let solidity_verifier = zk .contracts .generate_verifier(GenerateVerifierRequest { circuit_id: compiled.circuit_id.clone(), language: "solidity".to_string(), optimized: true, }) .await?; println!( "Solidity verifier generated: {} bytes", solidity_verifier.code.len() ); println!(" Contract name: {}", solidity_verifier.contract_name); println!(" Gas estimate: {}", solidity_verifier.gas_estimate); // Generate proof let mut inputs = HashMap::new(); inputs.insert("vote".to_string(), "1".to_string()); // Vote YES (1) or NO (0) inputs.insert("nullifier".to_string(), "12345".to_string()); inputs.insert("commitment".to_string(), "12345".to_string()); // 1 * 12345 let proof = zk .proofs .generate(GenerateProofRequest { circuit_id: compiled.circuit_id.clone(), inputs, }) .await?; // Format proof for on-chain verification println!("\nFormatting proof for on-chain..."); let on_chain_proof = zk .contracts .format_proof(FormatProofRequest { circuit_id: compiled.circuit_id.clone(), proof: proof.proof.clone(), public_signals: proof.public_signals.clone(), format: "calldata".to_string(), }) .await?; let calldata_preview = if on_chain_proof.calldata.len() > 100 { &on_chain_proof.calldata[..100] } else { &on_chain_proof.calldata }; println!(" Calldata: {}...", calldata_preview); println!(" Estimated gas: {}", on_chain_proof.gas_estimate); // Deploy verifier contract (simulation) println!("\nDeploying verifier contract..."); let deployment = zk .contracts .deploy_verifier(DeployRequest { circuit_id: compiled.circuit_id.clone(), network: "synor-testnet".to_string(), }) .await?; println!(" Contract address: {}", deployment.address); println!(" TX hash: {}", deployment.tx_hash); println!(" Gas used: {}", deployment.gas_used); // Verify on-chain println!("\nVerifying on-chain..."); let on_chain_result = zk .contracts .verify_on_chain(OnChainVerifyRequest { contract_address: deployment.address, proof: proof.proof, public_signals: proof.public_signals, network: "synor-testnet".to_string(), }) .await?; println!(" TX hash: {}", on_chain_result.tx_hash); println!(" Verified: {}", on_chain_result.verified); println!(" Gas used: {}", on_chain_result.gas_used); // Generate verifier for other targets println!("\nGenerating verifiers for other targets:"); let targets = ["cairo", "noir", "ink"]; for target in targets { let verifier = zk .contracts .generate_verifier(GenerateVerifierRequest { circuit_id: compiled.circuit_id.clone(), language: target.to_string(), optimized: false, }) .await?; println!(" {}: {} bytes", target, verifier.code.len()); } println!(); Ok(()) } async fn setup_example(zk: &SynorZk) -> Result<(), Box> { println!("=== Trusted Setup ==="); // Get available ceremonies let ceremonies = zk.setup.list_ceremonies().await?; println!("Active ceremonies: {}", ceremonies.len()); for ceremony in &ceremonies { println!(" {}:", ceremony.name); println!(" Status: {}", ceremony.status); println!(" Participants: {}", ceremony.participant_count); println!(" Current round: {}", ceremony.current_round); } // Create a new circuit setup let circuit = r#" pragma circom 2.1.0; template NewCircuit() { signal input a; signal output b; b <== a + 1; } component main {public [b]} = NewCircuit(); "#; println!("\nInitializing setup for new circuit..."); let setup = zk .setup .initialize(SetupInitRequest { circuit: circuit.to_string(), format: CircuitFormat::Circom, name: "new_circuit_setup".to_string(), proving_system: ProvingSystem::Groth16, ceremony_type: "powers_of_tau".to_string(), // or 'phase2' }) .await?; println!("Setup initialized:"); println!(" Ceremony ID: {}", setup.ceremony_id); println!(" Powers of Tau required: {}", setup.powers_required); println!(" Current phase: {}", setup.phase); // Contribute to ceremony (in practice, generates random entropy) println!("\nContributing to ceremony..."); let contribution = zk .setup .contribute(ContributeRequest { ceremony_id: setup.ceremony_id.clone(), entropy: hex::encode(b"random-entropy-from-user"), }) .await?; println!("Contribution submitted:"); println!(" Participant: {}", contribution.participant_id); println!(" Contribution hash: {}", contribution.hash); println!(" Verification status: {}", contribution.verified); // Get ceremony status let status = zk.setup.get_status(&setup.ceremony_id).await?; println!("\nCeremony status:"); println!(" Phase: {}", status.phase); println!(" Total contributions: {}", status.total_contributions); println!(" Verified contributions: {}", status.verified_contributions); println!(" Ready for finalization: {}", status.ready_for_finalization); // Finalize setup (when enough contributions) if status.ready_for_finalization { println!("\nFinalizing setup..."); let finalized = zk.setup.finalize(&setup.ceremony_id).await?; println!("Setup finalized:"); println!(" Proving key hash: {}", finalized.proving_key_hash); println!(" Verification key hash: {}", finalized.verification_key_hash); println!(" Contribution transcript: {}", finalized.transcript_cid); } // Download ceremony transcript let transcript = zk.setup.get_transcript(&setup.ceremony_id).await?; println!("\nCeremony transcript: {} bytes", transcript.len()); println!(); Ok(()) }