PLONK proofs
SEAL uses PLONK over BN254 for withdrawal, transfer, settlement and account-only transitions. Monetary circuits accept up to eight notes and expose 71 public signals; the account-only circuit exposes 11. Every action binds its checkpoint transition and optional proof expiration. A proof contains nine G1 commitments and six field evaluations: 24 words, or 768 bytes. The transaction also carries the public signals and operation data.
Private note openings, spending keys, balances and Merkle paths remain in the browser worker. The worker calculates a witness, generates a proof and verifies it locally. The pool checks the proof through its operation-specific PlonkVerifierAdapter and enforces execution context, spent-nullifier, root and asset-accounting rules.
flowchart LR
N[Private notes and membership paths] --> W[WASM witness calculation]
W --> P[Compact PLONK prover]
P --> V[Local verification]
V --> T[Proof and public signals]
T --> C[Optimized Solidity verifier and pool]
Universal setup
The setup uses the pinned power-19 Perpetual Powers of Tau checkpoint 0080. PLONK circuit keys are derived deterministically from that public structured reference string (SRS); no circuit-specific contribution ceremony is needed. The SRS contribution chain and beacon still require verification. Public setup does not establish circuit correctness, prover correctness or production approval.
Compilation uses Circom 2.2.3 with --O1, followed by a checked private-affine-alias elimination pass. The pass leaves the Circom source, original witness calculator, eight-note capacity and public signals unchanged. The monetary circuits use a 524,288-point domain; the account-only circuit uses 32,768 points. R1CS constraint count alone does not predict PLONK proving cost.
Compact proving keys
The seal-plonk-rows-v1 format stores selector values at the base domain, wire maps and public SRS points. The prover reconstructs permutation polynomials, selector coefficients and extended evaluations. It generates the combined public-input polynomial and first Lagrange polynomial at runtime. Within one proof, the five selector polynomials reconstructed for the quotient are reused for linearization, avoiding five duplicate inverse FFTs. Their extended evaluation buffers are released after the quotient round. This retains public coefficients only for that invocation; the dedicated worker is still terminated after success, failure or cancellation. These changes preserve the PLONK statement and verification key.
Each bundle manifest pins the exact sizes of its keys. The browser downloads the circuit it needs; proving requires substantially more working memory than the download.
The implementation is generated from pinned snarkjs 0.7.6 sources, with ffjavascript 0.3.1. The compact key is intentionally a distinct format, zkcr, rather than a standard snarkjs key. See proof generation and artifact integrity.
Prover and compiler checks
The quotient loop batches the pinned snarkjs expression into existing ffjavascript WASM field operations. It leaves proof blinding, Fiat–Shamir challenges and the pairing equation unchanged. Byte-for-byte differential tests compare its output with the JavaScript loop, including field boundaries, pseudorandom inputs, chunk boundaries and the single-worker fallback.
Each affine substitution has a certificate. A separate checker uses BigInt arithmetic to verify that the original constraint implies the substitution, that only private variables are eliminated, and that every other row is preserved after substitution. It checks both the in-memory result and the serialized R1CS. Public variables and witness indices remain fixed. Exhaustive small-field tests compare the original and optimized public relation and reconstruct satisfying original witnesses.
These checks matter separately from verifier differential tests: two verifiers can agree on an incorrectly compiled relation. This optimization remains subject to independent cryptographic review and release qualification; passing tests does not approve a mainnet launch.
Solidity optimization
The optimized verifier uses the modular-exponentiation precompile for a checked field inverse and copies the public-input transcript directly from calldata. Inverse scratch space follows the batch-inversion prefix products. Curve checks, canonical field checks, transcript binding and the pairing equation remain in the verifier.
The source-pinned snarkjs PLONK template is the reference for differential tests. Tests exercise valid proofs, altered proof/public words, noncanonical fields, malformed lengths, operation separation and the inverse routine. These checks supplement independent review; they are not a proof of soundness.