ROOTVIELROOTVIEL
← Academy

Module 14 · Privacy protocols in practice: shielded pools, Railgun & the compliance frontier

The privacy-protocol design space

There is no single "private blockchain" design — there is a design space, and every point in it trades scope of privacy against cost, composability and the adversary it resists. This lesson lays out five families: fixed-denomination mixers (hide the deposit↔withdrawal link within an anonymity set of equal amounts), shielded pools (note-commitment + nullifier, hiding sender, receiver and amount of shielded transfers), private smart-contract balances (encrypted or committed state with ZK state transitions), private rollups (execution and state hidden off-chain, only proofs posted), and chain-level privacy (the whole ledger is confidential by default, e.g. ring signatures + stealth addresses + confidential amounts). Two mental models organise them: the UTXO-note model (spend-and-recreate notes, nullifiers prevent double-spend) and the account model (a persistent balance whose updates are proven). Across all of them, privacy is defined against a specific threat model — a chain observer, a relayer or broadcaster, a network-level observer, or physical coercion — and the thing that actually hides a user is the anonymity set, a quantity you measure, not a property the proof guarantees.

Learning objective

Build a map of how real on-chain privacy systems are actually constructed and, for each family, state precisely what it hides and what it leaks. Cover fixed-denomination mixers, shielded pools (note-commitment + nullifier), private smart-contract balances, private rollups and chain-level privacy; the two mental models (UTXO-note vs account); and the threat model (chain observer, relayer/broadcaster, network, physical coercion). The through-line: "private" is always private against a specific adversary, and the anonymity set that quantifies it is a measured quantity, never something the proof asserts.

Track
Research
Module
14 · Privacy protocols in practice: shielded pools, Railgun & the compliance frontier
Prerequisites
What is a zero-knowledge proof · Nullifiers, Merkle membership and the privacy-pool pattern · Ring signatures and stealth addresses

Conceptual introduction

A transparent ledger publishes every sender, receiver and amount forever, and most chains are transparent by construction. "On-chain privacy" is not one feature bolted on afterwards; it is a family of distinct designs, each hiding a different subset of {sender, receiver, amount, contract state, graph structure} and each paying for it differently. The useful move is to stop asking "is this chain private?" and start asking "which of these fields does this design hide, from which observer, and how large is the set it hides the user inside?"

This lesson maps the space. We walk five families from the narrowest to the broadest, give the two mental models (UTXO-note vs account) that most designs reduce to, and fix a threat model so that every privacy claim is stated against a named adversary. The claims stay honest: a protocol can hide a field perfectly in theory and still leak it entirely through timing, amounts, address reuse or network metadata. Privacy is measured at the level of the whole system and its users, not the cryptographic core alone.

Note

"Private" with no adversary named is not a claim — it is marketing. Every family below defends against a specific observer and is silent against others. A design that hides your receiver from a chain observer may expose it to the relayer that broadcast your transaction, or to anyone watching the mempool, or to anyone who can compel you to decrypt. State the adversary first; then the privacy claim means something.

The threat model: against whom?

Before comparing designs, fix the adversaries. Each family resists some of these and is defenceless against the rest, and the difference between a sound system and a false sense of safety is almost always a confusion about which adversary is in scope.

Chain observer
Anyone who reads the public ledger after the fact — explorers, chain-analysis firms, researchers. Sees all on-chain data, can correlate across time and addresses, and never forgets. This is the default adversary most privacy designs target, and the one the cryptography is built against.
Relayer / broadcaster
The party that submits your transaction when you cannot (to avoid linking a fresh address to a funded one, or to pay gas from shielded funds). It necessarily learns something the chain observer does not — often your recipient, IP, or the timing — and a protocol that hides a field from the chain may still hand it to the relayer. Trust in the relayer is a separate assumption that must be stated.
Network observer
Whoever watches the peer-to-peer and mempool layer: ISPs, node operators, mempool watchers. Links transactions to IP addresses and to each other by propagation timing, defeating on-chain privacy entirely if the user does not add network-level protection (Tor/mixnets, private mempools). Cryptography on the ledger says nothing about this layer.
Physical / legal coercion
An adversary who can compel the holder to reveal keys, decrypt notes, or sign a withdrawal. No on-chain privacy design resists this; it is outside the cryptographic threat model by nature. Encryption hides data from observers, not from someone standing over the person who holds the key.

Keep these distinct in every review. A statement like "the amount is hidden" is incomplete until it reads "the amount is hidden from a chain observer, assuming the user did not disclose it to the relayer and did not reveal it through a unique value." The cryptographic guarantee is narrow; the system guarantee is the intersection of the cryptography and user behaviour against each adversary in turn.

Two mental models: UTXO-note and account

Almost every design in the space reduces to one of two state models, and knowing which one a protocol uses tells you immediately how it prevents double-spends and where its privacy lives.

In the UTXO-note model, value lives in discrete notes. Spending a note does not mutate it; instead the spender proves ownership of an unspent note, publishes a nullifier that marks it spent, and creates one or more fresh output notes as commitments. Double-spend prevention is the nullifier set: a note can only be nullified once. Privacy comes from the fact that the proof reveals membership in the set of all notes without revealing which note, and the new commitments are unlinkable to the old ones. This is the shielded-pool and mixer lineage.

In the account model, value is a persistent balance attached to an identity, and a transfer mutates balances. To make this private, the balance is held as an encrypted or committed value and every update is accompanied by a zero-knowledge proof that the transition is valid (the sender had the funds, no value was created) without revealing the amounts. Double-spend prevention is the account nonce/ordering, as on a transparent chain; privacy comes from encrypting the state and proving transitions over ciphertext/commitments. This is the private-balance and some private-rollup lineage.

Note

The models are not strictly better or worse. UTXO-note systems give strong unlinkability but awkward programmability and a wallet that must scan for its notes; account systems compose naturally with smart contracts but tend to leak the transaction graph (who interacts with whom) even when amounts are hidden. Many real systems are hybrids. Identify the model before judging the privacy.

The five families: what each hides and what leaks

Here is the core map. Each family is a real, deployed pattern (named protocols are public and cited generically in the references). Read the table as "against a chain observer, by default" — the leaks column lists what is exposed on-chain even when the design works exactly as intended, before any user-behaviour leaks are added.

FamilyModelHidesLeaks (even when working)
Fixed-denomination mixerUTXO-noteThe link between a specific deposit and a specific withdrawal, within an anonymity set of equal-amount depositsThat a deposit and a withdrawal happened; the (fixed) amount; pool membership; timing; the relayer, if used
Shielded poolUTXO-noteSender, receiver and amount of shielded transfers; the link between shielded in/outThat a shielded transaction occurred; shielding/unshielding events at the transparent boundary; total pool value
Private smart-contract balancesAccountPer-account balance and transfer amounts (encrypted/committed state)The transaction graph (which accounts interact, and when); contract identity; call patterns
Private rollupAccount or note (off-chain)Execution and state of transactions processed off-chain; often amounts and parties inside the rollupThat the rollup advanced; the validity proof and state root; deposit/withdrawal at the L1 bridge; aggregate footprint
Chain-level privacyNote / stealth-accountSender (ring/decoy set), receiver (stealth address), amount (confidential amounts) — by default for all transfersThat a transaction occurred; approximate decoy-set structure; timing; metadata at the network layer

Reading the table top to bottom is reading increasing scope. A mixer hides one link for one fixed amount; a shielded pool hides the three core fields for transfers that stay shielded; private balances move privacy into general computation but expose the interaction graph; private rollups hide whole execution but reveal the L1 boundary; chain-level privacy makes confidentiality the default for every transfer but still cannot hide that activity is happening or protect the network layer. Nothing on the list hides the fact that something occurred, and nothing on the list resists coercion.

synthetic — the same question, asked of each family (illustrative)
# For any privacy design, answer these before trusting a privacy claim: # fields_hidden subset of {sender, receiver, amount, state, graph} # adversary {chain_observer, relayer, network, coercion} # anonymity_set a MEASURED number n (deposits/notes you blend into) # boundary_leaks what the transparent<->private boundary reveals # # Example — fixed-denomination mixer, chain observer: # fields_hidden = {link(deposit, withdrawal)} # NOT the amount # adversary = chain_observer # NOT the relayer # anonymity_set = n = (# unspent same-denom deposits at withdrawal time) # boundary_leaks = {deposit happened, withdrawal happened, amount} # # A claim is only as strong as the WEAKEST unchecked line above.

The anonymity set is measured, not proven

The recurring honest limit across every family is that the cryptography can be flawless while the privacy is zero, because privacy at the system level is governed by the anonymity set — the number of indistinguishable alternatives an observer cannot rule out — and that number is a property of the pool size and user behaviour, not of the proof. With n indistinguishable candidates, the best a chance guess does is 1/n; as n falls to 1 the user is hidden among exactly themselves.

Behaviour collapses the set in ways no proof prevents: depositing and withdrawing within minutes, using a one-off amount, reusing an address across the privacy boundary, always choosing the same relayer, or leaking the receiving IP at the network layer. In chain-level designs the decoy/ring set is finite and sometimes guessable; in shielded pools an observer can watch the transparent shielding and unshielding events at the boundary. In every case the right way to report privacy is to report the field-level cryptographic claim and, separately, the measured anonymity set — never to let the existence of a proof imply the set is large.

Note

PROVEN vs NOT PROVEN, kept distinct: a verifying proof PROVES the stated transition (valid spend, correct amount hidden, membership). It does NOT prove that the anonymity set is large, that the user was not deanonymised by metadata, or that any particular observer failed to link the transaction. "The amounts are confidential" (a cryptographic property) and "this user is actually anonymous" (a measured, often small, empirical property) are different claims, and conflating them is the most common dishonest move in privacy marketing.

Reading the guarantee honestly (Rootchain / Rootzk)

This map is the frame for how Rootchain and Rootzk treat any privacy claim as evidence. When a proof in one of these systems verifies, it attests to a specific, bounded statement — membership of a note, ownership of a spend authority, validity of a state transition, correctness of a hidden amount — and it attests to that statement only under the circuit's constraints, the commitment scheme's assumptions and correct Fiat–Shamir. That is the whole of what a valid proof says.

A valid proof is never evidence that funds are clean, that a source is legitimate, or that the privacy the user wanted was actually achieved. Those are claims about provenance, intent and the empirical anonymity set — and the first two are outside cryptography entirely while the third is a measured quantity reported separately. So Rootzk outputs the attested statement and its assumptions as one artifact, and reports the anonymity set and the threat model as distinct, measured facts beside it. Membership and ownership are PROVEN under assumptions; "clean", "safe" and "anonymous" are NOT PROVEN by any proof and must be labelled UNKNOWN unless established by separate, non-cryptographic evidence.

Exercise

Note

A team says: "Our chain gives you full privacy — sender, receiver and amount are all hidden by default, verified by zero-knowledge proofs, so your transactions are anonymous." Using the design-space map and the threat model, (a) classify which family this is, (b) list at least three things that still leak or are still exposed even if the cryptography is perfect, naming the adversary for each, and (c) explain the single most important correction to the word "anonymous" in their claim.

Expected direction: (a) Hiding sender, receiver and amount by default for all transfers is chain-level privacy (the Monero-style lineage: decoy/ring set for the sender, stealth addresses for the receiver, confidential amounts). (b) Even with perfect cryptography it still leaks: that a transaction occurred at all (chain observer — no design hides activity); network-layer metadata linking the transaction to an IP and to other transactions by propagation timing (network observer) unless Tor/a mixnet is used; the finite decoy/ring structure and timing, which a chain observer can sometimes exploit to narrow candidates; and nothing resists an adversary who can coerce the holder to reveal keys (physical/legal coercion). (c) The key correction: "anonymous" conflates a cryptographic field-hiding property with an empirical anonymity-set property. The proof proves the fields are hidden from a chain observer under its assumptions; it does NOT prove the anonymity set is large or that the user was not deanonymised by timing, amounts, address reuse or network metadata. Anonymity is a measured quantity against a named adversary, not something the proof guarantees — so the honest claim is "amounts and parties are confidential against a chain observer under stated assumptions," with the anonymity set reported separately.

Check your understanding

Why is naming the adversary a precondition for any privacy claim, and what are the four adversaries in the lesson's threat model?
Because every family hides some fields from some observers and is defenceless against others, so a claim with no adversary named cannot be evaluated. The four adversaries are: a chain observer (reads the public ledger and correlates forever), a relayer/broadcaster (submits the transaction and necessarily learns more than the chain), a network observer (watches the P2P/mempool layer and links transactions to IPs by timing), and physical/legal coercion (can compel the holder to reveal keys — outside the cryptographic model entirely).
Distinguish the UTXO-note model from the account model, including how each prevents double-spends.
In the UTXO-note model value lives in discrete notes; spending proves ownership of an unspent note, publishes a nullifier to mark it spent, and creates fresh output commitments — double-spend prevention is the nullifier set (a note can be nullified only once), and privacy comes from unlinkable commitments plus membership proofs. In the account model value is a persistent balance; transfers mutate encrypted/committed balances with a ZK proof of valid transition, double-spend prevention is the account nonce/ordering as on a transparent chain, and privacy comes from encrypting state — but the transaction graph tends to leak.
A fixed-denomination mixer and a shielded pool both use the UTXO-note model. What does the shielded pool hide that the mixer does not?
The mixer hides only the link between a specific deposit and a specific withdrawal within an anonymity set of equal-amount deposits — the fixed amount itself is public and that a deposit/withdrawal happened is public. A shielded pool hides the sender, receiver and amount of transfers that stay inside the shielded set, not just one link, though it still leaks that a shielded transaction occurred and exposes the shielding/unshielding events at the transparent boundary.
Why can a privacy system have flawless cryptography and still provide no real privacy, and how should the two be reported?
Because system-level privacy is governed by the anonymity set — the number of indistinguishable alternatives, a property of pool size and user behaviour, not of the proof. Immediate withdrawals, unique amounts, address reuse, a fixed relayer or a leaked IP can collapse the set to one while every proof still verifies. They should be reported separately: the field-level cryptographic claim (PROVEN under assumptions) on one side, and the measured anonymity set against a named adversary on the other — never letting a verifying proof imply the set is large.

References

  1. [1]Banco ZK — Vol. II/III (2025), chapters on ZK privacy infrastructure (shielded pools, nullifiers, anonymity set, confidential amounts) — external educational reference
  2. [2]Hopwood, Bowe, Hornby & Wilcox — Zcash Protocol Specification (shielded pools: note commitments, nullifiers, Sapling/Orchard), as publicly documented
  3. [3]van Saberhagen / the Monero project — CryptoNote and Monero (ring signatures, stealth addresses, RingCT confidential amounts), as publicly documented
  4. [4]Pertsev, Semenov & Storm — Tornado Cash (fixed-denomination mixer: commitment + Merkle membership + nullifier), as widely documented
  5. [5]Williamson et al. — Aztec (private smart-contract state and private rollup over ZK proofs), as publicly documented
  6. [6]Railgun — shielded-pool privacy system for smart-contract assets, as publicly documented
  7. [7]Buterin, Illum, Nadler, Schär & Soleimani — Blockchain Privacy and Regulatory Compliance: Towards a Practical Equilibrium (Privacy Pools)

References point to public, well-known technical sources for further study.

Related articles