Module 14 · Privacy protocols in practice: shielded pools, Railgun & the compliance frontier
Private Proofs of Innocence & privacy pools
A shielded pool hides who paid whom; the problem is that it hides it for everyone, including whoever just drained a bridge. A voluntary compliance layer tries to let honest users distinguish themselves without giving up privacy. Two dual designs dominate. Railgun's Private Proofs of Innocence (PPOI) require every spend to carry a zero-knowledge proof that the note being spent is NOT in a published blocklist — a non-membership statement bound to the spend's nullifier, revealing nothing about which note it is. The "Privacy Pools" paper (Buterin, Illum, Nadler, Schär, Soleimani) and deployed 0xbow-style implementations take the dual view: a withdrawal proves membership in a chosen association set of deposits the user vouches are clean. Both shrink the anonymity set to the chosen set and both rest on exactly the same honesty boundary: the proof attests only "this note is / is not in THIS set as published at THIS time, under these assumptions." It is a set-membership statement, not a verdict that funds are legitimate — and who curates the set, and who they can exclude, is a policy question the cryptography deliberately leaves open.
Learning objective
Understand the voluntary, compliance-oriented layer that newer shielded pools add on top of their core privacy: Railgun's Private Proofs of Innocence, where a user proves in zero knowledge that their note is NOT in a published blocklist without revealing which note it is; and the Buterin-et-al "Privacy Pools" design of association sets, where a user instead proves membership in a chosen "clean" set, with deployed 0xbow-style implementations. Then draw the sharp honest boundary: "innocence" here is a set-membership statement relative to a chosen set and a chosen blocklist at a chosen time — never a universal proof that funds are legitimate — and understand the policy tension of who curates the set.
- Track
- Research
- Module
- 14 · Privacy protocols in practice: shielded pools, Railgun & the compliance frontier
- Prerequisites
- Nullifiers, Merkle membership and the privacy-pool pattern · Non-membership proofs, compliance and proof-of-innocence · Merkle trees
Conceptual introduction
A shielded pool is privacy for everyone in it. That is its strength and its liability: the same anonymity set that protects an ordinary user also protects an attacker laundering stolen funds through the pool. The question these designs try to answer is narrow and voluntary: can an honest user publicly distinguish their funds from known-tainted funds, without revealing which deposit or note is theirs and without surrendering the privacy they joined the pool for?
The answer is a second proof layered on top of the ordinary spend. The core spend proof still says "I own a valid, unspent note" via a nullifier and a Merkle membership proof. The compliance layer adds a second zero-knowledge statement about a curated set — either "my note is NOT in this blocklist" or "my note IS in this clean association set" — bound to the same spend so the two cannot be mixed and matched. Both framings are dual and both are built from the membership / non-membership machinery covered in the prerequisite lessons; what is new here is how they are deployed, who curates the set, and the care required to not overstate what they prove.
Everything in this lesson is a statement about a specific set as published at a specific time. "Innocence" and "clean" are names for set-membership predicates chosen by a curator — not universal facts about the funds. Keep that qualifier attached to every claim; it is where the real-world meaning lives and where it is contested.
Railgun: Private Proofs of Innocence
Railgun is a real, deployed shielded-balance protocol: users shield assets into a pool and transact privately within it. Its Private Proofs of Innocence (PPOI) layer makes compliance the default without a gatekeeper. Each note has a nullifier-like identifier, and the system publishes a blocklist of identifiers associated with flagged sources. To spend or unshield, a user must attach a zero-knowledge proof that the note they are spending is NOT on the current blocklist — a non-membership proof — without revealing which note it is.
This is the exclusion framing: the default is "allowed", and only notes tied to listed sources fail. Because the proof is non-membership against a published blocklist root, an honest user proves dissociation from flagged funds while staying anonymous among all the other allowed notes; a spender whose note is on the list simply cannot produce the proof and so cannot complete the private spend. The anonymity set is "everyone not on this list" rather than "everyone in the pool".
synthetic — PPOI-style non-membership proof bound to the spend nullifier (illustrative)# PUBLIC INPUTS # nullifier = H(note_secret, leaf_index) # the spend's nullifier # blocklist_root = R_block # published blocklist root, time T # merkle_root = R_pool # pool commitment root # # PRIVATE WITNESS (never revealed) # note_secret, leaf_index, note_commitment # pool_path = Merkle path of note in R_pool # nonmember_witness = indexed-tree bracket for "nullifier NOT in R_block" # # CIRCUIT asserts, all in one proof: # 1. nullifier == H(note_secret, leaf_index) # nullifier well-formed # 2. verify(pool_path, note_commitment, R_pool) # note really in the pool # 3. verify_nonmembership(nonmember_witness, # same nullifier is ABSENT # nullifier, R_block) # from the blocklist # # REVEALS: only "the spent note's nullifier is not in R_block at time T". # Binding (2) and (3) to the SAME nullifier stops proving innocence for one # note while spending another. It says nothing about WHICH note, or its owner.
The binding is the load-bearing detail. The non-membership statement is about the very same nullifier the spend consumes, so a user cannot borrow a clean note's proof to launder a listed one. The verifier learns a single predicate — "the spent note is not on the blocklist as of this root" — and nothing about the note's identity, amount, or owner.
Privacy Pools: association sets (the dual)
The "Privacy Pools" concept — set out publicly by Buterin, Illum, Nadler, Schär and Soleimani — takes the dual view. Instead of proving absence from a blocklist, a withdrawal proves membership in a chosen association set: a published set of deposits the user is willing to associate with. On withdrawal the user proves, in zero knowledge, that their deposit is one of the members of a set whose root they name, without revealing which member it is.
The design's key insight is that the user chooses the set, and the set they choose is itself a signal. An honest user picks the broadest "clean" set that still excludes a known hack; a user who can only prove membership in a set that necessarily includes stolen funds has, by that very choice, revealed something. Deployed 0xbow-style implementations publish association sets and let withdrawers select which root to prove against. This is the inclusion framing: the default is "not in the set", and only members pass.
- Blocklist
- A published set of note/deposit identifiers tied to flagged sources (hacks, sanctioned entities). Used by PPOI as the thing to prove NON-membership against: pass by being absent. Default is "allowed".
- Association set
- A published set of deposits a user is willing to associate with and can prove MEMBERSHIP in. Used by the Privacy Pools design: pass by being present. Default is "excluded". The dual of a blocklist.
- ASP / set curator (association-set provider)
- The entity that defines, publishes and updates a set — a community, a protocol, or a compliance service. Different curators publish different sets with different restriction levels; the user chooses which root to prove against, but not what the curator put in it.
- Exclusion proof
- A zero-knowledge non-membership proof that a specific (private) element is absent from a published set at a given root — the cryptographic core of a PPOI-style "innocence" statement. Its dual is an inclusion (membership) proof against an association set.
Blocklist (PPOI) and association set (Privacy Pools) are duals of the same machinery: non-membership against a flagged set versus membership in a clean set. The cryptography is identical; the politics is not. Exclusion treats everyone as clean until listed; inclusion treats everyone as dirty until admitted. Who curates, how the set updates, and who is excluded by default or by error are policy choices the proof hides unless you state them.
The policy tension: who curates the set
Because both designs prove a statement about a curated set, the curator holds real power and the proof does not reveal how it was used. Three tensions recur and none is solved by cryptography. First, censorship versus compliance: a curator who can add an identifier to a blocklist, or omit a deposit from an association set, can exclude an honest user from private transacting with no protocol-level recourse. Second, centralisation: if one provider's set becomes the de-facto standard, choosing it is no longer voluntary in any meaningful sense. Third, false exclusion and false inclusion: a wrongly-listed address fails despite being clean, while a genuinely illicit source not yet on any list passes trivially.
The honest framings help but do not resolve this. Exclusion (PPOI) is permissionless-by-default and cannot silently bless a user who is simply not listed, but it depends on the blocklist being complete and current. Inclusion (association sets) lets users self-select the set they vouch for, shifting the signal to the user's own choice, but it makes the default "excluded" and gives curators a gate. The right design is a policy question about who should hold that power and how it is checked — not a theorem the proof can settle.
Evidence model: a proof attests non-membership, not cleanliness (ROOTVIEL)
When a verifier accepts a PPOI or Privacy Pools proof, it has established one precise, checkable fact: the private note or deposit is absent from (PPOI) or present in (association set) the set with this root, as published at this time, under the tree construction and commitment assumptions — and bound to the specific nullifier being spent. That is genuinely useful: it is a time-bound, set-relative, curator-named statement that a verifier can check for itself.
What it does NOT establish is everything the word "innocence" tempts a reader to assume. It does not establish that the set is correct, complete or current; that the curator is honest, neutral or uncompromised; that funds absent from a blocklist (or present in an association set) are lawfully obtained; or that a decision to trust those funds is correct. "Innocence" is a protocol label for a set-membership predicate — PROVEN is only the non-membership (or membership) statement under its assumptions; the funds' real provenance and legality are UNKNOWN to the proof, and whether acting on it is sound is NOT PROVEN by it.
For ROOTVIEL the discipline is strict: report such a proof as evidence about a specific published set at a specific time from a named curator, state whether it is exclusion (blocklist) or inclusion (association set), and never let "innocence" or "clean" in a protocol's vocabulary stand in for a legitimacy judgment the cryptography did not make. A valid proof against a set is not a verdict about a person or about where the money came from.
Exercise
A pool integrates Railgun-style PPOI: every private spend carries a zero-knowledge proof that the spent note is not in a blocklist root published by a single provider. A separate team proposes switching to a Privacy-Pools-style association set curated by the same provider. A product lead concludes: "Either way, a passing proof means the funds are clean and we can treat the user as compliant." Identify at least four things this conflates, explain how the exclusion (PPOI) and inclusion (association set) framings differ, and restate precisely what a passing proof does and does not establish.
Expected direction: Conflations: (1) Set-relative vs absolute — a PPOI proof shows ABSENCE from this blocklist, not that funds are clean; illicit funds not yet listed pass trivially. An association-set proof shows PRESENCE in a chosen set, not legitimacy of the underlying funds. (2) Time — the root is a snapshot; a proof reflects the set as published at that moment and says nothing about additions/removals since. (3) Curator trust — one provider defines the set, so completeness, correctness and neutrality all rest on it; a wrongly-excluded user fails with no protocol recourse, a missing entry passes. (4) Name vs verdict — "innocence"/"clean" are protocol labels for a set-membership predicate, not legal or moral findings. Framing difference: PPOI (exclusion) is non-membership against a blocklist, default "allowed" — everyone transacts until listed; Privacy Pools (inclusion) is membership in an association set, default "excluded" — only members pass, and the user's choice of set is itself a signal. Same cryptography, opposite defaults and opposite failure modes (false inclusion of unlisted illicit funds vs false exclusion of unlisted honest users). Precise restatement: a passing proof establishes that the spent note/deposit is absent from (or present in) the set with the given root as published at that time, under the tree/commitment assumptions, bound to the spend's nullifier — and nothing about the funds' actual provenance or legality, the set's accuracy or currency, the curator's honesty, or whether treating the user as compliant is correct. Treat it as one piece of time-bound, set-relative, curator-named evidence, not a clean-funds verdict.
Check your understanding
- What does a Railgun-style Private Proof of Innocence actually prove, and why is it bound to the spend's nullifier?
- It proves, in zero knowledge, that the spent note's identifier is NOT in a published blocklist at a given root and time — a non-membership statement revealing nothing about which note it is. It is bound to the same nullifier the spend consumes so a user cannot prove innocence for one (clean) note while actually spending a different (listed) one; binding the non-membership check and the spend to one nullifier stops that substitution.
- How does the Privacy Pools association-set design differ from PPOI, cryptographically and in framing?
- They are duals. PPOI is a non-membership proof against a blocklist (exclusion; default allowed — pass by being absent). Privacy Pools is a membership proof in a chosen association set (inclusion; default excluded — pass by being present), and the user's choice of which set to prove against is itself a signal. The membership/non-membership machinery is the same; the defaults, the party who selects the set, and the failure modes differ.
- Why is "innocence" a misleading word for what these proofs establish?
- Because it suggests a verdict that funds are clean or lawful, while the proof only establishes that a private element is absent from (or present in) a specific curated set as published at a specific time, under stated assumptions. It says nothing about the set's correctness or currency, the curator's honesty, the funds' real provenance or legality, or whether acting on it is safe. "Innocence"/"clean" are protocol labels for a set-membership predicate, not legal or moral findings.
- Name the main policy tensions created by having a curator define the set, and say why cryptography does not resolve them.
- Censorship vs compliance (a curator can exclude an honest user by listing them or omitting them, with no protocol recourse); centralisation (one provider's set becoming a de-facto standard makes "choice" illusory); and false exclusion / false inclusion (a wrongly-listed clean user fails, an unlisted illicit source passes). The proof only attests membership/non-membership against the set as given; who curates it, how it updates, and whether its contents are just are policy questions the cryptography deliberately leaves open.
References
- [1]Banco ZK — Vol. II/III (2025): private proofs of innocence, blocklists, association sets and exclusion/inclusion proofs — external educational reference
- [2]Buterin, Illum, Nadler, Schär & Soleimani — Blockchain Privacy and Regulatory Compliance: Towards a Practical Equilibrium (privacy pools / association sets)
- [3]Railgun — Private Proofs of Innocence, as documented by the protocol
- [4]0xbow — deployed association-set / privacy-pool implementation, as documented
References point to public, well-known technical sources for further study.
Related articles
