ZeraLabs logo
WALLET

Proof System

Groth16 zk-SNARKs, circuit architecture, trusted setup, state transitions, and post-quantum outlook

Zera uses Groth16 zk-SNARKs -- the most succinct non-interactive zero-knowledge proof system in production -- to validate transactions while revealing nothing about amounts, senders, recipients, or note positions. Proofs are generated client-side via snarkjs and verified on-chain via Solana's alt_bn128 precompile.

1. Groth16 Protocol Overview

Given an arithmetic circuit C encoding a relation R(x, w) -- for example, "commitment C is in the Merkle tree with root R, and nullifier N is correctly derived" -- the Groth16 prover and verifier interact as follows:

(pk, vk) <- Setup(C) // trusted setup, once per circuit
π <- Prove(pk, x, w) // client-side, via snarkjs
b <- Verify(vk, x, π) // on-chain, via alt_bn128 precompile

Why Groth16

Groth16 was chosen for Zera because it offers the smallest proof size and fastest verification time of any deployed SNARK system:

  • Proof size: ~200 bytes (2 G1 points + 1 G2 point on BN254) -- smallest of any SNARK
  • Verification: Single pairing equation check, constant time regardless of circuit complexity
  • On-chain cost: ~200k compute units on Solana via the alt_bn128 precompile
  • Trade-off: Requires a per-circuit trusted setup (powers of tau + phase 2), unlike universal/transparent systems like PLONK or STARKs

Security Properties

  • Completeness: Honest prover with valid witness always produces an accepted proof
  • Knowledge Soundness: Any prover that produces a valid proof must "know" the witness (under the KEA assumption on BN254)
  • Zero-Knowledge: A simulator with the trapdoor can produce proofs indistinguishable from real ones -- no information about w leaks
Succinct Proofs
Groth16 proofs are ~200 bytes regardless of circuit complexity. A withdraw proof covering Poseidon commitment opening, 24-level Merkle path verification, and nullifier derivation is the same size as a trivial proof.
Constant-Time Verification
On-chain verification is a single BN254 pairing check: e(A, B) = e(alpha, beta) * e(L, gamma) * e(C, delta). This takes ~200k compute units on Solana -- constant regardless of what the circuit proves.

Interactive Proof Flow

Explore how proofs flow through each of Zera's four circuit types. Click a circuit to see the step-by-step proof generation and verification pipeline:

Shield tokens by creating a Poseidon commitment in the Merkle tree

2. Four Circuit Types

Zera has four circuit types, each with its own (pk, vk) pair:

  • Deposit: Proves the commitment is correctly formed from (amount, secret, blinding, asset, memo)
  • Withdraw: Proves Merkle membership, correct nullifier derivation, and amount consistency
  • Relayed Withdraw: Same as withdraw, plus relayer fee deduction and recipient designation
  • Transfer: Proves spending of input notes and creation of output notes with value conservation

Circuit Architecture

Commitment Verification

Inside the circuit, the prover recomputes C = Poseidon(amount, secret, blinding, asset, memo[0..3]) and checks it matches the committed leaf. This costs ~250 R1CS constraints.

Merkle Path Verification

The circuit verifies a 24-level Merkle inclusion proof: starting from the commitment leaf, hashing up through 24 sibling nodes to reach the public root. ~6,000 R1CS constraints.

Nullifier Correctness

The circuit verifies N = Poseidon(secret, C) and exposes N as a public output. This ensures the nullifier is deterministically bound to the note and can be checked against the on-chain nullifier set.

3. Transaction Flow: Withdraw Example

A user withdrawing from the privacy pool proceeds through the following steps. Click each step to explore:

Step 1 of 6

Retrieve Merkle Root

Retrieve the current Merkle root R from on-chain state (or any of the last 100 roots).

4. Trusted Setup

Zera currently uses a standard Groth16 trusted setup ceremony -- a one-time, multi-party computation that generates the proving and verification keys for each circuit (deposit, withdraw, relayed withdraw, transfer).

4.1 How It Works

Zera's four Groth16 circuits each require a structured reference string (SRS) generated by a trusted setup ceremony. The ceremony uses the "powers of tau" protocol followed by circuit-specific phase-2 contributions:

SRS = (pk, vk) ← Setup(C)
where C is the arithmetic circuit (R1CS) for each operation

4.2 Security Guarantee

The standard Groth16 trust assumption: at least one participant in the ceremony must have honestly destroyed their toxic waste (the secret randomness used during their contribution). If this holds, the SRS is sound and no party can forge proofs.

4.3 On-Chain Verification

Groth16 proofs are verified on Solana using the alt_bn128 precompile, which natively supports BN254 pairing operations. The verification key (vk) is stored on-chain; each proof verification requires a single pairing check:

e(A, B) = e(α, β) · e(L, γ) · e(C, δ)
where e is the BN254 optimal Ate pairing

5. Groth16 Security Properties

PropertyGuaranteeAssumption
SoundnessNo polynomial-time adversary can produce a valid proof for a false statement (e.g., spending a note not in the tree, or reusing a nullifier) except with negligible probability.Knowledge-of-exponent (KEA) on BN254
Zero-KnowledgeProofs reveal nothing about the witness (amount, secret, blinding, Merkle path, leaf index). A simulator can produce indistinguishable transcripts.Simulation via trapdoor from SRS
SuccinctnessProof size is constant (~200 bytes: 2 G1 points + 1 G2 point). Verification is a single pairing equation check, independent of circuit size.BN254 pairing efficiency
Trusted SetupSRS is generated via multi-party ceremony. Security requires at least one honest participant to have destroyed their secret randomness ("toxic waste").1-of-N honesty

6. State Transitions & Double-Spend Prevention

Zera's global state evolves through leaf insertions into a 24-level incremental Merkle tree. Each state transition appends a new commitment and recomputes the root -- a deterministic, append-only transition verified by Groth16 proofs.

S_(i+1) = MerkleInsert(S_i, C_new)
Root_(i+1) = Poseidon(... path from new leaf to root ...)

Nullifier-Based Double-Spend Prevention

Zera prevents double-spends through deterministic nullifiers. When a note is spent:

  • The spender computes N = Poseidon(secret, commitment) and reveals N on-chain
  • The on-chain program checks N against a nullifier set -- if N already exists, the transaction is rejected
  • The Groth16 proof demonstrates that N was correctly derived from a valid commitment in the Merkle tree
  • No party can spend the same note twice without producing the same nullifier
Append-Only Merkle State
The incremental Merkle tree provides a verifiable, append-only accumulator. Each insertion deterministically produces a new root via Poseidon(left, right) at each level -- a pure function of the previous state plus the new leaf.
Nullifier Finality
Each spend is a one-way state transition: once a nullifier N = Poseidon(secret, C) is published, the corresponding note can never be spent again. This provides cryptographic finality without epoch boundaries.

Concurrent Transaction Tolerance

Root History Buffer
The on-chain program maintains the last 100 Merkle roots. A proof generated against root R_i remains valid even after new deposits advance the tree to R_(i+k), as long as R_i is still in the buffer.
Incremental Merkle Tree
The 24-level tree uses Poseidon(left, right) at each node. New commitments are inserted at the next available leaf index, and only the path from leaf to root is recomputed -- O(24) Poseidon hashes per insertion.

7. Post-Quantum Considerations

Current Vulnerability Surface

BN254 pairings used by Groth16 are vulnerable to Shor's algorithm on a sufficiently large quantum computer. However, the Poseidon hash-based commitment layer is not directly broken by quantum attacks (unlike Pedersen commitments which rely on discrete log).

Migration Path

Hash-based commitments (already deployed) are quantum-resistant. The proof system would need replacement -- e.g., lattice-based SNARKs, STARKs, or WOTS (Winternitz One-Time Signatures) for hash-based authentication. The Poseidon commitment layer is architecturally positioned for a post-quantum proof system swap.

Research: Homomorphic Evolution

The theoretical framework of structure-preserving homomorphisms remains a valuable research direction for protocol upgrades that migrate commitment schemes while preserving validity of existing proofs, cross-chain bridges mapping state between different algebraic domains, and future epoch-based systems that evolve cryptographic parameters over time. This is not deployed in the current system, which uses fixed Poseidon parameters and a static Groth16 SRS.

8. Deployed System Parameters

ParameterValueRationale
Merkle tree depth24 levelsCapacity: 2^24 = 16,777,216 notes
Hash functionPoseidon X5 over BN254 scalar fieldSNARK-friendly; minimal R1CS constraints
Root history buffer100 entriesConcurrent transaction tolerance
Proof systemGroth16 (snarkjs / groth16-solana)~200 byte proofs, constant-time verification
VerificationSolana alt_bn128 precompileNative BN254 pairing at ~200k CU

9. Performance & Implementation

  • Proof generation: ~2-5 seconds client-side via snarkjs (WASM), dominated by the multi-scalar multiplication in Groth16 proving
  • Proof size: ~200 bytes (constant) -- 2 G1 points + 1 G2 point on BN254
  • On-chain verification: ~200k compute units on Solana via alt_bn128 precompile
  • Trusted setup: One-time per circuit; Zera has four circuits (deposit, withdraw, relayed withdraw, transfer)
Implementation Stack
  • Rust on-chain: light-poseidon 0.4, ark-bn254 0.5.0, ark-ff 0.5.0, groth16-solana 0.2.0
  • TypeScript client: circomlibjs for Poseidon, snarkjs for Groth16 proving, @noble/hashes for Keccak-256
  • Verification: Solana's alt_bn128 precompile for native BN254 pairing operations
  • Circuit types: deposit, withdraw, relayed withdraw, transfer

10. Research Direction: Perpetual Genesis Ceremony

The following describes a theoretical research direction -- not the deployed system. It explores how a one-shot ceremony could be replaced with continuous participation, building on ideas from updatable SRS schemes.

Global Epoch Counter

Time would be divided into fixed-length epochs T1, T2, ... Every wallet would know the current epoch index i from the ledger header.

Base Randomness per Epoch

A public randomness beacon (e.g., the threshold-BLS drand network) would publish an unpredictable scalar: beta_i = Hash(drand sig_i) mod p.

User Contributions

Anyone could inject additional entropy during the contribution window. Contributors pick a private scalar r, broadcast a hash commitment H = Poseidon(r, nonce) with a proof of knowledge, and reveal after the window closes. All revealed scalars are added modulo p.

Epoch Seed & Updatable SRS

The epoch seed S_(i+1) = Poseidon(S_i, beta_i, rho_i) could drive an updatable structured reference string, allowing the proving/verification keys to evolve without re-running a full ceremony. This is an active area of research in the SNARKs community.

Go Deeper

Cryptographic Primitives

Poseidon X5, BN254 scalar field, Merkle math

$ZERA Token

Burn mechanics, fee structure, supply dynamics

Compliance & Economics

Regulatory positioning, investment framework

Glossary

All terms and definitions