ZeroDocumentation
Browse documentation
How it works

Shielded

A Groth16 shielded pool on Solana that breaks the link between sender and recipient.

A shielded pool on Solana

The Shielded mode holds money as private notes inside a pool. Spending a note publishes a zero-knowledge proof and a nullifier, never the note itself, so nobody can tell which deposit a payment came from, who sent it or how much it was. The proof is a Groth16 proof over BN254 from a circuit of about 62,000 constraints, and the chain verifies it in about 190,000 compute units.

Notes and the tree

note        = (amount, owner, blinding)
commitment  = Poseidon(amount, owner, blinding)

Every new note’s commitment is appended to a 26-level Poseidon Merkle tree, room for 67 million notes. The chain stores only the tree’s right edge and its last 100 roots, which keeps the account to a few kilobytes and lets many people prove against the tree at the same time without invalidating each other.

Spending exactly once

nullifier = Poseidon(commitment, nullifier_key, position)

Spending a note publishes its nullifier, which only its owner can compute. The program stores each nullifier as its own account, and an account can only be created once, so a second spend of the same note fails the moment its nullifier account would be created again.

The proof

Each shielded transaction spends up to two notes and creates two. Its Groth16 proof, built in your browser, shows all of this without revealing any of it:

  • Every spent note is in the tree.
  • You own it: you know the keys behind its owner.
  • Its nullifier is computed correctly.
  • Value in equals value out plus the fee, and every amount is in range.
  • The recipient, relayer, fee and encrypted outputs are exactly the ones submitted.

The pool program verifies it with Solana’s BN254 pairing syscalls. The verifying key is compiled into the program itself, so it cannot be swapped out, and it comes from a trusted setup ceremony built on the Perpetual Powers of Tau and finalized with a public drand randomness beacon.

Finding your notes

Every note is encrypted to its owner with X25519 and XChaCha20-Poly1305 and posted with the transaction. Your browser tries to decrypt every output in the pool and keeps the ones that open, so no server ever learns which notes are yours.

Keys that do one job each

spend key ─┬─ public key      receive
           ├─ nullifier key   spend
           └─ view key        read

All of them come from one signature your wallet makes. The split is designed in from the start, so reading and spending can be separated, and the circuit carries an association root for proof-of-innocence membership sets.

Search the Zero documentationLocal search · no external service