- Introduced DexExample.swift demonstrating decentralized exchange operations including spot trading, perpetual futures, liquidity provision, order book management, and portfolio tracking. - Added IbcExample.swift showcasing inter-blockchain communication operations such as cross-chain transfers, channel management, packet handling, and relayer operations. - Created ZkExample.swift illustrating zero-knowledge proof operations including circuit compilation, proof generation and verification, and trusted setup ceremonies.
537 lines
21 KiB
Java
537 lines
21 KiB
Java
package io.synor.examples;
|
|
|
|
import io.synor.zk.*;
|
|
import io.synor.zk.types.*;
|
|
|
|
import java.util.*;
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
/**
|
|
* Synor ZK SDK Examples for Java
|
|
*
|
|
* Demonstrates Zero-Knowledge proof operations:
|
|
* - Circuit compilation
|
|
* - Proof generation and verification
|
|
* - Groth16, PLONK, and STARK proving systems
|
|
* - Recursive proofs
|
|
* - On-chain verification
|
|
*/
|
|
public class ZkExample {
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
// Initialize client
|
|
ZkConfig config = ZkConfig.builder()
|
|
.apiKey(System.getenv("SYNOR_API_KEY") != null ?
|
|
System.getenv("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)
|
|
.build();
|
|
|
|
SynorZk zk = new SynorZk(config);
|
|
|
|
try {
|
|
// Check service health
|
|
boolean healthy = zk.healthCheck().get();
|
|
System.out.println("Service healthy: " + healthy + "\n");
|
|
|
|
// Run examples
|
|
circuitExample(zk);
|
|
proofExample(zk);
|
|
provingSystemsExample(zk);
|
|
recursiveProofExample(zk);
|
|
onChainVerificationExample(zk);
|
|
setupExample(zk);
|
|
} finally {
|
|
zk.close();
|
|
}
|
|
}
|
|
|
|
static void circuitExample(SynorZk zk) throws Exception {
|
|
System.out.println("=== Circuit Compilation ===");
|
|
|
|
// Circom circuit example: prove knowledge of preimage
|
|
String 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
|
|
System.out.println("Compiling Circom circuit...");
|
|
CompiledCircuit compiled = zk.circuits().compile(CompileRequest.builder()
|
|
.code(circomCircuit)
|
|
.format(CircuitFormat.CIRCOM)
|
|
.name("hash_preimage")
|
|
.provingSystem(ProvingSystem.GROTH16)
|
|
.build()).get();
|
|
|
|
System.out.println("Circuit compiled:");
|
|
System.out.println(" Circuit ID: " + compiled.getCircuitId());
|
|
System.out.println(" Constraints: " + compiled.getConstraintCount());
|
|
System.out.println(" Public inputs: " + compiled.getPublicInputCount());
|
|
System.out.println(" Private inputs: " + compiled.getPrivateInputCount());
|
|
System.out.println(" Proving key size: " + compiled.getProvingKeySize() + " bytes");
|
|
System.out.println(" Verification key size: " + compiled.getVerificationKeySize() + " bytes");
|
|
|
|
// List circuits
|
|
List<Circuit> circuits = zk.circuits().list().get();
|
|
System.out.println("\nYour circuits: " + circuits.size());
|
|
for (Circuit circuit : circuits) {
|
|
System.out.println(" " + circuit.getName() + " (" + circuit.getCircuitId() + ")");
|
|
}
|
|
|
|
// Get circuit details
|
|
CircuitDetails details = zk.circuits().get(compiled.getCircuitId()).get();
|
|
System.out.println("\nCircuit details:");
|
|
System.out.println(" Format: " + details.getFormat());
|
|
System.out.println(" Proving system: " + details.getProvingSystem());
|
|
System.out.println(" Created: " + details.getCreatedAt());
|
|
|
|
// Download proving key
|
|
byte[] provingKey = zk.circuits().getProvingKey(compiled.getCircuitId()).get();
|
|
System.out.println("\nProving key downloaded: " + provingKey.length + " bytes");
|
|
|
|
// Download verification key
|
|
byte[] verificationKey = zk.circuits().getVerificationKey(compiled.getCircuitId()).get();
|
|
System.out.println("Verification key downloaded: " + verificationKey.length + " bytes");
|
|
|
|
System.out.println();
|
|
}
|
|
|
|
static void proofExample(SynorZk zk) throws Exception {
|
|
System.out.println("=== Proof Generation ===");
|
|
|
|
// First, compile a simple circuit
|
|
String 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();
|
|
""";
|
|
|
|
CompiledCircuit compiled = zk.circuits().compile(CompileRequest.builder()
|
|
.code(circuit)
|
|
.format(CircuitFormat.CIRCOM)
|
|
.name("multiplier")
|
|
.provingSystem(ProvingSystem.GROTH16)
|
|
.build()).get();
|
|
|
|
// Generate proof
|
|
System.out.println("Generating proof...");
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
Map<String, String> inputs = new HashMap<>();
|
|
inputs.put("a", "3");
|
|
inputs.put("b", "7");
|
|
|
|
Proof proof = zk.proofs().generate(GenerateProofRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.inputs(inputs)
|
|
.build()).get();
|
|
|
|
long proofTime = System.currentTimeMillis() - startTime;
|
|
System.out.println("Proof generated in " + proofTime + "ms");
|
|
System.out.println(" Proof ID: " + proof.getProofId());
|
|
System.out.println(" Proof size: " + proof.getProof().length() + " bytes");
|
|
System.out.println(" Public signals: " + proof.getPublicSignals());
|
|
|
|
// Verify proof
|
|
System.out.println("\nVerifying proof...");
|
|
long verifyStart = System.currentTimeMillis();
|
|
|
|
boolean isValid = zk.proofs().verify(VerifyRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.proof(proof.getProof())
|
|
.publicSignals(proof.getPublicSignals())
|
|
.build()).get();
|
|
|
|
long verifyTime = System.currentTimeMillis() - verifyStart;
|
|
System.out.println("Verification completed in " + verifyTime + "ms");
|
|
System.out.println(" Valid: " + isValid);
|
|
|
|
// Verify with wrong public signals (should fail)
|
|
System.out.println("\nVerifying with wrong signals...");
|
|
boolean invalidResult = zk.proofs().verify(VerifyRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.proof(proof.getProof())
|
|
.publicSignals(List.of("42")) // Wrong answer
|
|
.build()).get();
|
|
System.out.println(" Valid: " + invalidResult + " (expected false)");
|
|
|
|
// Get proof status
|
|
ProofStatus status = zk.proofs().getStatus(proof.getProofId()).get();
|
|
System.out.println("\nProof status:");
|
|
System.out.println(" State: " + status.getState());
|
|
System.out.println(" Verified: " + status.isVerified());
|
|
System.out.println(" Created: " + status.getCreatedAt());
|
|
|
|
// List proofs
|
|
List<ProofInfo> proofs = zk.proofs().list(compiled.getCircuitId()).get();
|
|
System.out.println("\nProofs for circuit: " + proofs.size());
|
|
|
|
System.out.println();
|
|
}
|
|
|
|
static void provingSystemsExample(SynorZk zk) throws Exception {
|
|
System.out.println("=== Proving Systems Comparison ===");
|
|
|
|
// Simple circuit for comparison
|
|
String 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();
|
|
""";
|
|
|
|
ProvingSystem[] systems = {
|
|
ProvingSystem.GROTH16,
|
|
ProvingSystem.PLONK,
|
|
ProvingSystem.STARK
|
|
};
|
|
|
|
System.out.println("Comparing proving systems:\n");
|
|
|
|
for (ProvingSystem system : systems) {
|
|
System.out.println(system + ":");
|
|
|
|
// Compile for this system
|
|
CompiledCircuit compiled = zk.circuits().compile(CompileRequest.builder()
|
|
.code(circuit)
|
|
.format(CircuitFormat.CIRCOM)
|
|
.name("comparison_" + system.toString().toLowerCase())
|
|
.provingSystem(system)
|
|
.build()).get();
|
|
|
|
// Generate proof
|
|
long proofStart = System.currentTimeMillis();
|
|
Map<String, String> inputs = new HashMap<>();
|
|
inputs.put("x", "10");
|
|
inputs.put("y", "20");
|
|
|
|
Proof proof = zk.proofs().generate(GenerateProofRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.inputs(inputs)
|
|
.build()).get();
|
|
long proofTime = System.currentTimeMillis() - proofStart;
|
|
|
|
// Verify proof
|
|
long verifyStart = System.currentTimeMillis();
|
|
zk.proofs().verify(VerifyRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.proof(proof.getProof())
|
|
.publicSignals(proof.getPublicSignals())
|
|
.build()).get();
|
|
long verifyTime = System.currentTimeMillis() - verifyStart;
|
|
|
|
System.out.println(" Setup: " + compiled.getSetupTime() + "ms");
|
|
System.out.println(" Proof time: " + proofTime + "ms");
|
|
System.out.println(" Verify time: " + verifyTime + "ms");
|
|
System.out.println(" Proof size: " + proof.getProof().length() + " bytes");
|
|
System.out.println(" Verification key: " + compiled.getVerificationKeySize() + " bytes");
|
|
System.out.println();
|
|
}
|
|
|
|
System.out.println("Summary:");
|
|
System.out.println(" Groth16: Smallest proofs, fast verification, trusted setup required");
|
|
System.out.println(" PLONK: Universal setup, flexible, moderate proof size");
|
|
System.out.println(" STARK: No trusted setup, largest proofs, quantum resistant");
|
|
|
|
System.out.println();
|
|
}
|
|
|
|
static void recursiveProofExample(SynorZk zk) throws Exception {
|
|
System.out.println("=== Recursive Proofs ===");
|
|
|
|
// Inner circuit
|
|
String 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
|
|
CompiledCircuit inner = zk.circuits().compile(CompileRequest.builder()
|
|
.code(innerCircuit)
|
|
.format(CircuitFormat.CIRCOM)
|
|
.name("inner_circuit")
|
|
.provingSystem(ProvingSystem.GROTH16)
|
|
.build()).get();
|
|
|
|
// Generate multiple proofs to aggregate
|
|
System.out.println("Generating proofs to aggregate...");
|
|
List<ProofData> proofsToAggregate = new ArrayList<>();
|
|
for (int i = 1; i <= 4; i++) {
|
|
Map<String, String> inputs = new HashMap<>();
|
|
inputs.put("x", String.valueOf(i));
|
|
|
|
Proof proof = zk.proofs().generate(GenerateProofRequest.builder()
|
|
.circuitId(inner.getCircuitId())
|
|
.inputs(inputs)
|
|
.build()).get();
|
|
|
|
proofsToAggregate.add(ProofData.builder()
|
|
.proof(proof.getProof())
|
|
.publicSignals(proof.getPublicSignals())
|
|
.build());
|
|
System.out.println(" Proof " + i + ": y = " + proof.getPublicSignals().get(0));
|
|
}
|
|
|
|
// Aggregate proofs recursively
|
|
System.out.println("\nAggregating proofs...");
|
|
AggregatedProof aggregated = zk.proofs().aggregate(AggregateRequest.builder()
|
|
.circuitId(inner.getCircuitId())
|
|
.proofs(proofsToAggregate)
|
|
.aggregationType("recursive")
|
|
.build()).get();
|
|
|
|
int originalSize = proofsToAggregate.stream()
|
|
.mapToInt(p -> p.getProof().length())
|
|
.sum();
|
|
|
|
System.out.println("Aggregated proof:");
|
|
System.out.println(" Proof ID: " + aggregated.getProofId());
|
|
System.out.println(" Aggregated count: " + aggregated.getAggregatedCount());
|
|
System.out.println(" Proof size: " + aggregated.getProof().length() + " bytes");
|
|
System.out.println(" Size reduction: " +
|
|
String.format("%.1f", (1 - (double) aggregated.getProof().length() / originalSize) * 100) + "%");
|
|
|
|
// Verify aggregated proof
|
|
List<List<String>> publicSignalsList = proofsToAggregate.stream()
|
|
.map(ProofData::getPublicSignals)
|
|
.toList();
|
|
|
|
boolean isValid = zk.proofs().verifyAggregated(VerifyAggregatedRequest.builder()
|
|
.circuitId(inner.getCircuitId())
|
|
.proof(aggregated.getProof())
|
|
.publicSignalsList(publicSignalsList)
|
|
.build()).get();
|
|
System.out.println("\nAggregated proof valid: " + isValid);
|
|
|
|
// Batch verification
|
|
System.out.println("\nBatch verification...");
|
|
BatchVerifyResult batchResult = zk.proofs().batchVerify(BatchVerifyRequest.builder()
|
|
.circuitId(inner.getCircuitId())
|
|
.proofs(proofsToAggregate)
|
|
.build()).get();
|
|
System.out.println(" All valid: " + batchResult.isAllValid());
|
|
System.out.println(" Results: " + batchResult.getResults());
|
|
|
|
System.out.println();
|
|
}
|
|
|
|
static void onChainVerificationExample(SynorZk zk) throws Exception {
|
|
System.out.println("=== On-Chain Verification ===");
|
|
|
|
// Compile circuit
|
|
String circuit = """
|
|
pragma circom 2.1.0;
|
|
|
|
template VoteCommitment() {
|
|
signal input vote;
|
|
signal input nullifier;
|
|
signal input commitment;
|
|
|
|
signal computed;
|
|
computed <== vote * nullifier;
|
|
commitment === computed;
|
|
}
|
|
|
|
component main {public [commitment]} = VoteCommitment();
|
|
""";
|
|
|
|
CompiledCircuit compiled = zk.circuits().compile(CompileRequest.builder()
|
|
.code(circuit)
|
|
.format(CircuitFormat.CIRCOM)
|
|
.name("vote_commitment")
|
|
.provingSystem(ProvingSystem.GROTH16)
|
|
.build()).get();
|
|
|
|
// Generate Solidity verifier
|
|
System.out.println("Generating Solidity verifier...");
|
|
GeneratedVerifier solidityVerifier = zk.contracts().generateVerifier(GenerateVerifierRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.language("solidity")
|
|
.optimized(true)
|
|
.build()).get();
|
|
System.out.println("Solidity verifier generated: " + solidityVerifier.getCode().length() + " bytes");
|
|
System.out.println(" Contract name: " + solidityVerifier.getContractName());
|
|
System.out.println(" Gas estimate: " + solidityVerifier.getGasEstimate());
|
|
|
|
// Generate proof
|
|
Map<String, String> inputs = new HashMap<>();
|
|
inputs.put("vote", "1");
|
|
inputs.put("nullifier", "12345");
|
|
inputs.put("commitment", "12345");
|
|
|
|
Proof proof = zk.proofs().generate(GenerateProofRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.inputs(inputs)
|
|
.build()).get();
|
|
|
|
// Format proof for on-chain verification
|
|
System.out.println("\nFormatting proof for on-chain...");
|
|
FormattedProof onChainProof = zk.contracts().formatProof(FormatProofRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.proof(proof.getProof())
|
|
.publicSignals(proof.getPublicSignals())
|
|
.format("calldata")
|
|
.build()).get();
|
|
String calldataPreview = onChainProof.getCalldata().substring(0,
|
|
Math.min(100, onChainProof.getCalldata().length()));
|
|
System.out.println(" Calldata: " + calldataPreview + "...");
|
|
System.out.println(" Estimated gas: " + onChainProof.getGasEstimate());
|
|
|
|
// Deploy verifier contract
|
|
System.out.println("\nDeploying verifier contract...");
|
|
Deployment deployment = zk.contracts().deployVerifier(DeployRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.network("synor-testnet")
|
|
.build()).get();
|
|
System.out.println(" Contract address: " + deployment.getAddress());
|
|
System.out.println(" TX hash: " + deployment.getTxHash());
|
|
System.out.println(" Gas used: " + deployment.getGasUsed());
|
|
|
|
// Verify on-chain
|
|
System.out.println("\nVerifying on-chain...");
|
|
OnChainVerifyResult onChainResult = zk.contracts().verifyOnChain(OnChainVerifyRequest.builder()
|
|
.contractAddress(deployment.getAddress())
|
|
.proof(proof.getProof())
|
|
.publicSignals(proof.getPublicSignals())
|
|
.network("synor-testnet")
|
|
.build()).get();
|
|
System.out.println(" TX hash: " + onChainResult.getTxHash());
|
|
System.out.println(" Verified: " + onChainResult.isVerified());
|
|
System.out.println(" Gas used: " + onChainResult.getGasUsed());
|
|
|
|
// Generate verifier for other targets
|
|
System.out.println("\nGenerating verifiers for other targets:");
|
|
String[] targets = {"cairo", "noir", "ink"};
|
|
for (String target : targets) {
|
|
GeneratedVerifier verifier = zk.contracts().generateVerifier(GenerateVerifierRequest.builder()
|
|
.circuitId(compiled.getCircuitId())
|
|
.language(target)
|
|
.build()).get();
|
|
System.out.println(" " + target + ": " + verifier.getCode().length() + " bytes");
|
|
}
|
|
|
|
System.out.println();
|
|
}
|
|
|
|
static void setupExample(SynorZk zk) throws Exception {
|
|
System.out.println("=== Trusted Setup ===");
|
|
|
|
// Get available ceremonies
|
|
List<Ceremony> ceremonies = zk.setup().listCeremonies().get();
|
|
System.out.println("Active ceremonies: " + ceremonies.size());
|
|
for (Ceremony ceremony : ceremonies) {
|
|
System.out.println(" " + ceremony.getName() + ":");
|
|
System.out.println(" Status: " + ceremony.getStatus());
|
|
System.out.println(" Participants: " + ceremony.getParticipantCount());
|
|
System.out.println(" Current round: " + ceremony.getCurrentRound());
|
|
}
|
|
|
|
// Create a new circuit setup
|
|
String circuit = """
|
|
pragma circom 2.1.0;
|
|
|
|
template NewCircuit() {
|
|
signal input a;
|
|
signal output b;
|
|
b <== a + 1;
|
|
}
|
|
|
|
component main {public [b]} = NewCircuit();
|
|
""";
|
|
|
|
System.out.println("\nInitializing setup for new circuit...");
|
|
SetupResult setup = zk.setup().initialize(SetupInitRequest.builder()
|
|
.circuit(circuit)
|
|
.format(CircuitFormat.CIRCOM)
|
|
.name("new_circuit_setup")
|
|
.provingSystem(ProvingSystem.GROTH16)
|
|
.ceremonyType("powers_of_tau")
|
|
.build()).get();
|
|
System.out.println("Setup initialized:");
|
|
System.out.println(" Ceremony ID: " + setup.getCeremonyId());
|
|
System.out.println(" Powers of Tau required: " + setup.getPowersRequired());
|
|
System.out.println(" Current phase: " + setup.getPhase());
|
|
|
|
// Contribute to ceremony
|
|
System.out.println("\nContributing to ceremony...");
|
|
Contribution contribution = zk.setup().contribute(ContributeRequest.builder()
|
|
.ceremonyId(setup.getCeremonyId())
|
|
.entropy(bytesToHex("random-entropy-from-user".getBytes()))
|
|
.build()).get();
|
|
System.out.println("Contribution submitted:");
|
|
System.out.println(" Participant: " + contribution.getParticipantId());
|
|
System.out.println(" Contribution hash: " + contribution.getHash());
|
|
System.out.println(" Verification status: " + contribution.isVerified());
|
|
|
|
// Get ceremony status
|
|
CeremonyStatus status = zk.setup().getStatus(setup.getCeremonyId()).get();
|
|
System.out.println("\nCeremony status:");
|
|
System.out.println(" Phase: " + status.getPhase());
|
|
System.out.println(" Total contributions: " + status.getTotalContributions());
|
|
System.out.println(" Verified contributions: " + status.getVerifiedContributions());
|
|
System.out.println(" Ready for finalization: " + status.isReadyForFinalization());
|
|
|
|
// Finalize setup (when enough contributions)
|
|
if (status.isReadyForFinalization()) {
|
|
System.out.println("\nFinalizing setup...");
|
|
FinalizedSetup finalized = zk.setup().finalize(setup.getCeremonyId()).get();
|
|
System.out.println("Setup finalized:");
|
|
System.out.println(" Proving key hash: " + finalized.getProvingKeyHash());
|
|
System.out.println(" Verification key hash: " + finalized.getVerificationKeyHash());
|
|
System.out.println(" Contribution transcript: " + finalized.getTranscriptCid());
|
|
}
|
|
|
|
// Download ceremony transcript
|
|
byte[] transcript = zk.setup().getTranscript(setup.getCeremonyId()).get();
|
|
System.out.println("\nCeremony transcript: " + transcript.length + " bytes");
|
|
|
|
System.out.println();
|
|
}
|
|
|
|
private static String bytesToHex(byte[] bytes) {
|
|
StringBuilder sb = new StringBuilder();
|
|
for (byte b : bytes) {
|
|
sb.append(String.format("%02x", b));
|
|
}
|
|
return sb.toString();
|
|
}
|
|
}
|