# frozen_string_literal: true # # Synor ZK SDK Examples for Ruby # # Demonstrates zero-knowledge proof operations: # - Circuit compilation (Circom) # - Proof generation and verification # - Multiple proving systems (Groth16, PLONK, STARK) # - Recursive proof composition # - Trusted setup ceremonies # require 'securerandom' require 'synor/zk' class ZkExample def initialize(zk) @zk = zk end def run_circuit_example puts '=== Circuit Compilation ===' # Simple Circom circuit: prove knowledge of factors circom_code = <<~CIRCOM pragma circom 2.1.0; template Multiplier() { signal input a; signal input b; signal output c; c <== a * b; } component main = Multiplier(); CIRCOM # Compile the circuit puts 'Compiling circuit...' circuit = @zk.circuits.compile( code: circom_code, language: :circom ) puts 'Circuit compiled:' puts " Circuit ID: #{circuit.circuit_id}" puts " Constraints: #{circuit.constraints}" puts " Public inputs: #{circuit.public_inputs}" puts " Private inputs: #{circuit.private_inputs}" puts " Outputs: #{circuit.outputs}" # Get circuit info info = @zk.circuits.get(circuit.circuit_id) puts "\nCircuit info:" puts " Name: #{info.name}" puts " Version: #{info.version}" puts " Wires: #{info.wire_count}" puts " Labels: #{info.label_count}" # List available circuits circuits = @zk.circuits.list puts "\nAvailable circuits: #{circuits.length}" circuits.first(3).each do |c| puts " #{c.circuit_id}: #{c.name} (#{c.constraints} constraints)" end puts end def run_groth16_example puts '=== Groth16 Proving System ===' circuit_id = 'multiplier-v1' # Generate proving/verification keys (trusted setup) puts 'Generating keys...' keys = @zk.groth16.setup(circuit_id) puts 'Keys generated:' puts " Proving key size: #{keys.proving_key.length} bytes" puts " Verification key size: #{keys.verification_key.length} bytes" # Prepare witness (private inputs) witness = { 'a' => '3', 'b' => '7' } # Generate proof puts "\nGenerating proof..." proof = @zk.groth16.prove( circuit_id: circuit_id, witness: witness, proving_key: keys.proving_key ) puts 'Proof generated:' puts " Proof size: #{proof.proof_bytes.length} bytes" puts " Public signals: #{proof.public_signals.length}" puts " Proving time: #{proof.proving_time_ms}ms" # Verify proof puts "\nVerifying proof..." verified = @zk.groth16.verify( proof: proof.proof_bytes, public_signals: proof.public_signals, verification_key: keys.verification_key ) puts "Verification result: #{verified}" # Export proof for on-chain verification solidity_calldata = @zk.groth16.export_calldata(proof) puts "\nSolidity calldata: #{solidity_calldata[0, 100]}..." puts end def run_plonk_example puts '=== PLONK Proving System ===' circuit_id = 'multiplier-v1' # PLONK uses universal trusted setup puts 'Getting universal setup...' srs = @zk.plonk.get_universal_setup(14) # 2^14 constraints puts "SRS loaded: #{srs.length} bytes" # Generate circuit-specific keys puts "\nGenerating circuit keys..." keys = @zk.plonk.setup(circuit_id, srs) puts 'Keys generated' # Generate proof witness = { 'a' => '5', 'b' => '9' } puts "\nGenerating PLONK proof..." proof = @zk.plonk.prove( circuit_id: circuit_id, witness: witness, proving_key: keys.proving_key ) puts 'Proof generated:' puts " Proof size: #{proof.proof_bytes.length} bytes" puts " Proving time: #{proof.proving_time_ms}ms" # Verify proof verified = @zk.plonk.verify( proof: proof.proof_bytes, public_signals: proof.public_signals, verification_key: keys.verification_key ) puts "Verification result: #{verified}" # Compare with Groth16 puts "\nPLONK advantages:" puts ' - Universal trusted setup' puts ' - Larger proofs (~2.5 KB vs ~200 bytes)' puts ' - Faster proving for some circuits' puts end def run_stark_example puts '=== STARK Proving System ===' circuit_id = 'multiplier-v1' # STARKs don't need trusted setup puts 'Configuring STARK parameters...' config = { field_size: 256, hash_function: :poseidon, blowup_factor: 8, num_queries: 30, folding_factor: 8 } # Generate proof witness = { 'a' => '11', 'b' => '13' } puts "\nGenerating STARK proof..." proof = @zk.stark.prove( circuit_id: circuit_id, witness: witness, config: config ) puts 'Proof generated:' puts " Proof size: #{proof.proof_bytes.length} bytes" puts " Proving time: #{proof.proving_time_ms}ms" puts " FRI layers: #{proof.fri_layers}" # Verify proof puts "\nVerifying STARK proof..." verified = @zk.stark.verify( proof: proof.proof_bytes, public_signals: proof.public_signals, config: config ) puts "Verification result: #{verified}" # Compare with SNARKs puts "\nSTARK advantages:" puts ' - No trusted setup needed' puts ' - Post-quantum secure' puts ' - Larger proofs (~100 KB)' puts ' - Faster proving for complex computations' puts end def run_recursive_example puts '=== Recursive Proof Composition ===' # Create inner proofs puts 'Generating inner proofs...' inner_proofs = [] (1..3).each do |i| witness = { 'a' => i.to_s, 'b' => (i + 1).to_s } proof = @zk.recursive.prove_inner( circuit_id: 'multiplier-v1', witness: witness, level: 0 ) inner_proofs << proof puts " Inner proof #{i} generated" end # Aggregate proofs recursively puts "\nAggregating proofs..." aggregated_proof = @zk.recursive.aggregate( proofs: inner_proofs, aggregation_circuit: 'recursive-aggregator-v1' ) puts 'Aggregated proof:' puts " Proof size: #{aggregated_proof.proof_bytes.length} bytes" puts " Proofs aggregated: #{aggregated_proof.proofs_aggregated}" puts " Recursion depth: #{aggregated_proof.recursion_depth}" # Verify aggregated proof (verifies all inner proofs at once) puts "\nVerifying aggregated proof..." verified = @zk.recursive.verify_aggregated(aggregated_proof) puts "Verification result: #{verified}" # Use cases puts "\nRecursive proof use cases:" puts ' - Rollup batch verification' puts ' - Incremental computation proofs' puts ' - Cross-chain state proofs' puts end def run_ceremony_example puts '=== Trusted Setup Ceremony ===' # List active ceremonies ceremonies = @zk.ceremony.list(:active) puts "Active ceremonies: #{ceremonies.length}" ceremonies.first(3).each do |ceremony| puts "\n #{ceremony.ceremony_id}:" puts " Circuit: #{ceremony.circuit_id}" puts " Participants: #{ceremony.participant_count}" puts " Current round: #{ceremony.current_round}" puts " Status: #{ceremony.status}" end # Create a new ceremony puts "\nCreating new ceremony..." new_ceremony = @zk.ceremony.create( circuit_id: 'new-circuit-v1', min_participants: 10, max_participants: 100, round_duration: 3600, # 1 hour per round verify_contributions: true ) puts 'Ceremony created:' puts " Ceremony ID: #{new_ceremony.ceremony_id}" puts " Join URL: #{new_ceremony.join_url}" # Participate in a ceremony puts "\nParticipating in ceremony..." # Generate entropy entropy = SecureRandom.random_bytes(32) contribution = @zk.ceremony.contribute( ceremony_id: new_ceremony.ceremony_id, entropy: entropy ) puts 'Contribution made:' puts " Contribution ID: #{contribution.contribution_id}" puts " Position: #{contribution.position}" puts " Hash: #{contribution.hash}" # Verify a contribution puts "\nVerifying contribution..." valid = @zk.ceremony.verify_contribution(contribution.contribution_id) puts "Contribution valid: #{valid}" # Get ceremony transcript (for auditability) transcript = @zk.ceremony.get_transcript(new_ceremony.ceremony_id) puts "\nCeremony transcript:" puts " Total contributions: #{transcript.contributions.length}" puts " Start time: #{transcript.start_time}" puts " Final hash: #{transcript.final_hash.empty? ? 'pending' : transcript.final_hash}" puts end end # Main execution if __FILE__ == $PROGRAM_NAME # Initialize client api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key') config = Synor::Zk::Config.new( api_key: api_key, endpoint: 'https://zk.synor.io/v1', timeout: 120, # ZK operations can be slow retries: 3, debug: false, default_proving_system: :groth16, prove_timeout: 300, verify_timeout: 30 ) zk = Synor::Zk::Client.new(config) example = ZkExample.new(zk) begin # Check service health healthy = zk.health_check puts "Service healthy: #{healthy}\n\n" # Run examples example.run_circuit_example example.run_groth16_example example.run_plonk_example example.run_stark_example example.run_recursive_example example.run_ceremony_example rescue StandardError => e warn "Error: #{e.message}" exit 1 end end