Module 14 · Privacy protocols in practice: shielded pools, Railgun & the compliance frontier
Privacy protocols compared — reading the guarantee honestly
There is no single "private blockchain" design; there is a family of very different systems, each hiding a different thing under different assumptions. Monero hides sender, receiver and amount on its own chain with ring signatures, RingCT and stealth addresses — no SNARK, no trusted setup, a per-transaction anonymity set bounded by the ring size. Tornado-style mixers hide the deposit→withdrawal link within a fixed-denomination pool. Zcash offers an optional shielded pool with real zero-knowledge proofs. Railgun shields ERC-20 balances and transfers inside a smart-contract system on public chains. Aztec builds programmable privacy as a private rollup. Privacy Pools are compliance-first, letting a user prove their funds are disassociated from a flagged set. Comparing them means comparing at the functionality level — what each hides and under what assumptions — not ticking a shared feature list. Feature presence is not feature parity, and parity is not equivalent security or maturity.
Learning objective
Place the main real-world privacy systems side by side — Monero, Tornado-style fixed-denomination mixers, Zcash, Railgun, Aztec and Privacy Pools — and learn to read each one's guarantee for what it is: what it actually hides, its anonymity-set model, its trust and setup assumptions, and its maturity and compliance posture. The throughline is that a checkmark on a feature is not equivalence; a valid proof attests a specific statement under assumptions and says nothing by itself about whether an output is private in practice, which depends on the anonymity set and off-chain behaviour.
- Track
- Research
- Module
- 14 · Privacy protocols in practice: shielded pools, Railgun & the compliance frontier
- Prerequisites
- Nullifiers, Merkle membership and the privacy-pool pattern · Ring signatures and stealth addresses · Non-membership and proof of innocence
There is no "the" privacy protocol
People speak of "privacy coins" or "privacy protocols" as if they were one category with one guarantee. They are not. The systems in wide use hide different things, for different threat models, under different cryptographic and operational assumptions, and at very different levels of maturity. Reading any one of them honestly means answering four separate questions about it — not reaching for a single verdict of "private" or "not private".
- ▸What does it actually hide? Sender, receiver, amount, the link between two transactions, or an account balance — these are distinct, and a system can hide some while leaving others fully public.
- ▸What is its anonymity-set model? Privacy is almost never a yes/no property; it is a size. Among how many indistinguishable parties is a given action hidden, and what controls that number?
- ▸What are its trust and setup assumptions? A trusted setup ceremony, a specific hardness assumption, a relayer, a sequencer, or a compliance oracle each adds something that must hold for the guarantee to mean anything.
- ▸What is its maturity and compliance posture? How long has it been deployed and reviewed, and is it designed to resist disclosure, to permit selective disclosure, or to prove disassociation from flagged funds?
The core claim of this lesson: a feature checkmark is not equivalence. Two systems can both "hide the amount", yet differ in what cryptographic statement they prove, how large the hiding set is, and what has to be trusted. Feature presence ≠ feature parity ≠ equivalent security or maturity. Any comparison worth making is made at the functionality level and stays honest about all three gaps.
Six systems, six different guarantees
The following are all real, publicly documented systems. Each is summarised only at the level its public documentation and widely reported design support; no throughput, pool-size or timing figures are invented here, because those are exactly the numbers that must be measured per deployment, not asserted.
- Monero (ring signatures + RingCT + stealth addresses)
- A standalone chain, not a SNARK system. A ring signature hides the true spender among a fixed-size ring of decoy outputs; RingCT hides the amount with range-proof commitments; stealth addresses hide the receiver by deriving a one-time address per output. The anonymity set is the ring size per input — bounded and uniform — and there is no trusted setup. It is mature and has been deployed and analysed for years; its documented weaknesses are decoy-selection and statistical heuristics, not a setup ceremony.
- Tornado-style fixed-denomination mixers
- The commitment + Merkle-membership + nullifier pattern from the previous lesson. It hides only one thing: the on-chain link between a deposit and a later withdrawal of the same fixed denomination. It does not hide that you used the pool, nor the amount (it is fixed by design). The anonymity set is the number of unspent same-denomination deposits, and it collapses to one under tight timing, address reuse or unique behaviour.
- Zcash (shielded pool)
- An optional shielded pool on its own chain using real zero-knowledge proofs, where shielded transactions hide sender, receiver and amount. Privacy is opt-in: value can sit transparently or be shielded, and the effective anonymity set depends on how much of the supply is actually in the shielded pool. Earlier circuits depended on a trusted setup ceremony; the guarantee is only as good as that ceremony and the share of activity that is shielded rather than transparent.
- Railgun (shielded ERC-20 balances)
- A smart-contract system on public EVM chains that holds shielded balances of ERC-20 tokens and lets users transfer within the shield using zero-knowledge proofs, rather than running a separate chain. It hides balances and transfers inside its own pool while living on a transparent base chain, so the anonymity set is scoped to activity inside the shield, and the base chain still sees entries and exits.
- Aztec (private rollup / programmable privacy)
- A rollup aimed at programmable privacy — private state and private function execution, not just a fixed mixing primitive. The ambition is general: application-level private computation rather than a single denomination pool. With that generality come a sequencer/prover role and a more complex trust surface, and the design has evolved across versions, so maturity is read per the specific deployment and era, not as a single fixed fact.
- Privacy Pools (compliance-first)
- A design that keeps the pool pattern but lets an honest user prove their withdrawal is disassociated from a set of flagged deposits — an association/exclusion proof — so privacy and a compliance claim coexist. It hides the specific link while letting the user voluntarily prove membership in a "clean" subset. The guarantee is explicitly about disassociation from a named set, not blanket anonymity.
Notice how little these share. Monero and Zcash hide amounts; mixers and Privacy Pools do not (denomination is fixed and public). Monero needs no trusted setup; several SNARK systems historically did. Only Privacy Pools is built to produce a compliance statement. "Both are private" papers over every one of these differences.
Side by side — what each one actually claims
The table compares the six on the four questions from the introduction. Read each cell as a claim to be verified for a specific deployment, not as a score. "Maturity" here means length and breadth of public deployment and review, which is distinct from — and does not imply — correctness.
| System | What it actually hides | Anonymity-set model | Setup / trust | Maturity & compliance posture |
|---|---|---|---|---|
| Monero | Sender, receiver and amount on its own chain | Per-input ring (fixed size) + stealth outputs; bounded, uniform | No trusted setup; standard hardness assumptions | Long-deployed, heavily analysed; privacy is mandatory, not selective |
| Tornado-style mixer | Only the deposit↔withdrawal link, at a fixed denomination | Count of unspent same-denomination deposits; collapses under bad behaviour | ZK proof + (historically) a setup; relayer optional | Pattern is well understood; no built-in compliance, no amount hiding |
| Zcash | Sender, receiver, amount — when shielded | Share of value actually in the shielded pool | Real ZK proofs; earlier circuits needed a trusted-setup ceremony | Mature chain; privacy is opt-in, so transparent use shrinks the set |
| Railgun | Shielded ERC-20 balances and in-shield transfers | Activity inside the shield on a transparent base chain | ZK proofs on a public EVM chain; contract + relayer trust | Contract system on live chains; entries/exits visible on base chain |
| Aztec | Private state and private function execution (programmable) | Depends on the application and in-pool activity | ZK rollup; sequencer/prover role; evolving across versions | Ambitious, general; maturity read per deployment and era |
| Privacy Pools | The specific link, while proving disassociation from a flagged set | Chosen association/exclusion set; user proves "clean" membership | ZK proofs + an agreed association-set source | Compliance-first by design; proves disassociation, not blanket anonymity |
Even arranged in one table, the columns do not line up into a ranking. Monero's "no trusted setup" is not strictly better than Zcash's SNARK; it buys a different, bounded anonymity model. Privacy Pools' compliance proof is not a weaker Tornado; it answers a different question. The table is a map of distinct guarantees, not a leaderboard.
Reading a proof vs. reading a privacy outcome
The most common mistake in this area is to read "the proof verified" as "the user is private". These are different statements. A zero-knowledge proof in any of these systems attests a precise cryptographic claim — "I know the opening of an unspent leaf under this root", "this is a valid shielded transfer", "my withdrawal is disassociated from this flagged set" — and it attests that claim only under the circuit's constraints, the scheme's hardness assumption, and (where present) a sound setup ceremony.
None of those statements is "this output is private in practice". Practical privacy is an emergent property of the anonymity set and off-chain behaviour: pool size, timing, amount uniqueness, address reuse, relayer choice, and whether the chain is public around the shield. A flawless proof over an anonymity set of one hides nothing; a modest proof over a large, well-mixed set can hide a great deal. The proof and the privacy outcome must be reported as two separate facts.
synthetic — separating the two facts when evaluating a withdrawal (illustrative)# WRONG: collapsing proof validity into a privacy claim # if verify(proof): report("transaction is private") # non sequitur # RIGHT: report the attested statement and the measured outcome separately. proof_ok = verify(proof, public_inputs) # cryptographic statement # -> attests: valid membership/transfer/disassociation UNDER assumptions anon_set = count_indistinguishable(pool, denom, time_window) # measured linkable = behavioural_leaks(timing, amount, address_reuse, relayer) report({ "proof": proof_ok, # PROVEN: the stated claim, under assumptions "anonymity_set": anon_set, # measured quantity, not implied by the proof "practically_linkable": linkable, # may be true even when proof_ok is true }) # A valid proof + anon_set == 1 => verifiable AND de-anonymised.
PROVEN vs NOT PROVEN vs UNKNOWN stay distinct here. "The withdrawal proof verifies" is PROVEN (under its assumptions). "The user is unlinkable" is a separate claim that is PROVEN only if the anonymity set is measured and large; otherwise it is NOT PROVEN or UNKNOWN. Do not let a green checkmark on the first silently stand in for the second.
The evidence model (Rootchain / Rootzk)
For Rootchain and Rootzk the comparison above is the evidence model in miniature. When any of these systems produces a verifying proof, the honest report names the exact statement proven and the exact assumptions it rests on — the circuit constraints, the hardness assumption, the setup ceremony if there is one, the association set if the design uses one — and stops there. It does not upgrade "valid proof" into "private", "safe", "legitimate" or "compliant".
The practical privacy outcome is reported as a separate, measured quantity: the anonymity set for that action, and the behavioural factors that could collapse it. A compliance posture, where a system like Privacy Pools offers one, is reported as the specific disassociation claim it actually makes against a named set — never as a general certificate of clean funds. This is also why a feature comparison must be made at the functionality level: writing "✓ hides amount" for two systems hides that one proves it inside a SNARK and the other relies on a bounded ring, that one needed a ceremony and the other did not, and that they have very different deployment histories. Rootzk records each system's guarantee in its own terms, keeps PROVEN / NOT PROVEN / UNKNOWN apart, and refuses the false equivalence that a shared checkmark implies.
Exercise
Two teams both claim their system "hides the amount". Team A runs a Monero-style design (ring signatures + RingCT + stealth addresses); Team B runs a shielded-pool design with zero-knowledge proofs and an earlier trusted-setup ceremony. A reviewer produces a comparison table with a single "✓ hides amount" cell for both and concludes they are "equivalently private". Explain why that conclusion is unsound, naming at least three functionality-level differences the shared checkmark conceals, and state how you would report each system's guarantee honestly instead.
Expected direction: The conclusion is unsound because a shared feature checkmark is not feature parity and parity is not equivalent security or maturity. At least three concealed differences: (1) What is proven and under which assumptions — Team A hides amounts with range-proof commitments and a bounded, uniform per-input ring and needs NO trusted setup; Team B hides amounts inside a zero-knowledge proof whose soundness also rests on its setup ceremony being honest, so the two rest on different trust surfaces. (2) Anonymity-set model — Team A's hiding set is the ring size per input (bounded and fixed), while Team B's effective set depends on how much value is actually in the shielded pool (opt-in, so transparent use shrinks it); "hides amount" says nothing about either set size. (3) Maturity/compliance posture — length and breadth of deployment and review differ, and neither is read from the checkmark; a ceremony dependency and an opt-in pool are material facts the cell erases. Honest reporting: for each system, state the precise statement proven and its assumptions (PROVEN, under those assumptions), report the anonymity set as a separate measured quantity (PROVEN only if measured and large, else NOT PROVEN/UNKNOWN), and compare at the functionality level rather than collapsing both into one "private" verdict.
Check your understanding
- Why is a single "✓ hides amount" cell shared by two systems not evidence that they are equivalently private?
- Because feature presence is not feature parity, and parity is not equivalent security or maturity. The checkmark hides what statement each system actually proves and under which assumptions (e.g. a trusted-setup ceremony vs none), how large each one's anonymity set is and what controls it, and how long and broadly each has been deployed and reviewed. Honest comparison is made at the functionality level, naming those differences, not by ticking a shared list.
- What does a verifying zero-knowledge proof in these systems attest, and what does it NOT attest?
- It attests a precise cryptographic statement — e.g. valid membership, a valid shielded transfer, or disassociation from a flagged set — and only under the circuit's constraints, the scheme's hardness assumption, and any setup ceremony. It does NOT attest that the output is private in practice; practical privacy is an emergent property of the anonymity set and off-chain behaviour (pool size, timing, amount uniqueness, address reuse, relayer choice) and must be reported as a separate, measured quantity.
- How does Monero's guarantee differ from a fixed-denomination mixer's, at the functionality level?
- Monero hides sender, receiver AND amount on its own chain using ring signatures, RingCT and stealth addresses, with no trusted setup and a bounded per-input ring as the anonymity set. A fixed-denomination mixer hides ONLY the deposit↔withdrawal link at a public, fixed amount; it does not hide that the pool was used or the amount, and its anonymity set is the count of unspent same-denomination deposits, which collapses under tight timing or address reuse. Different things hidden, different sets, different assumptions.
- What specific kind of claim does a compliance-first Privacy Pool make, and why must it be reported precisely rather than as "clean funds"?
- It lets a user voluntarily prove that their withdrawal is disassociated from a named set of flagged deposits (an association/exclusion proof) while still hiding the specific link. It must be reported as exactly that — disassociation from a specified set under the proof's assumptions — because it is not a general certificate that the funds are legitimate or "clean"; reporting it as blanket compliance would overstate a statement that is only about a particular named set.
References
- [1]Banco ZK — Vol. II/III (2025): privacy-system families, anonymity-set models and setup assumptions — external educational reference
- [2]Monero project documentation — ring signatures, RingCT and stealth addresses, as publicly documented
- [3]Zcash protocol specification — the shielded pool and its parameter/setup model, as publicly documented
- [4]Buterin, Illum, Nadler, Schär & Soleimani — Blockchain Privacy and Regulatory Compliance: Towards a Practical Equilibrium (the Privacy Pools concept)
References point to public, well-known technical sources for further study.
Related articles
