/** * Synor ZK SDK Examples for JavaScript/TypeScript * * Demonstrates Zero-Knowledge proof operations: * - Circuit compilation * - Proof generation and verification * - Groth16, PLONK, and STARK proving systems * - Recursive proofs * - On-chain verification */ import { SynorZk, ZkConfig, ProvingSystem, CircuitFormat, ProofStatus, } from '../src/zk'; async function main() { // Initialize client const config: ZkConfig = { apiKey: process.env.SYNOR_API_KEY || 'your-api-key', endpoint: 'https://zk.synor.io/v1', timeout: 120000, // ZK ops can be slow retries: 3, debug: false, defaultProvingSystem: ProvingSystem.Groth16, }; const zk = new SynorZk(config); try { // Check service health const healthy = await zk.healthCheck(); console.log(`Service healthy: ${healthy}\n`); // Example 1: Circuit compilation await circuitExample(zk); // Example 2: Proof generation await proofExample(zk); // Example 3: Different proving systems await provingSystemsExample(zk); // Example 4: Recursive proofs await recursiveProofExample(zk); // Example 5: On-chain verification await onChainVerificationExample(zk); // Example 6: Trusted setup await setupExample(zk); } finally { zk.close(); } } /** * Circuit compilation */ async function circuitExample(zk: SynorZk): Promise { console.log('=== 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 console.log('Compiling Circom circuit...'); const compiled = await zk.circuits.compile({ code: circomCircuit, format: CircuitFormat.Circom, name: 'hash_preimage', provingSystem: ProvingSystem.Groth16, }); console.log(`Circuit compiled:`); console.log(` Circuit ID: ${compiled.circuitId}`); console.log(` Constraints: ${compiled.constraintCount}`); console.log(` Public inputs: ${compiled.publicInputCount}`); console.log(` Private inputs: ${compiled.privateInputCount}`); console.log(` Proving key size: ${compiled.provingKeySize} bytes`); console.log(` Verification key size: ${compiled.verificationKeySize} bytes`); // List circuits const circuits = await zk.circuits.list(); console.log(`\nYour circuits: ${circuits.length}`); for (const circuit of circuits) { console.log(` ${circuit.name} (${circuit.circuitId})`); } // Get circuit details const details = await zk.circuits.get(compiled.circuitId); console.log(`\nCircuit details:`); console.log(` Format: ${details.format}`); console.log(` Proving system: ${details.provingSystem}`); console.log(` Created: ${new Date(details.createdAt).toISOString()}`); // Download proving key const provingKey = await zk.circuits.getProvingKey(compiled.circuitId); console.log(`\nProving key downloaded: ${provingKey.length} bytes`); // Download verification key const verificationKey = await zk.circuits.getVerificationKey(compiled.circuitId); console.log(`Verification key downloaded: ${verificationKey.length} bytes`); console.log(''); } /** * Proof generation and verification */ async function proofExample(zk: SynorZk): Promise { console.log('=== 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(); `; const compiled = await zk.circuits.compile({ code: circuit, format: CircuitFormat.Circom, name: 'multiplier', provingSystem: ProvingSystem.Groth16, }); // Generate proof console.log('Generating proof...'); const startTime = Date.now(); const proof = await zk.proofs.generate({ circuitId: compiled.circuitId, inputs: { a: '3', b: '7', }, }); const proofTime = Date.now() - startTime; console.log(`Proof generated in ${proofTime}ms`); console.log(` Proof ID: ${proof.proofId}`); console.log(` Proof size: ${proof.proof.length} bytes`); console.log(` Public signals: ${proof.publicSignals}`); // Verify proof console.log('\nVerifying proof...'); const verifyStart = Date.now(); const isValid = await zk.proofs.verify({ circuitId: compiled.circuitId, proof: proof.proof, publicSignals: proof.publicSignals, }); const verifyTime = Date.now() - verifyStart; console.log(`Verification completed in ${verifyTime}ms`); console.log(` Valid: ${isValid}`); // Verify with wrong public signals (should fail) console.log('\nVerifying with wrong signals...'); const invalidResult = await zk.proofs.verify({ circuitId: compiled.circuitId, proof: proof.proof, publicSignals: ['42'], // Wrong answer }); console.log(` Valid: ${invalidResult} (expected false)`); // Get proof status const status = await zk.proofs.getStatus(proof.proofId); console.log(`\nProof status:`); console.log(` State: ${status.state}`); console.log(` Verified: ${status.verified}`); console.log(` Created: ${new Date(status.createdAt).toISOString()}`); // List proofs const proofs = await zk.proofs.list({ circuitId: compiled.circuitId }); console.log(`\nProofs for circuit: ${proofs.length}`); console.log(''); } /** * Different proving systems comparison */ async function provingSystemsExample(zk: SynorZk): Promise { console.log('=== 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(); `; const systems = [ ProvingSystem.Groth16, ProvingSystem.Plonk, ProvingSystem.Stark, ]; console.log('Comparing proving systems:\n'); for (const system of systems) { console.log(`${system}:`); // Compile for this system const compiled = await zk.circuits.compile({ code: circuit, format: CircuitFormat.Circom, name: `comparison_${system.toLowerCase()}`, provingSystem: system, }); // Generate proof const proofStart = Date.now(); const proof = await zk.proofs.generate({ circuitId: compiled.circuitId, inputs: { x: '10', y: '20' }, }); const proofTime = Date.now() - proofStart; // Verify proof const verifyStart = Date.now(); await zk.proofs.verify({ circuitId: compiled.circuitId, proof: proof.proof, publicSignals: proof.publicSignals, }); const verifyTime = Date.now() - verifyStart; console.log(` Setup: ${compiled.setupTime}ms`); console.log(` Proof time: ${proofTime}ms`); console.log(` Verify time: ${verifyTime}ms`); console.log(` Proof size: ${proof.proof.length} bytes`); console.log(` Verification key: ${compiled.verificationKeySize} bytes`); console.log(''); } console.log('Summary:'); console.log(' Groth16: Smallest proofs, fast verification, trusted setup required'); console.log(' PLONK: Universal setup, flexible, moderate proof size'); console.log(' STARK: No trusted setup, largest proofs, quantum resistant'); console.log(''); } /** * Recursive proof aggregation */ async function recursiveProofExample(zk: SynorZk): Promise { console.log('=== 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 const inner = await zk.circuits.compile({ code: innerCircuit, format: CircuitFormat.Circom, name: 'inner_circuit', provingSystem: ProvingSystem.Groth16, }); // Generate multiple proofs to aggregate console.log('Generating proofs to aggregate...'); const proofsToAggregate = []; for (let i = 1; i <= 4; i++) { const proof = await zk.proofs.generate({ circuitId: inner.circuitId, inputs: { x: i.toString() }, }); proofsToAggregate.push({ proof: proof.proof, publicSignals: proof.publicSignals, }); console.log(` Proof ${i}: y = ${proof.publicSignals[0]}`); } // Aggregate proofs recursively console.log('\nAggregating proofs...'); const aggregated = await zk.proofs.aggregate({ circuitId: inner.circuitId, proofs: proofsToAggregate, aggregationType: 'recursive', }); console.log(`Aggregated proof:`); console.log(` Proof ID: ${aggregated.proofId}`); console.log(` Aggregated count: ${aggregated.aggregatedCount}`); console.log(` Proof size: ${aggregated.proof.length} bytes`); console.log(` Size reduction: ${(1 - aggregated.proof.length / (proofsToAggregate.length * proofsToAggregate[0].proof.length)) * 100}%`); // Verify aggregated proof const isValid = await zk.proofs.verifyAggregated({ circuitId: inner.circuitId, proof: aggregated.proof, publicSignalsList: proofsToAggregate.map(p => p.publicSignals), }); console.log(`\nAggregated proof valid: ${isValid}`); // Batch verification (verify multiple proofs in one operation) console.log('\nBatch verification...'); const batchResult = await zk.proofs.batchVerify({ circuitId: inner.circuitId, proofs: proofsToAggregate, }); console.log(` All valid: ${batchResult.allValid}`); console.log(` Results: ${batchResult.results.join(', ')}`); console.log(''); } /** * On-chain verification */ async function onChainVerificationExample(zk: SynorZk): Promise { console.log('=== 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(); `; const compiled = await zk.circuits.compile({ code: circuit, format: CircuitFormat.Circom, name: 'vote_commitment', provingSystem: ProvingSystem.Groth16, }); // Generate Solidity verifier console.log('Generating Solidity verifier...'); const solidityVerifier = await zk.contracts.generateVerifier({ circuitId: compiled.circuitId, language: 'solidity', optimized: true, }); console.log(`Solidity verifier generated: ${solidityVerifier.code.length} bytes`); console.log(` Contract name: ${solidityVerifier.contractName}`); console.log(` Gas estimate: ${solidityVerifier.gasEstimate}`); // Generate proof const proof = await zk.proofs.generate({ circuitId: compiled.circuitId, inputs: { vote: '1', // Vote YES (1) or NO (0) nullifier: '12345', commitment: '12345', // 1 * 12345 }, }); // Format proof for on-chain verification console.log('\nFormatting proof for on-chain...'); const onChainProof = await zk.contracts.formatProof({ circuitId: compiled.circuitId, proof: proof.proof, publicSignals: proof.publicSignals, format: 'calldata', }); console.log(` Calldata: ${onChainProof.calldata.slice(0, 100)}...`); console.log(` Estimated gas: ${onChainProof.gasEstimate}`); // Deploy verifier contract (simulation) console.log('\nDeploying verifier contract...'); const deployment = await zk.contracts.deployVerifier({ circuitId: compiled.circuitId, network: 'synor-testnet', }); console.log(` Contract address: ${deployment.address}`); console.log(` TX hash: ${deployment.txHash}`); console.log(` Gas used: ${deployment.gasUsed}`); // Verify on-chain console.log('\nVerifying on-chain...'); const onChainResult = await zk.contracts.verifyOnChain({ contractAddress: deployment.address, proof: proof.proof, publicSignals: proof.publicSignals, network: 'synor-testnet', }); console.log(` TX hash: ${onChainResult.txHash}`); console.log(` Verified: ${onChainResult.verified}`); console.log(` Gas used: ${onChainResult.gasUsed}`); // Generate verifier for other targets console.log('\nGenerating verifiers for other targets:'); const targets = ['cairo', 'noir', 'ink']; for (const target of targets) { const verifier = await zk.contracts.generateVerifier({ circuitId: compiled.circuitId, language: target, }); console.log(` ${target}: ${verifier.code.length} bytes`); } console.log(''); } /** * Trusted setup ceremonies */ async function setupExample(zk: SynorZk): Promise { console.log('=== Trusted Setup ==='); // Get available ceremonies const ceremonies = await zk.setup.listCeremonies(); console.log(`Active ceremonies: ${ceremonies.length}`); for (const ceremony of ceremonies) { console.log(` ${ceremony.name}:`); console.log(` Status: ${ceremony.status}`); console.log(` Participants: ${ceremony.participantCount}`); console.log(` 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(); `; console.log('\nInitializing setup for new circuit...'); const setup = await zk.setup.initialize({ circuit, format: CircuitFormat.Circom, name: 'new_circuit_setup', provingSystem: ProvingSystem.Groth16, ceremonyType: 'powers_of_tau', // or 'phase2' }); console.log(`Setup initialized:`); console.log(` Ceremony ID: ${setup.ceremonyId}`); console.log(` Powers of Tau required: ${setup.powersRequired}`); console.log(` Current phase: ${setup.phase}`); // Contribute to ceremony (in practice, generates random entropy) console.log('\nContributing to ceremony...'); const contribution = await zk.setup.contribute({ ceremonyId: setup.ceremonyId, entropy: Buffer.from('random-entropy-from-user').toString('hex'), }); console.log(`Contribution submitted:`); console.log(` Participant: ${contribution.participantId}`); console.log(` Contribution hash: ${contribution.hash}`); console.log(` Verification status: ${contribution.verified}`); // Get ceremony status const status = await zk.setup.getStatus(setup.ceremonyId); console.log(`\nCeremony status:`); console.log(` Phase: ${status.phase}`); console.log(` Total contributions: ${status.totalContributions}`); console.log(` Verified contributions: ${status.verifiedContributions}`); console.log(` Ready for finalization: ${status.readyForFinalization}`); // Finalize setup (when enough contributions) if (status.readyForFinalization) { console.log('\nFinalizing setup...'); const finalized = await zk.setup.finalize(setup.ceremonyId); console.log(`Setup finalized:`); console.log(` Proving key hash: ${finalized.provingKeyHash}`); console.log(` Verification key hash: ${finalized.verificationKeyHash}`); console.log(` Contribution transcript: ${finalized.transcriptCid}`); } // Download ceremony transcript const transcript = await zk.setup.getTranscript(setup.ceremonyId); console.log(`\nCeremony transcript: ${transcript.length} bytes`); console.log(''); } // Run examples main().catch(console.error);