Circuit Design
How ZORB Cash uses zero-knowledge proofs to enable private transactions
Circuit Design
ZORB Cash uses zero-knowledge (ZK) proofs to enable private transactions on Solana. This page explains the circuit architecture—what the proofs actually prove and why they're designed this way.
Notes and Nullifiers
At the heart of ZORB Cash is a simple concept: instead of tracking balances like a bank, we track encrypted "notes" that represent value. This design pattern originated in Zcash and has been refined by protocols like Tornado Cash and Aztec.
When you deposit tokens, you create a note—a cryptographic commitment that says "someone owns X amount of token Y." The note goes into a public Merkle tree, but nobody can tell who owns it or what it contains without the right keys.
When you spend tokens, you reveal a nullifier—a unique fingerprint derived from the note. The nullifier proves you're spending a specific note without revealing which one. Once a nullifier is published, that note can never be spent again.
→ How nullifiers are stored and cleaned up
The Transaction Circuit
The main circuit handles spending and creating notes. ZORB Cash uses a 4-in-4-out design: each transaction can consume up to 4 existing notes and create up to 4 new notes.
Why 4? It's a balance between flexibility and proof generation time. Four inputs handle most use cases (combining small notes, sending to multiple recipients, claiming change), while keeping proof generation under 30 seconds in a browser.
What the Circuit Proves
When you submit a transaction, you generate a proof that demonstrates:
-
You own the input notes — You prove knowledge of the secret keys that created each note's commitment, without revealing those keys.
-
The notes exist in the Merkle tree — You prove each input note is in the commitment tree at a specific position, without revealing which positions.
-
The math adds up — Total inputs (plus any deposits) equals total outputs (plus any withdrawals and fees). Value can't be created or destroyed.
-
The nullifiers are correctly derived — Each nullifier deterministically comes from its note, so you can't forge a nullifier to steal someone else's funds.
-
No duplicate nullifiers — The transaction doesn't try to spend the same note twice.
All of this is proven in a single Groth16 proof that verifies in about 1-2 milliseconds on-chain.
Multi-Asset Privacy
ZORB Cash supports multiple tokens (WSOL, USDC, and more) in a single shielded pool. This is a significant privacy improvement over having separate pools per token.
Why a Shared Pool Matters
With separate pools, if you deposit 100 USDC and later withdraw 100 USDC, an observer knows those are probably related. With a shared pool, you might deposit 100 USDC while someone else deposits WSOL, and later you might withdraw WSOL. The token types mix, making analysis much harder.
How It Works
Each note contains an assetId field identifying the token type. The circuit enforces:
- Value conservation per asset — You can't deposit USDC and withdraw more USDC than you put in.
- Asset validation — Notes must reference valid, enabled tokens.
- Private asset selection — Which tokens you're spending is hidden from on-chain observers.
The circuit uses a token registry (passed as public inputs) to map asset IDs to their current state. This allows the protocol to add new tokens without changing the circuit.
The Note Structure
Each note commitment is a hash of 7 fields:
| Field | Purpose |
|---|---|
| Domain | Protocol identifier to prevent cross-protocol collisions |
| Version | Future-proof for note format upgrades |
| Asset ID | Which token this note holds |
| Amount | How much value (hidden from observers) |
| Public Key | Owner's key (derived from secret keys) |
| Blinding | Random value that makes the commitment unique |
| Reward Accumulator | Yield snapshot for reward calculation |
The commitment uses Poseidon hashing, a ZK-friendly hash function designed to minimize circuit complexity while providing cryptographic security. Poseidon requires far fewer constraints than traditional hashes like SHA-256, making it ideal for ZK circuits.
→ Key derivation and the public key
Why This Design Excels
1. Economical Nullifier Storage
The epoch-based nullifier system means storage costs don't grow forever. After sufficient time passes, old nullifier PDAs can be reclaimed. Only the compact Merkle tree root is permanent.
→ Learn about nullifier epochs
2. Fast On-Chain Verification
Groth16 proofs are tiny (about 256 bytes) and verify in constant time. The on-chain cost is the same whether you're proving ownership of 1 note or 4.
3. Strong Privacy Set
All tokens share one pool, and all users share one anonymity set. The more people use ZORB Cash, the stronger everyone's privacy becomes.
4. Yield Without Tradeoffs
Notes earn rewards automatically. You don't sacrifice yield for privacy or vice versa.
5. Flexible Transactions
The 4-in-4-out design handles complex use cases: combining dust notes, sending to multiple recipients, claiming change—all in a single proof.
6. Future-Proof
The versioned note format and modular circuit design allow upgrades without migrating all existing notes.
Constraint Counts
For the technically curious, here are the circuit sizes:
| Circuit | Constraints | Use Case |
|---|---|---|
| Transaction (4-in-4-out) | ~35,620 | User transactions |
| Nullifier Non-Membership | ~29,104 | Prove nullifiers not in historical tree |
| Nullifier Batch Insert (4) | ~50,000 | Sequencer tree updates |
The transaction circuit is optimized for browser proving using snarkjs, keeping constraints low enough for reasonable generation times (~10-30 seconds) while maintaining full security.
What Observers See
When you transact with ZORB Cash, here's what on-chain observers can see:
| Visible | Hidden |
|---|---|
| New commitments (opaque hashes) | What's inside the commitments |
| Nullifiers (opaque hashes) | Which notes were spent |
| Deposit/withdrawal amounts | Private transfer amounts |
| Proof verification result | Who sent, who received |
The visible data reveals nothing about transaction participants, amounts (except deposits/withdrawals), or the connection between inputs and outputs.
Further Reading
Internal Documentation
- Wallet Guide — How to use ZORB Cash
- Nullifier Epochs — How storage costs stay low
- Key Hierarchy — Spending vs. viewing keys
- Shielded Yield — How yield works on private balances
- Comparisons — How ZORB Cash compares to alternatives
External References
Zero-Knowledge Proofs
- Zero-Knowledge Proof — Wikipedia overview
- What are ZK-SNARKs? — Zcash Foundation introduction
- Groth16 — Wikipedia on the proof system
Cryptographic Primitives
- Poseidon Hash — Official specification and parameters
- BN254 Curve — Barreto-Naehrig elliptic curves
- Merkle Trees — Wikipedia on the data structure
Protocol Inspirations
- Zcash Sapling Protocol — Key derivation and note structure
- Aztec Indexed Merkle Tree — Non-membership proof design
- Tornado Cash — Note/nullifier model
- Railgun — Multi-asset privacy pool design
Development Tools
- Circom — ZK circuit compiler
- snarkjs — JavaScript Groth16 prover/verifier
- circomlib — Standard circuit library (Poseidon, comparators, etc.)
Solana
- Solana PDAs — Program Derived Addresses
- Rent — Solana's storage cost model