synor/sdk/rust/examples/zk_example.rs
Gulshan Yadav 9416d76108 Add IBC and ZK SDK examples for Rust
- Introduced `ibc_example.rs` demonstrating Inter-Blockchain Communication operations including cross-chain transfers, channel management, packet handling, and relayer operations.
- Introduced `zk_example.rs` showcasing Zero-Knowledge proof operations such as circuit compilation, proof generation and verification, and on-chain verification with multiple proving systems.
2026-01-28 14:15:51 +05:30

607 lines
19 KiB
Rust

//! 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<dyn std::error::Error>> {
// 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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<Vec<String>> = 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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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(())
}