Privacy Pools
Understanding the core cryptographic primitives behind Shinobi Cash.
Key Terms
| Term | Meaning |
|---|---|
| Commitment | A hash representing your deposit, added to the Merkle tree |
| Nullifier | A unique value revealed during withdrawal to prevent double-spend |
| Merkle Tree | Data structure that allows proving membership without revealing position |
| ZK Proof | Cryptographic proof that verifies claims without revealing inputs |
Overview
Privacy Pools enable private transactions by breaking the on-chain link between deposits and withdrawals. Users deposit funds into a shared pool and later withdraw using zero-knowledge proofs that verify ownership without revealing which deposit is theirs.
Concrete Example
Alice deposits 1 ETH:
→ Commitment C₁ added to Merkle tree
→ Alice stores secret S₁ locally
Later, Alice withdraws 0.3 ETH:
→ Generates ZK proof: "I know secret for some commitment in the tree"
→ Reveals nullifier N₁ (derived from S₁)
→ Receives 0.3 ETH to recipient address
→ Change note: 0.7 ETH commitment C₂ created
On-chain, observers see:
→ Deposit: someone added C₁
→ Withdrawal: someone spent N₁, created C₂
→ No link between C₁ and N₁ visibleKey Concepts
Commitments
When you deposit, a commitment is created and added to a Merkle tree:
commitment = hash(nullifier, secret, amount, ...)This commitment is public, but the underlying values (nullifier, secret) are known only to you.
Nullifiers
When you withdraw, you reveal a nullifier derived from your deposit:
nullifier = hash(secret, depositIndex)The nullifier proves you own a valid deposit without revealing which one. Once revealed, the nullifier is marked as "spent" to prevent double-spending.
Zero-Knowledge Proofs
Withdrawals require a Groth16 SNARK proof that verifies:
- You know the secret for a valid commitment in the tree
- The nullifier is correctly derived from that commitment
- The commitment is in a compliant Association Set (ASP membership)
The proof reveals nothing about which deposit you're spending.
Merkle Trees
Shinobi Cash uses two Merkle trees:
State Tree
Contains all deposit commitments. The root changes with each deposit.
ASP Tree
Contains commitments approved by Association Set Providers. Only deposits in the ASP tree can be withdrawn (ensuring compliance).
Proof Signals
Standard Withdrawal (8 signals)
[0] newCommitmentHash // Change note commitment
[1] existingNullifierHash // Spent deposit nullifier
[2] withdrawnValue // Amount withdrawn
[3] stateRoot // Merkle root of deposits
[4] stateTreeDepth // Depth of state tree
[5] ASPRoot // Merkle root of ASP set
[6] ASPTreeDepth // Depth of ASP tree
[7] context // Binding context (prevents replay)Cross-Chain Withdrawal (9 signals)
Adds one additional signal:
[2] refundCommitmentHash // Fallback if intent failsThis enables recovery if the cross-chain settlement fails.
Privacy Guarantees
| What's Hidden | What's Revealed |
|---|---|
| Which deposit you're spending | That you have a valid deposit |
| Your deposit history | The nullifier (once spent) |
| Connection to your identity | The withdrawal amount |
| The recipient address |
Learn More
- Cross-Chain Architecture — How privacy works across chains
- Compliance — Association Set Providers explained
- Smart Contracts — Implementation details