/// Synor ZK SDK Examples for Flutter/Dart /// /// Demonstrates Zero-Knowledge proof operations: /// - Circuit compilation /// - Proof generation and verification /// - Groth16, PLONK, and STARK proving systems /// - Recursive proofs /// - On-chain verification library; import 'dart:io'; import 'package:synor_zk/synor_zk.dart'; Future main() async { // Initialize client final config = ZkConfig( apiKey: Platform.environment['SYNOR_API_KEY'] ?? 'your-api-key', endpoint: 'https://zk.synor.io/v1', timeout: const Duration(seconds: 120), // ZK ops can be slow retries: 3, debug: false, defaultProvingSystem: ProvingSystem.groth16, ); final zk = SynorZk(config); try { // Check service health final healthy = await zk.healthCheck(); print('Service healthy: $healthy\n'); // Run examples await circuitExample(zk); await proofExample(zk); await provingSystemsExample(zk); await recursiveProofExample(zk); await onChainVerificationExample(zk); await setupExample(zk); } finally { await zk.close(); } } Future circuitExample(SynorZk zk) async { print('=== Circuit Compilation ==='); // Circom circuit example: prove knowledge of preimage const circomCircuit = ''' 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 print('Compiling Circom circuit...'); final compiled = await zk.circuits.compile(CompileRequest( code: circomCircuit, format: CircuitFormat.circom, name: 'hash_preimage', provingSystem: ProvingSystem.groth16, )); print('Circuit compiled:'); print(' Circuit ID: ${compiled.circuitId}'); print(' Constraints: ${compiled.constraintCount}'); print(' Public inputs: ${compiled.publicInputCount}'); print(' Private inputs: ${compiled.privateInputCount}'); print(' Proving key size: ${compiled.provingKeySize} bytes'); print(' Verification key size: ${compiled.verificationKeySize} bytes'); // List circuits final circuits = await zk.circuits.list(); print('\nYour circuits: ${circuits.length}'); for (final circuit in circuits) { print(' ${circuit.name} (${circuit.circuitId})'); } // Get circuit details final details = await zk.circuits.get(compiled.circuitId); print('\nCircuit details:'); print(' Format: ${details.format}'); print(' Proving system: ${details.provingSystem}'); print(' Created: ${details.createdAt}'); // Download proving key final provingKey = await zk.circuits.getProvingKey(compiled.circuitId); print('\nProving key downloaded: ${provingKey.length} bytes'); // Download verification key final verificationKey = await zk.circuits.getVerificationKey(compiled.circuitId); print('Verification key downloaded: ${verificationKey.length} bytes'); print(''); } Future proofExample(SynorZk zk) async { print('=== Proof Generation ==='); // First, compile a simple circuit const circuit = ''' pragma circom 2.1.0; template Multiplier() { signal input a; signal input b; signal output c; c <== a * b; } component main {public [c]} = Multiplier(); '''; final compiled = await zk.circuits.compile(CompileRequest( code: circuit, format: CircuitFormat.circom, name: 'multiplier', provingSystem: ProvingSystem.groth16, )); // Generate proof print('Generating proof...'); final startTime = DateTime.now(); final proof = await zk.proofs.generate(GenerateProofRequest( circuitId: compiled.circuitId, inputs: {'a': '3', 'b': '7'}, )); final proofTime = DateTime.now().difference(startTime); print('Proof generated in ${proofTime.inMilliseconds}ms'); print(' Proof ID: ${proof.proofId}'); print(' Proof size: ${proof.proof.length} bytes'); print(' Public signals: ${proof.publicSignals}'); // Verify proof print('\nVerifying proof...'); final verifyStart = DateTime.now(); final isValid = await zk.proofs.verify(VerifyRequest( circuitId: compiled.circuitId, proof: proof.proof, publicSignals: proof.publicSignals, )); final verifyTime = DateTime.now().difference(verifyStart); print('Verification completed in ${verifyTime.inMilliseconds}ms'); print(' Valid: $isValid'); // Verify with wrong public signals (should fail) print('\nVerifying with wrong signals...'); final invalidResult = await zk.proofs.verify(VerifyRequest( circuitId: compiled.circuitId, proof: proof.proof, publicSignals: ['42'], // Wrong answer )); print(' Valid: $invalidResult (expected false)'); // Get proof status final status = await zk.proofs.getStatus(proof.proofId); print('\nProof status:'); print(' State: ${status.state}'); print(' Verified: ${status.verified}'); print(' Created: ${status.createdAt}'); // List proofs final proofs = await zk.proofs.list(compiled.circuitId); print('\nProofs for circuit: ${proofs.length}'); print(''); } Future provingSystemsExample(SynorZk zk) async { print('=== Proving Systems Comparison ==='); // Simple circuit for comparison const circuit = ''' pragma circom 2.1.0; template Comparison() { signal input x; signal input y; signal output sum; sum <== x + y; } component main {public [sum]} = Comparison(); '''; final systems = [ (ProvingSystem.groth16, 'GROTH16'), (ProvingSystem.plonk, 'PLONK'), (ProvingSystem.stark, 'STARK'), ]; print('Comparing proving systems:\n'); for (final (system, name) in systems) { print('$name:'); // Compile for this system final compiled = await zk.circuits.compile(CompileRequest( code: circuit, format: CircuitFormat.circom, name: 'comparison_${name.toLowerCase()}', provingSystem: system, )); // Generate proof final proofStart = DateTime.now(); final proof = await zk.proofs.generate(GenerateProofRequest( circuitId: compiled.circuitId, inputs: {'x': '10', 'y': '20'}, )); final proofTime = DateTime.now().difference(proofStart); // Verify proof final verifyStart = DateTime.now(); await zk.proofs.verify(VerifyRequest( circuitId: compiled.circuitId, proof: proof.proof, publicSignals: proof.publicSignals, )); final verifyTime = DateTime.now().difference(verifyStart); print(' Setup: ${compiled.setupTime}ms'); print(' Proof time: ${proofTime.inMilliseconds}ms'); print(' Verify time: ${verifyTime.inMilliseconds}ms'); print(' Proof size: ${proof.proof.length} bytes'); print(' Verification key: ${compiled.verificationKeySize} bytes'); print(''); } print('Summary:'); print(' Groth16: Smallest proofs, fast verification, trusted setup required'); print(' PLONK: Universal setup, flexible, moderate proof size'); print(' STARK: No trusted setup, largest proofs, quantum resistant'); print(''); } Future recursiveProofExample(SynorZk zk) async { print('=== Recursive Proofs ==='); // Inner circuit const innerCircuit = ''' pragma circom 2.1.0; template Inner() { signal input x; signal output y; y <== x * x; } component main {public [y]} = Inner(); '''; // Compile inner circuit final inner = await zk.circuits.compile(CompileRequest( code: innerCircuit, format: CircuitFormat.circom, name: 'inner_circuit', provingSystem: ProvingSystem.groth16, )); // Generate multiple proofs to aggregate print('Generating proofs to aggregate...'); final proofsToAggregate = []; for (var i = 1; i <= 4; i++) { final proof = await zk.proofs.generate(GenerateProofRequest( circuitId: inner.circuitId, inputs: {'x': '$i'}, )); proofsToAggregate.add(ProofData( proof: proof.proof, publicSignals: proof.publicSignals, )); print(' Proof $i: y = ${proof.publicSignals[0]}'); } // Aggregate proofs recursively print('\nAggregating proofs...'); final aggregated = await zk.proofs.aggregate(AggregateRequest( circuitId: inner.circuitId, proofs: proofsToAggregate, aggregationType: 'recursive', )); final originalSize = proofsToAggregate.fold( 0, (sum, p) => sum + p.proof.length, ); print('Aggregated proof:'); print(' Proof ID: ${aggregated.proofId}'); print(' Aggregated count: ${aggregated.aggregatedCount}'); print(' Proof size: ${aggregated.proof.length} bytes'); print(' Size reduction: ${((1 - aggregated.proof.length / originalSize) * 100).toStringAsFixed(1)}%'); // Verify aggregated proof final isValid = await zk.proofs.verifyAggregated(VerifyAggregatedRequest( circuitId: inner.circuitId, proof: aggregated.proof, publicSignalsList: proofsToAggregate.map((p) => p.publicSignals).toList(), )); print('\nAggregated proof valid: $isValid'); // Batch verification (verify multiple proofs in one operation) print('\nBatch verification...'); final batchResult = await zk.proofs.batchVerify(BatchVerifyRequest( circuitId: inner.circuitId, proofs: proofsToAggregate, )); print(' All valid: ${batchResult.allValid}'); print(' Results: ${batchResult.results.join(", ")}'); print(''); } Future onChainVerificationExample(SynorZk zk) async { print('=== On-Chain Verification ==='); // Compile circuit const circuit = ''' 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(); '''; final compiled = await zk.circuits.compile(CompileRequest( code: circuit, format: CircuitFormat.circom, name: 'vote_commitment', provingSystem: ProvingSystem.groth16, )); // Generate Solidity verifier print('Generating Solidity verifier...'); final solidityVerifier = await zk.contracts.generateVerifier(GenerateVerifierRequest( circuitId: compiled.circuitId, language: 'solidity', optimized: true, )); print('Solidity verifier generated: ${solidityVerifier.code.length} bytes'); print(' Contract name: ${solidityVerifier.contractName}'); print(' Gas estimate: ${solidityVerifier.gasEstimate}'); // Generate proof final proof = await zk.proofs.generate(GenerateProofRequest( circuitId: compiled.circuitId, inputs: { 'vote': '1', // Vote YES (1) or NO (0) 'nullifier': '12345', 'commitment': '12345', // 1 * 12345 }, )); // Format proof for on-chain verification print('\nFormatting proof for on-chain...'); final onChainProof = await zk.contracts.formatProof(FormatProofRequest( circuitId: compiled.circuitId, proof: proof.proof, publicSignals: proof.publicSignals, format: 'calldata', )); final calldataPreview = onChainProof.calldata.length > 100 ? onChainProof.calldata.substring(0, 100) : onChainProof.calldata; print(' Calldata: $calldataPreview...'); print(' Estimated gas: ${onChainProof.gasEstimate}'); // Deploy verifier contract (simulation) print('\nDeploying verifier contract...'); final deployment = await zk.contracts.deployVerifier(DeployRequest( circuitId: compiled.circuitId, network: 'synor-testnet', )); print(' Contract address: ${deployment.address}'); print(' TX hash: ${deployment.txHash}'); print(' Gas used: ${deployment.gasUsed}'); // Verify on-chain print('\nVerifying on-chain...'); final onChainResult = await zk.contracts.verifyOnChain(OnChainVerifyRequest( contractAddress: deployment.address, proof: proof.proof, publicSignals: proof.publicSignals, network: 'synor-testnet', )); print(' TX hash: ${onChainResult.txHash}'); print(' Verified: ${onChainResult.verified}'); print(' Gas used: ${onChainResult.gasUsed}'); // Generate verifier for other targets print('\nGenerating verifiers for other targets:'); final targets = ['cairo', 'noir', 'ink']; for (final target in targets) { final verifier = await zk.contracts.generateVerifier(GenerateVerifierRequest( circuitId: compiled.circuitId, language: target, )); print(' $target: ${verifier.code.length} bytes'); } print(''); } Future setupExample(SynorZk zk) async { print('=== Trusted Setup ==='); // Get available ceremonies final ceremonies = await zk.setup.listCeremonies(); print('Active ceremonies: ${ceremonies.length}'); for (final ceremony in ceremonies) { print(' ${ceremony.name}:'); print(' Status: ${ceremony.status}'); print(' Participants: ${ceremony.participantCount}'); print(' Current round: ${ceremony.currentRound}'); } // Create a new circuit setup const circuit = ''' pragma circom 2.1.0; template NewCircuit() { signal input a; signal output b; b <== a + 1; } component main {public [b]} = NewCircuit(); '''; print('\nInitializing setup for new circuit...'); final setup = await zk.setup.initialize(SetupInitRequest( circuit: circuit, format: CircuitFormat.circom, name: 'new_circuit_setup', provingSystem: ProvingSystem.groth16, ceremonyType: 'powers_of_tau', // or 'phase2' )); print('Setup initialized:'); print(' Ceremony ID: ${setup.ceremonyId}'); print(' Powers of Tau required: ${setup.powersRequired}'); print(' Current phase: ${setup.phase}'); // Contribute to ceremony (in practice, generates random entropy) print('\nContributing to ceremony...'); final contribution = await zk.setup.contribute(ContributeRequest( ceremonyId: setup.ceremonyId, entropy: 'random-entropy-from-user'.codeUnits.map((b) => b.toRadixString(16).padLeft(2, '0')).join(), )); print('Contribution submitted:'); print(' Participant: ${contribution.participantId}'); print(' Contribution hash: ${contribution.hash}'); print(' Verification status: ${contribution.verified}'); // Get ceremony status final status = await zk.setup.getStatus(setup.ceremonyId); print('\nCeremony status:'); print(' Phase: ${status.phase}'); print(' Total contributions: ${status.totalContributions}'); print(' Verified contributions: ${status.verifiedContributions}'); print(' Ready for finalization: ${status.readyForFinalization}'); // Finalize setup (when enough contributions) if (status.readyForFinalization) { print('\nFinalizing setup...'); final finalized = await zk.setup.finalize(setup.ceremonyId); print('Setup finalized:'); print(' Proving key hash: ${finalized.provingKeyHash}'); print(' Verification key hash: ${finalized.verificationKeyHash}'); print(' Contribution transcript: ${finalized.transcriptCid}'); } // Download ceremony transcript final transcript = await zk.setup.getTranscript(setup.ceremonyId); print('\nCeremony transcript: ${transcript.length} bytes'); print(''); }