// Package main demonstrates the Synor ZK SDK for Go // // This example covers Zero-Knowledge proof operations: // - Circuit compilation // - Proof generation and verification // - Groth16, PLONK, and STARK proving systems // - Recursive proofs // - On-chain verification package main import ( "context" "fmt" "log" "os" "time" "github.com/synor/sdk-go/zk" ) func main() { // Initialize client config := zk.Config{ APIKey: getEnv("SYNOR_API_KEY", "your-api-key"), Endpoint: "https://zk.synor.io/v1", Timeout: 120 * time.Second, // ZK ops can be slow Retries: 3, Debug: false, DefaultProvingSystem: zk.ProvingSystemGroth16, } client, err := zk.NewClient(config) if err != nil { log.Fatalf("Failed to create client: %v", err) } defer client.Close() ctx := context.Background() // Check service health healthy, err := client.HealthCheck(ctx) if err != nil { log.Printf("Health check failed: %v", err) } else { fmt.Printf("Service healthy: %v\n\n", healthy) } // Run examples circuitExample(ctx, client) proofExample(ctx, client) provingSystemsExample(ctx, client) recursiveProofExample(ctx, client) onChainVerificationExample(ctx, client) setupExample(ctx, client) } func circuitExample(ctx context.Context, client *zk.Client) { fmt.Println("=== Circuit Compilation ===") // Circom circuit example: prove knowledge of preimage 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 fmt.Println("Compiling Circom circuit...") compiled, err := client.Circuits.Compile(ctx, &zk.CompileRequest{ Code: circomCircuit, Format: zk.CircuitFormatCircom, Name: "hash_preimage", ProvingSystem: zk.ProvingSystemGroth16, }) if err != nil { log.Printf("Failed to compile circuit: %v", err) return } fmt.Println("Circuit compiled:") fmt.Printf(" Circuit ID: %s\n", compiled.CircuitID) fmt.Printf(" Constraints: %d\n", compiled.ConstraintCount) fmt.Printf(" Public inputs: %d\n", compiled.PublicInputCount) fmt.Printf(" Private inputs: %d\n", compiled.PrivateInputCount) fmt.Printf(" Proving key size: %d bytes\n", compiled.ProvingKeySize) fmt.Printf(" Verification key size: %d bytes\n", compiled.VerificationKeySize) // List circuits circuits, err := client.Circuits.List(ctx) if err != nil { log.Printf("Failed to list circuits: %v", err) return } fmt.Printf("\nYour circuits: %d\n", len(circuits)) for _, circuit := range circuits { fmt.Printf(" %s (%s)\n", circuit.Name, circuit.CircuitID) } // Get circuit details details, err := client.Circuits.Get(ctx, compiled.CircuitID) if err != nil { log.Printf("Failed to get circuit details: %v", err) return } fmt.Println("\nCircuit details:") fmt.Printf(" Format: %s\n", details.Format) fmt.Printf(" Proving system: %s\n", details.ProvingSystem) fmt.Printf(" Created: %s\n", details.CreatedAt) // Download proving key provingKey, err := client.Circuits.GetProvingKey(ctx, compiled.CircuitID) if err != nil { log.Printf("Failed to get proving key: %v", err) return } fmt.Printf("\nProving key downloaded: %d bytes\n", len(provingKey)) // Download verification key verificationKey, err := client.Circuits.GetVerificationKey(ctx, compiled.CircuitID) if err != nil { log.Printf("Failed to get verification key: %v", err) return } fmt.Printf("Verification key downloaded: %d bytes\n", len(verificationKey)) fmt.Println() } func proofExample(ctx context.Context, client *zk.Client) { fmt.Println("=== Proof Generation ===") // First, compile a simple circuit 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(); ` compiled, err := client.Circuits.Compile(ctx, &zk.CompileRequest{ Code: circuit, Format: zk.CircuitFormatCircom, Name: "multiplier", ProvingSystem: zk.ProvingSystemGroth16, }) if err != nil { log.Printf("Failed to compile circuit: %v", err) return } // Generate proof fmt.Println("Generating proof...") startTime := time.Now() proof, err := client.Proofs.Generate(ctx, &zk.GenerateProofRequest{ CircuitID: compiled.CircuitID, Inputs: map[string]string{"a": "3", "b": "7"}, }) if err != nil { log.Printf("Failed to generate proof: %v", err) return } proofTime := time.Since(startTime) fmt.Printf("Proof generated in %v\n", proofTime) fmt.Printf(" Proof ID: %s\n", proof.ProofID) fmt.Printf(" Proof size: %d bytes\n", len(proof.Proof)) fmt.Printf(" Public signals: %v\n", proof.PublicSignals) // Verify proof fmt.Println("\nVerifying proof...") verifyStart := time.Now() isValid, err := client.Proofs.Verify(ctx, &zk.VerifyRequest{ CircuitID: compiled.CircuitID, Proof: proof.Proof, PublicSignals: proof.PublicSignals, }) if err != nil { log.Printf("Failed to verify proof: %v", err) return } verifyTime := time.Since(verifyStart) fmt.Printf("Verification completed in %v\n", verifyTime) fmt.Printf(" Valid: %v\n", isValid) // Verify with wrong public signals (should fail) fmt.Println("\nVerifying with wrong signals...") invalidResult, err := client.Proofs.Verify(ctx, &zk.VerifyRequest{ CircuitID: compiled.CircuitID, Proof: proof.Proof, PublicSignals: []string{"42"}, // Wrong answer }) if err != nil { log.Printf("Failed to verify with wrong signals: %v", err) return } fmt.Printf(" Valid: %v (expected false)\n", invalidResult) // Get proof status status, err := client.Proofs.GetStatus(ctx, proof.ProofID) if err != nil { log.Printf("Failed to get proof status: %v", err) return } fmt.Println("\nProof status:") fmt.Printf(" State: %s\n", status.State) fmt.Printf(" Verified: %v\n", status.Verified) fmt.Printf(" Created: %s\n", status.CreatedAt) // List proofs proofs, err := client.Proofs.List(ctx, compiled.CircuitID) if err != nil { log.Printf("Failed to list proofs: %v", err) return } fmt.Printf("\nProofs for circuit: %d\n", len(proofs)) fmt.Println() } func provingSystemsExample(ctx context.Context, client *zk.Client) { fmt.Println("=== Proving Systems Comparison ===") // Simple circuit for comparison 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(); ` systems := []struct { system zk.ProvingSystem name string }{ {zk.ProvingSystemGroth16, "GROTH16"}, {zk.ProvingSystemPLONK, "PLONK"}, {zk.ProvingSystemSTARK, "STARK"}, } fmt.Println("Comparing proving systems:\n") for _, s := range systems { fmt.Printf("%s:\n", s.name) // Compile for this system compiled, err := client.Circuits.Compile(ctx, &zk.CompileRequest{ Code: circuit, Format: zk.CircuitFormatCircom, Name: fmt.Sprintf("comparison_%s", s.name), ProvingSystem: s.system, }) if err != nil { log.Printf("Failed to compile for %s: %v", s.name, err) continue } // Generate proof proofStart := time.Now() proof, err := client.Proofs.Generate(ctx, &zk.GenerateProofRequest{ CircuitID: compiled.CircuitID, Inputs: map[string]string{"x": "10", "y": "20"}, }) if err != nil { log.Printf("Failed to generate proof for %s: %v", s.name, err) continue } proofTime := time.Since(proofStart) // Verify proof verifyStart := time.Now() _, err = client.Proofs.Verify(ctx, &zk.VerifyRequest{ CircuitID: compiled.CircuitID, Proof: proof.Proof, PublicSignals: proof.PublicSignals, }) if err != nil { log.Printf("Failed to verify proof for %s: %v", s.name, err) continue } verifyTime := time.Since(verifyStart) fmt.Printf(" Setup: %dms\n", compiled.SetupTime) fmt.Printf(" Proof time: %v\n", proofTime) fmt.Printf(" Verify time: %v\n", verifyTime) fmt.Printf(" Proof size: %d bytes\n", len(proof.Proof)) fmt.Printf(" Verification key: %d bytes\n", compiled.VerificationKeySize) fmt.Println() } fmt.Println("Summary:") fmt.Println(" Groth16: Smallest proofs, fast verification, trusted setup required") fmt.Println(" PLONK: Universal setup, flexible, moderate proof size") fmt.Println(" STARK: No trusted setup, largest proofs, quantum resistant") fmt.Println() } func recursiveProofExample(ctx context.Context, client *zk.Client) { fmt.Println("=== Recursive Proofs ===") // Inner circuit 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 inner, err := client.Circuits.Compile(ctx, &zk.CompileRequest{ Code: innerCircuit, Format: zk.CircuitFormatCircom, Name: "inner_circuit", ProvingSystem: zk.ProvingSystemGroth16, }) if err != nil { log.Printf("Failed to compile inner circuit: %v", err) return } // Generate multiple proofs to aggregate fmt.Println("Generating proofs to aggregate...") var proofsToAggregate []zk.ProofData for i := 1; i <= 4; i++ { proof, err := client.Proofs.Generate(ctx, &zk.GenerateProofRequest{ CircuitID: inner.CircuitID, Inputs: map[string]string{"x": fmt.Sprintf("%d", i)}, }) if err != nil { log.Printf("Failed to generate proof %d: %v", i, err) continue } proofsToAggregate = append(proofsToAggregate, zk.ProofData{ Proof: proof.Proof, PublicSignals: proof.PublicSignals, }) fmt.Printf(" Proof %d: y = %s\n", i, proof.PublicSignals[0]) } // Aggregate proofs recursively fmt.Println("\nAggregating proofs...") aggregated, err := client.Proofs.Aggregate(ctx, &zk.AggregateRequest{ CircuitID: inner.CircuitID, Proofs: proofsToAggregate, AggregationType: "recursive", }) if err != nil { log.Printf("Failed to aggregate proofs: %v", err) return } originalSize := 0 for _, p := range proofsToAggregate { originalSize += len(p.Proof) } fmt.Println("Aggregated proof:") fmt.Printf(" Proof ID: %s\n", aggregated.ProofID) fmt.Printf(" Aggregated count: %d\n", aggregated.AggregatedCount) fmt.Printf(" Proof size: %d bytes\n", len(aggregated.Proof)) fmt.Printf(" Size reduction: %.1f%%\n", (1-float64(len(aggregated.Proof))/float64(originalSize))*100) // Verify aggregated proof publicSignalsList := make([][]string, len(proofsToAggregate)) for i, p := range proofsToAggregate { publicSignalsList[i] = p.PublicSignals } isValid, err := client.Proofs.VerifyAggregated(ctx, &zk.VerifyAggregatedRequest{ CircuitID: inner.CircuitID, Proof: aggregated.Proof, PublicSignalsList: publicSignalsList, }) if err != nil { log.Printf("Failed to verify aggregated proof: %v", err) return } fmt.Printf("\nAggregated proof valid: %v\n", isValid) // Batch verification (verify multiple proofs in one operation) fmt.Println("\nBatch verification...") batchResult, err := client.Proofs.BatchVerify(ctx, &zk.BatchVerifyRequest{ CircuitID: inner.CircuitID, Proofs: proofsToAggregate, }) if err != nil { log.Printf("Failed to batch verify: %v", err) return } fmt.Printf(" All valid: %v\n", batchResult.AllValid) fmt.Printf(" Results: %v\n", batchResult.Results) fmt.Println() } func onChainVerificationExample(ctx context.Context, client *zk.Client) { fmt.Println("=== On-Chain Verification ===") // Compile circuit 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(); ` compiled, err := client.Circuits.Compile(ctx, &zk.CompileRequest{ Code: circuit, Format: zk.CircuitFormatCircom, Name: "vote_commitment", ProvingSystem: zk.ProvingSystemGroth16, }) if err != nil { log.Printf("Failed to compile circuit: %v", err) return } // Generate Solidity verifier fmt.Println("Generating Solidity verifier...") solidityVerifier, err := client.Contracts.GenerateVerifier(ctx, &zk.GenerateVerifierRequest{ CircuitID: compiled.CircuitID, Language: "solidity", Optimized: true, }) if err != nil { log.Printf("Failed to generate verifier: %v", err) return } fmt.Printf("Solidity verifier generated: %d bytes\n", len(solidityVerifier.Code)) fmt.Printf(" Contract name: %s\n", solidityVerifier.ContractName) fmt.Printf(" Gas estimate: %d\n", solidityVerifier.GasEstimate) // Generate proof proof, err := client.Proofs.Generate(ctx, &zk.GenerateProofRequest{ CircuitID: compiled.CircuitID, Inputs: map[string]string{ "vote": "1", // Vote YES (1) or NO (0) "nullifier": "12345", "commitment": "12345", // 1 * 12345 }, }) if err != nil { log.Printf("Failed to generate proof: %v", err) return } // Format proof for on-chain verification fmt.Println("\nFormatting proof for on-chain...") onChainProof, err := client.Contracts.FormatProof(ctx, &zk.FormatProofRequest{ CircuitID: compiled.CircuitID, Proof: proof.Proof, PublicSignals: proof.PublicSignals, Format: "calldata", }) if err != nil { log.Printf("Failed to format proof: %v", err) return } calldataPreview := onChainProof.Calldata if len(calldataPreview) > 100 { calldataPreview = calldataPreview[:100] } fmt.Printf(" Calldata: %s...\n", calldataPreview) fmt.Printf(" Estimated gas: %d\n", onChainProof.GasEstimate) // Deploy verifier contract (simulation) fmt.Println("\nDeploying verifier contract...") deployment, err := client.Contracts.DeployVerifier(ctx, &zk.DeployRequest{ CircuitID: compiled.CircuitID, Network: "synor-testnet", }) if err != nil { log.Printf("Failed to deploy verifier: %v", err) return } fmt.Printf(" Contract address: %s\n", deployment.Address) fmt.Printf(" TX hash: %s\n", deployment.TxHash) fmt.Printf(" Gas used: %d\n", deployment.GasUsed) // Verify on-chain fmt.Println("\nVerifying on-chain...") onChainResult, err := client.Contracts.VerifyOnChain(ctx, &zk.OnChainVerifyRequest{ ContractAddress: deployment.Address, Proof: proof.Proof, PublicSignals: proof.PublicSignals, Network: "synor-testnet", }) if err != nil { log.Printf("Failed to verify on-chain: %v", err) return } fmt.Printf(" TX hash: %s\n", onChainResult.TxHash) fmt.Printf(" Verified: %v\n", onChainResult.Verified) fmt.Printf(" Gas used: %d\n", onChainResult.GasUsed) // Generate verifier for other targets fmt.Println("\nGenerating verifiers for other targets:") targets := []string{"cairo", "noir", "ink"} for _, target := range targets { verifier, err := client.Contracts.GenerateVerifier(ctx, &zk.GenerateVerifierRequest{ CircuitID: compiled.CircuitID, Language: target, }) if err != nil { log.Printf("Failed to generate %s verifier: %v", target, err) continue } fmt.Printf(" %s: %d bytes\n", target, len(verifier.Code)) } fmt.Println() } func setupExample(ctx context.Context, client *zk.Client) { fmt.Println("=== Trusted Setup ===") // Get available ceremonies ceremonies, err := client.Setup.ListCeremonies(ctx) if err != nil { log.Printf("Failed to list ceremonies: %v", err) return } fmt.Printf("Active ceremonies: %d\n", len(ceremonies)) for _, ceremony := range ceremonies { fmt.Printf(" %s:\n", ceremony.Name) fmt.Printf(" Status: %s\n", ceremony.Status) fmt.Printf(" Participants: %d\n", ceremony.ParticipantCount) fmt.Printf(" Current round: %d\n", ceremony.CurrentRound) } // Create a new circuit setup circuit := ` pragma circom 2.1.0; template NewCircuit() { signal input a; signal output b; b <== a + 1; } component main {public [b]} = NewCircuit(); ` fmt.Println("\nInitializing setup for new circuit...") setup, err := client.Setup.Initialize(ctx, &zk.SetupInitRequest{ Circuit: circuit, Format: zk.CircuitFormatCircom, Name: "new_circuit_setup", ProvingSystem: zk.ProvingSystemGroth16, CeremonyType: "powers_of_tau", // or 'phase2' }) if err != nil { log.Printf("Failed to initialize setup: %v", err) return } fmt.Println("Setup initialized:") fmt.Printf(" Ceremony ID: %s\n", setup.CeremonyID) fmt.Printf(" Powers of Tau required: %d\n", setup.PowersRequired) fmt.Printf(" Current phase: %s\n", setup.Phase) // Contribute to ceremony (in practice, generates random entropy) fmt.Println("\nContributing to ceremony...") contribution, err := client.Setup.Contribute(ctx, &zk.ContributeRequest{ CeremonyID: setup.CeremonyID, Entropy: fmt.Sprintf("%x", []byte("random-entropy-from-user")), }) if err != nil { log.Printf("Failed to contribute: %v", err) return } fmt.Println("Contribution submitted:") fmt.Printf(" Participant: %s\n", contribution.ParticipantID) fmt.Printf(" Contribution hash: %s\n", contribution.Hash) fmt.Printf(" Verification status: %v\n", contribution.Verified) // Get ceremony status status, err := client.Setup.GetStatus(ctx, setup.CeremonyID) if err != nil { log.Printf("Failed to get ceremony status: %v", err) return } fmt.Println("\nCeremony status:") fmt.Printf(" Phase: %s\n", status.Phase) fmt.Printf(" Total contributions: %d\n", status.TotalContributions) fmt.Printf(" Verified contributions: %d\n", status.VerifiedContributions) fmt.Printf(" Ready for finalization: %v\n", status.ReadyForFinalization) // Finalize setup (when enough contributions) if status.ReadyForFinalization { fmt.Println("\nFinalizing setup...") finalized, err := client.Setup.Finalize(ctx, setup.CeremonyID) if err != nil { log.Printf("Failed to finalize setup: %v", err) return } fmt.Println("Setup finalized:") fmt.Printf(" Proving key hash: %s\n", finalized.ProvingKeyHash) fmt.Printf(" Verification key hash: %s\n", finalized.VerificationKeyHash) fmt.Printf(" Contribution transcript: %s\n", finalized.TranscriptCID) } // Download ceremony transcript transcript, err := client.Setup.GetTranscript(ctx, setup.CeremonyID) if err != nil { log.Printf("Failed to get transcript: %v", err) return } fmt.Printf("\nCeremony transcript: %d bytes\n", len(transcript)) fmt.Println() } func getEnv(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue }