synor/sdk/js/examples/zk_example.ts
Gulshan Yadav 9416d76108 Add IBC and ZK SDK examples for Rust
- Introduced `ibc_example.rs` demonstrating Inter-Blockchain Communication operations including cross-chain transfers, channel management, packet handling, and relayer operations.
- Introduced `zk_example.rs` showcasing Zero-Knowledge proof operations such as circuit compilation, proof generation and verification, and on-chain verification with multiple proving systems.
2026-01-28 14:15:51 +05:30

537 lines
16 KiB
TypeScript

/**
* 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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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);