package io.synor.examples import io.synor.zk.* import io.synor.zk.types.* import kotlinx.coroutines.runBlocking /** * Synor ZK SDK Examples for Kotlin * * Demonstrates zero-knowledge proof operations: * - Circuit compilation (Circom) * - Proof generation and verification * - Multiple proving systems (Groth16, PLONK, STARK) * - Recursive proof composition * - Trusted setup ceremonies */ fun main() = runBlocking { // Initialize client val config = ZkConfig( apiKey = System.getenv("SYNOR_API_KEY") ?: "your-api-key", endpoint = "https://zk.synor.io/v1", timeout = 120_000, // ZK operations can be slow retries = 3, debug = false, defaultProvingSystem = ProvingSystem.GROTH16, proveTimeout = 300_000, verifyTimeout = 30_000 ) val zk = SynorZk(config) try { // Check service health val healthy = zk.healthCheck() println("Service healthy: $healthy\n") // Run examples circuitExample(zk) groth16Example(zk) plonkExample(zk) starkExample(zk) recursiveExample(zk) ceremonyExample(zk) } finally { zk.close() } } suspend fun circuitExample(zk: SynorZk) { println("=== Circuit Compilation ===") // Simple Circom circuit: prove knowledge of factors val circomCode = """ pragma circom 2.1.0; template Multiplier() { signal input a; signal input b; signal output c; c <== a * b; } component main = Multiplier(); """.trimIndent() // Compile the circuit println("Compiling circuit...") val circuit = zk.circuits.compile( CircuitSource( code = circomCode, language = CircuitLanguage.CIRCOM ) ) println("Circuit compiled:") println(" Circuit ID: ${circuit.circuitId}") println(" Constraints: ${circuit.constraints}") println(" Public inputs: ${circuit.publicInputs}") println(" Private inputs: ${circuit.privateInputs}") println(" Outputs: ${circuit.outputs}") // Get circuit info val info = zk.circuits.get(circuit.circuitId) println("\nCircuit info:") println(" Name: ${info.name}") println(" Version: ${info.version}") println(" Wires: ${info.wireCount}") println(" Labels: ${info.labelCount}") // List available circuits val circuits = zk.circuits.list() println("\nAvailable circuits: ${circuits.size}") circuits.take(3).forEach { c -> println(" ${c.circuitId}: ${c.name} (${c.constraints} constraints)") } println() } suspend fun groth16Example(zk: SynorZk) { println("=== Groth16 Proving System ===") // Use a pre-compiled circuit val circuitId = "multiplier-v1" // Generate proving/verification keys (trusted setup) println("Generating keys...") val keys = zk.groth16.setup(circuitId) println("Keys generated:") println(" Proving key size: ${keys.provingKey.size} bytes") println(" Verification key size: ${keys.verificationKey.size} bytes") // Prepare witness (private inputs) val witness = mapOf( "a" to "3", "b" to "7" ) // Generate proof println("\nGenerating proof...") val proof = zk.groth16.prove( ProveRequest( circuitId = circuitId, witness = witness, provingKey = keys.provingKey ) ) println("Proof generated:") println(" Proof size: ${proof.proofBytes.size} bytes") println(" Public signals: ${proof.publicSignals}") println(" Proving time: ${proof.provingTimeMs}ms") // Verify proof println("\nVerifying proof...") val verified = zk.groth16.verify( VerifyRequest( proof = proof.proofBytes, publicSignals = proof.publicSignals, verificationKey = keys.verificationKey ) ) println("Verification result: $verified") // Export proof for on-chain verification val solidityCalldata = zk.groth16.exportCalldata(proof) println("\nSolidity calldata: ${solidityCalldata.take(100)}...") println() } suspend fun plonkExample(zk: SynorZk) { println("=== PLONK Proving System ===") val circuitId = "multiplier-v1" // PLONK uses universal trusted setup println("Getting universal setup...") val srs = zk.plonk.getUniversalSetup(powersOfTau = 14) // 2^14 constraints println("SRS loaded: ${srs.size} bytes") // Generate circuit-specific keys println("\nGenerating circuit keys...") val keys = zk.plonk.setup(circuitId, srs) println("Keys generated") // Generate proof val witness = mapOf("a" to "5", "b" to "9") println("\nGenerating PLONK proof...") val proof = zk.plonk.prove( PlonkProveRequest( circuitId = circuitId, witness = witness, provingKey = keys.provingKey ) ) println("Proof generated:") println(" Proof size: ${proof.proofBytes.size} bytes") println(" Proving time: ${proof.provingTimeMs}ms") // Verify proof val verified = zk.plonk.verify( PlonkVerifyRequest( proof = proof.proofBytes, publicSignals = proof.publicSignals, verificationKey = keys.verificationKey ) ) println("Verification result: $verified") // Compare with Groth16 println("\nPLONK advantages:") println(" - Universal trusted setup") println(" - Larger proofs (~2.5 KB vs ~200 bytes)") println(" - Faster proving for some circuits") println() } suspend fun starkExample(zk: SynorZk) { println("=== STARK Proving System ===") val circuitId = "multiplier-v1" // STARKs don't need trusted setup println("Configuring STARK parameters...") val config = StarkConfig( fieldSize = 256, hashFunction = HashFunction.POSEIDON, blowupFactor = 8, numQueries = 30, foldingFactor = 8 ) // Generate proof val witness = mapOf("a" to "11", "b" to "13") println("\nGenerating STARK proof...") val proof = zk.stark.prove( StarkProveRequest( circuitId = circuitId, witness = witness, config = config ) ) println("Proof generated:") println(" Proof size: ${proof.proofBytes.size} bytes") println(" Proving time: ${proof.provingTimeMs}ms") println(" FRI layers: ${proof.friLayers}") // Verify proof println("\nVerifying STARK proof...") val verified = zk.stark.verify( StarkVerifyRequest( proof = proof.proofBytes, publicSignals = proof.publicSignals, config = config ) ) println("Verification result: $verified") // Compare with SNARKs println("\nSTARK advantages:") println(" - No trusted setup needed") println(" - Post-quantum secure") println(" - Larger proofs (~100 KB)") println(" - Faster proving for complex computations") println() } suspend fun recursiveExample(zk: SynorZk) { println("=== Recursive Proof Composition ===") // Create inner proofs println("Generating inner proofs...") val innerProofs = mutableListOf() for (i in 1..3) { val witness = mapOf("a" to i.toString(), "b" to (i + 1).toString()) val proof = zk.recursive.proveInner( RecursiveProveRequest( circuitId = "multiplier-v1", witness = witness, level = 0 ) ) innerProofs.add(proof) println(" Inner proof $i generated") } // Aggregate proofs recursively println("\nAggregating proofs...") val aggregatedProof = zk.recursive.aggregate( AggregateRequest( proofs = innerProofs, aggregationCircuit = "recursive-aggregator-v1" ) ) println("Aggregated proof:") println(" Proof size: ${aggregatedProof.proofBytes.size} bytes") println(" Proofs aggregated: ${aggregatedProof.proofsAggregated}") println(" Recursion depth: ${aggregatedProof.recursionDepth}") // Verify aggregated proof (verifies all inner proofs at once) println("\nVerifying aggregated proof...") val verified = zk.recursive.verifyAggregated(aggregatedProof) println("Verification result: $verified") // Use cases println("\nRecursive proof use cases:") println(" - Rollup batch verification") println(" - Incremental computation proofs") println(" - Cross-chain state proofs") println() } suspend fun ceremonyExample(zk: SynorZk) { println("=== Trusted Setup Ceremony ===") // List active ceremonies val ceremonies = zk.ceremony.list(status = CeremonyStatus.ACTIVE) println("Active ceremonies: ${ceremonies.size}") ceremonies.take(3).forEach { ceremony -> println("\n ${ceremony.ceremonyId}:") println(" Circuit: ${ceremony.circuitId}") println(" Participants: ${ceremony.participantCount}") println(" Current round: ${ceremony.currentRound}") println(" Status: ${ceremony.status}") } // Create a new ceremony println("\nCreating new ceremony...") val newCeremony = zk.ceremony.create( CeremonyConfig( circuitId = "new-circuit-v1", minParticipants = 10, maxParticipants = 100, roundDuration = 3600, // 1 hour per round verifyContributions = true ) ) println("Ceremony created:") println(" Ceremony ID: ${newCeremony.ceremonyId}") println(" Join URL: ${newCeremony.joinUrl}") // Participate in a ceremony println("\nParticipating in ceremony...") val contribution = zk.ceremony.contribute( ContributionRequest( ceremonyId = newCeremony.ceremonyId, entropy = generateEntropy() ) ) println("Contribution made:") println(" Contribution ID: ${contribution.contributionId}") println(" Position: ${contribution.position}") println(" Hash: ${contribution.hash}") // Verify a contribution println("\nVerifying contribution...") val valid = zk.ceremony.verifyContribution(contribution.contributionId) println("Contribution valid: $valid") // Get ceremony transcript (for auditability) val transcript = zk.ceremony.getTranscript(newCeremony.ceremonyId) println("\nCeremony transcript:") println(" Total contributions: ${transcript.contributions.size}") println(" Start time: ${transcript.startTime}") println(" Final hash: ${transcript.finalHash ?: "pending"}") println() } // Helper function to generate random entropy fun generateEntropy(): ByteArray { val entropy = ByteArray(32) java.security.SecureRandom().nextBytes(entropy) return entropy }