The UTXO Model
Privacy Boost uses a UTXO (Unspent Transaction Output) model. Instead of maintaining account balances, the system tracks individual notes, each representing a specific amount of a specific token owned by a specific user. Think of it like cash. You don’t have a “balance of $47,” you have a $20 bill, a $20 bill, a $5 bill, and two $1 bills. To pay someone $15, you hand over the $20 and get $5 back as change. In Privacy Boost:- Spending a note publishes a nullifier (marks it as consumed)
- Receiving creates new notes (adds commitments to the Merkle tree)
- A transfer consumes input notes and creates output notes, with the ZK circuit enforcing that inputs = outputs + fees
Notes and Commitments
What’s Inside a Note
A note contains three fields:| Field | Description |
|---|---|
| NPK (Note Public Key) | Unique per-note key derived from the owner’s identity + randomness |
| Token ID | Which ERC-20 token (compact ID from the TokenRegistry) |
| Value | Amount of tokens |
Commitments
A commitment is the Poseidon2 hash of a note’s contents:Nullifiers
A nullifier is a one-time-use tag that marks a specific note as spent. It prevents double-spending without revealing which note was consumed.How Nullifiers Work
Each nullifier is derived from the user’s secret nullifying key and the note’s position in the Merkle tree:How Ownership Is Proven
To spend a note, you prove three things inside the ZK circuit:- You know the note’s secrets: The circuit verifies your private fields hash to the correct commitment.
- Your auth key is registered: You sign with your EdDSA auth key, and the circuit proves it exists in the AuthRegistry.
- The note exists: The circuit verifies a Merkle proof for your commitment.
Merkle Trees
Fixed-Depth Incremental Merkle Tree
All note commitments are stored in an append-only, fixed-depth binary Merkle tree using Poseidon2 hashing. Each tree has a fixed depth of 24 (~16.7M leaves); empty subtrees are filled with precomputed zero hashes, so an append only recomputes the hashes along one path to the root. Leaves are never modified or deleted.Multi-Tree Architecture
When the active tree fills up, a new tree is created (rollover). Input notes can reference commitments in any historical tree, so old notes remain spendable indefinitely. Each tree maintains a ring buffer of recent roots, allowing proofs to reference slightly stale roots. This accommodates the delay between proof construction and onchain submission.Tree Transitions in Circuits
When new notes are created, the ZK circuit proves that the tree state transition is valid, and the contract just verifies the proof and updates the stored root. This means the contract never has to compute Poseidon2 hashes onchain for leaf insertions.Transaction Lifecycle
Deposit (Public → Shielded)
Deposits are a 2-step process:- User locks tokens: The user computes note commitments, encrypts the metadata using the dual-path ECDH scheme, and submits everything to the contract. The contract transfers the ERC-20 tokens and stores the pending deposit with replay protection.
- TEE processes the batch: The TEE detects pending deposits, generates a Groth16 proof verifying that commitments are correctly computed and the tree state transition is valid, then submits it onchain.
Transfer (Shielded → Shielded)
Transfers move value between shielded notes. Sender identity, recipient identity, token type, and amounts are all hidden from onchain observers.- User prepares: Select input notes to spend, construct output notes for the recipient (and change for yourself), sign with your EdDSA auth key, and encrypt the output metadata using dual-path ECDH
- User submits to TEE: The TEE verifies the signature and ciphertext integrity, then batches the transfer into an epoch
- TEE submits epoch: The TEE generates a Groth16 proof covering signature validity, note existence, nullifier correctness, value conservation, and tree state transition, then submits it onchain
- Contract verifies: Checks the proof, marks nullifiers as spent, updates the tree root
Withdrawal (Shielded → Public)
Withdrawals use the same mechanism as transfers. The difference: instead of creating an output note, the contract sends ERC-20 tokens to a public address. Withdrawals are batched alongside transfers in the same epoch.Forced Withdrawal (Emergency Exit)
Forced withdrawal is the self-custody escape hatch: exit the shielded pool without any TEE involvement.- Reconstruct your notes: Scan onchain events and decrypt metadata with your viewing key
- Generate a ZK proof locally: Prove you own the notes and derive correct nullifiers (this runs on consumer hardware)
- Submit to the contract: The contract verifies the proof and starts a configurable delay period
- Execute after the delay: The contract transfers your tokens
Epoch Batching
Multiple user transactions are aggregated into a single epoch, one Groth16 proof covering the entire batch. This is a key design choice for throughput:- A single Groth16 proof verifies the entire epoch, so the fixed cost of proof verification is amortized across every transaction in the batch
- The larger the batch, the lower the proof-verification overhead per transaction
- At Base’s gas target, this enables 300+ sustained TPS; at the gas limit, 1,800+ TPS
status field and surfaces it as phase: 'spendable' so applications can chain the next private action (another transfer or a withdrawal) without waiting for the epoch to land. Preconfirmation is a soft confirmation: a reorg can still force the TEE to re-batch or fail the request, so clients keep polling until completed. Shields and unshields also pass through preconfirmed, but neither produces a spendable output, so that state is progress UI only. See Transaction Lifecycle for the full state machine.
To prevent key-rotation attacks during an epoch, an epoch proof must reference a sufficiently fresh AuthRegistry root. When a root is replaced, the AuthRegistry records the block at which it was superseded, and the pool accepts an auth root only if it is current or still within a configured staleness window.
Fee Model
- Deposits are fee-free
- Transfers and withdrawals charge configurable fees (in basis points)
- The ZK circuit enforces conservation: inputs = outputs + fees
- Forced withdrawal fees are deducted at execution time
Earn: Private DeFi
Earn lets users put shielded funds to work in external DeFi and generate yield without publicly revealing their wallet identity. All DeFi activity is linked to Privacy Boost rather than to any individual user. The high-level flow:- Supply: move assets from your shielded balance into an approved vault and hold the resulting position privately.
- Redeem: redeem that position back into assets in your shielded balance.
- Asynchronous redeem: for vaults that settle redemptions over time, request a redemption and claim the assets once the vault fulfills it.
Smart Contracts
| Contract | Role |
|---|---|
| PrivacyBoost | Core shielded pool: Merkle trees, nullifier registry, deposits, epochs, forced withdrawals |
| AuthRegistry | Binds account IDs to EdDSA signing keys. Supports multi-device, rotation, and revocation. Maintains its own Poseidon2 Merkle tree; epoch proofs reference a recent (non-superseded) auth root within a staleness window. |
| TokenRegistry | Maps compact token IDs to ERC-20 addresses (append-only) |
| AuditGateway | Auditor registry and onchain audit logging (see Auditability) |
| Groth16 Verifiers | Proof verification for each circuit type (Epoch, Deposit, ForcedWithdraw) |
Coming Soon
More privacy-preserving capabilities are in development, each designed to preserve the same privacy and self-custody guarantees:- Portal deposit addresses: give each user a reusable public deposit address, similar to a centralized-exchange deposit address, that can be funded by others and displayed on a profile or invoice. Incoming tokens are automatically credited to the owner’s shielded balance, and observers see the address but never which account is credited.
- Claimable transfers: send shielded funds to a wallet address, even if the recipient has not joined Privacy Boost yet. The recipient can claim the funds by proving ownership of that address, and the sender can reclaim unclaimed funds after a set deadline.
- DeFi swaps: swap between tokens from a shielded balance without publicly exposing the user’s wallet identity, extending Earn beyond yield vaults.
Next Steps
- Keys & Encryption: How keys are derived and how the dual-path ECDH encryption scheme works
- Trust & Security: TEE guarantees and the full trust model
- Glossary: Technical terminology reference