Proof generation
SEAL uses four PLONK circuits. Withdrawal, transfer and settlement accept up to eight monetary inputs and expose 71 public signals, including the mandatory checkpoint transition and optional Unix proof expiration. The account-only circuit exposes 11 public signals for deposits and unfunded private-margin actions. The circuit package seal-pool/packages/circuits/README.md defines the signal layout. The specification defines authorization, conservation and execution binding.
The SDK validates openings, ownership, Merkle paths, amounts and output bounds. Disabled slots must be zero. The browser calculates the witness, generates the proof and verifies it locally before submission. Private witnesses remain on the client.
Compilation and setup
Use Node 22 or 24, Circom 2.2.3, snarkjs 0.7.6 and the pinned dependency lockfile. Compile with --O1; setup then eliminates private affine aliases with an independently checked certificate, preserving the original witness calculator and all eight note slots. The setup checks the actual translated PLONK domain against the power-19 public SRS.
npm run prepare:multi-asset
npm run prepare:assets
Verify the universal SRS
See Trusted Setup for pinned provenance, integrity checks, full contribution verification and retained verification records.
Qualify a circuit release
Build two fresh candidates, then run npm run qualify:plonk:browser -- CANDIDATE NEW_BROWSER_RESULT.json and npm run qualify:plonk -- CANDIDATE_A CANDIDATE_B BROWSER_RESULT.json NEW_RECORD_DIRECTORY. These commands retain reproducibility, complete stock/compact proof comparisons, browser proofs and Solidity replay evidence without approving a deployment.
The generated verification API requires canonical decimal strings or bigint values for proof fields and public signals. It rejects noncanonical field aliases, numeric/ambiguous string encodings and array-like objects before snarkjs converts them. Verification keys remain trusted, integrity-checked release artifacts.
Browser workers
Proving runs in a dedicated worker with at most four nested workers. If nested workers are unavailable, it uses a single-worker fallback. Failed or cancelled proofs cannot be submitted. The local timeout is 15 minutes; actual time and memory depend on hardware, browser and competing workloads.
The worker verifies the manifest and compressed asset hashes, decompresses the key within a pinned size limit, and checks its expanded size, digest and format. The .zkcr.gz.bin extension avoids servers transparently decompressing the transport bytes before integrity checking. See Circuit artifacts.
Each testnet build installs the proof bundle of its selected fresh run.
Validation
npm run test:circuits
npm run test:plonk-setup
npm run test:plonk-optimizations
npm run test:verifier-generation
npm run test:verifier-references
npm run test:verifier-fuzz
npm run test:verifier-mutations
npm run test:contracts
Tests cover malformed witnesses, compact-key reconstruction, proof generation, signal mutations and optimized/reference verifier comparisons. Changing a circuit, compiler optimization or setup implementation requires regenerating matching keys, verifiers and proof fixtures. Solidity exports are generated from pinned templates and must not be edited by hand.
The browser benchmark uses synthetic notes and submits no transaction. The local savings smoke test additionally deposits and withdraws through the actual pool using a browser-generated PLONK proof. Desktop results do not establish phone performance.