Breaking the link, not hiding the coin
The previous guide left you with a sobering picture: chain analysts cluster your addresses using common-input-ownership and change-detection heuristics, then pin one of those addresses to your real name the moment it touches a KYC exchange. Mixers are the first counterattack, and it helps to be precise about what they attack. A mixer does not hide that a coin exists, and (mostly) does not hide its amount. It attacks the single most valuable thing a chain analyst has: the thread connecting the coin you deposited to the coin you later withdrew. Cut that thread and the cluster falls apart.
A useful mental model is a coat check at a crowded station. You hand in a $20 bill; hundreds of other people hand in their own $20 bills into the same drawer; later you collect a $20 bill — not your $20. You get back identical value, but no observer can match the bill you walked out with to the bill you walked in with. The crowd of people who could have been the source of your bill is your anonymity set, and its size is the single number that decides how well you are hidden. Every design in this guide is really a different machine for building that crowd.
We will look at three flavours, in order of increasing trust-minimisation. CoinJoin uses no custodian at all — independent users collaborate on one shared transaction. A custodial tumbler is the old, convenient way — you trust an operator who pools everyone's coins and pays you back from unrelated ones. And a zero-knowledge pool like Tornado Cash replaces the operator entirely with a smart contract and a zero-knowledge proof, so you trust only the code and the math. Then we confront the hard part that no amount of cleverness erases: the metadata these tools still leak, and the sanctions they have attracted.
CoinJoin: many wallets, one transaction
CoinJoin, proposed by Bitcoin developer Gregory Maxwell in 2013, is the most elegant idea in this guide. Recall the common-input-ownership heuristic: when a transaction spends inputs from addresses A and B, analysts assume one wallet owns both, because normally you must sign with every input's private key. CoinJoin weaponises the exception. Several independent users jointly build one transaction — each contributing their own inputs and each signing only their own. Now "signed together" no longer implies "same owner," and the heuristic confidently merges strangers into a single phantom entity. The chain analyst's most reliable rule has just been poisoned.
The magic ingredient is equal-value outputs. If Alice puts in 1.013 and receives 0.9 while Bob puts in 1.020 and receives 1.1, an observer can still re-link them by amount. So a good CoinJoin pays every participant an identical output — say exactly 1.0 BTC each — and returns any remainder separately as change. With three indistinguishable 1.0 outputs, there are 3! = 6 ways to map inputs to outputs, and the observer cannot tell which input funded which output. Those equal outputs are the anonymity set: the more equal-output peers in the round, the larger the crowd.
// A 3-party equal-output CoinJoin (Bitcoin), as a block explorer shows it.
// Alice, Bob and Carol each put in one input and each take one 1.0-BTC
// output. The 1.0 outputs are IDENTICAL, so no one can match a given
// input to a given output.
{
"txid": "c01n...j01n",
"vin": [
{ "addr": "bc1q...ALICE", "value": 1.013 }, // signed only by Alice
{ "addr": "bc1q...BOB", "value": 1.020 }, // signed only by Bob
{ "addr": "bc1q...CAROL", "value": 1.008 } // signed only by Carol
],
"vout": [
{ "addr": "bc1q...OUT1", "value": 1.000 }, // whose? unknowable
{ "addr": "bc1q...OUT2", "value": 1.000 },
{ "addr": "bc1q...OUT3", "value": 1.000 },
{ "addr": "bc1q...CHG_A", "value": 0.012 }, // each gets change back
{ "addr": "bc1q...CHG_B", "value": 0.019 }, // to a SEPARATE output
{ "addr": "bc1q...CHG_C", "value": 0.007 }
]
// fee = (1.013+1.020+1.008) - (3*1.000 + 0.012+0.019+0.007) = 0.003
}
// common-input-ownership now FAILS: three different wallets signed, not one.
// And the three equal 1.0 outputs are interchangeable: 3! = 6 possible maps.Crucially, CoinJoin is non-custodial: no one ever holds anyone else's coins. The transaction is valid only if everyone signs, and each person signs only after checking that their own equal output is present and correct. So a malicious coordinator can at worst refuse to proceed — it can never steal. A coordinator (or a decentralised matching protocol like JoinMarket) simply helps strangers find each other and assembles the unsigned template; the security comes from the signatures, not from trusting the matchmaker. Wasabi (using the WabiSabi protocol) and Samourai's Whirlpool were the best-known consumer implementations.
Why isn't one round enough? A single CoinJoin with three peers gives an anonymity set of only ~3. Real privacy comes from many rounds with many peers, repeatedly remixing, so each coin's set of possible origins compounds across rounds. But every round costs a fee and leaks timing, and the change outputs are the weak point: if you later spend a freshly mixed 1.0 output together with its own change in one transaction, the common-input heuristic re-merges them and can unravel the whole mix. Good wallets isolate change into separate accounts precisely to stop this.
Custodial tumblers: convenient, and a leap of faith
The oldest and simplest mixer is a custodial tumbler (a cryptocurrency tumbler). You send coins to the operator's address; they drop your coins into a large pool fed by many users, wait a while, and send you back the same value minus a fee — but from unrelated coins, to a fresh address you control. On-chain, your deposit and your payout share no traceable link, because the operator's pool sits between them like a curtain.
The catch is total custodial trust, and it cuts three ways. (1) Theft. The operator literally holds your coins between deposit and payout and can simply keep them — the classic exit scam. (2) Logs. They can record exactly which deposit maps to which payout; if they keep that private ledger, your privacy is one subpoena, one hack, or one disgruntled insider away from total collapse. (3) Taint. The pool may contain proceeds of crime, so you might receive "dirty" coins flagged by taint analysis and frozen the moment you try to deposit them at an exchange. You are trusting a stranger's honesty, their operational security, and the cleanliness of a pool you cannot inspect.
History is unkind here. The operators of Helix and Bitcoin Fog were prosecuted and convicted of money laundering, and investigators showed in several cases that these services did keep records that helped deanonymise their users — the opposite of what customers paid for. ChipMixer was seized by Europol in 2023. The lesson is structural: a custodial mixer replaces the chain's transparency with a single point of trust and a single point of failure — exactly the thing blockchains were invented to remove.
Zero-knowledge pools: prove membership, reveal nothing
The cleverest mixer design is a zero-knowledge privacy pool, made famous by Tornado Cash on Ethereum. It is non-custodial like CoinJoin but, instead of one shared transaction, it uses two separate, unlinkable steps — a deposit now and a much-later withdrawal — bridged by a zero-knowledge proof. The construction reuses the Merkle tree, commitment, and nullifier machinery you will meet again in the very next guide on Zcash.
Deposit. Pools come in fixed denominations — Tornado Cash ran separate 0.1, 1, 10, and 100 ETH pools — so every deposit into a pool looks exactly alike. To deposit, your wallet generates two secret random numbers, a secret and a nullifier, and posts only their hash: a commitment. The contract appends that commitment as a leaf to a Merkle tree and escrows exactly one denomination of ETH. The chain learns only that a deposit of the fixed size happened; the commitment itself reveals nothing linkable about who or which future withdrawal.
Withdraw. Later — ideally much later, from a fresh address with no other history — you withdraw by submitting a zk-SNARK that proves three facts at once: you know a `(secret, nullifier)` pair whose commitment is some leaf under the current Merkle root; and that nullifier hashes to a tag you publish. The proof never says which leaf. The contract verifies the proof, checks that the revealed nullifier-hash has never been used before (blocking any second withdrawal of the same deposit), records it, and releases one denomination to any recipient you name.
# A zero-knowledge privacy pool (Tornado-Cash-style), denomination = 1 ETH. # # DEPOSIT (public on chain): # secret, nullifier = random(), random() # kept PRIVATE by the depositor # commitment = hash(nullifier, secret) # the only thing posted # tree.insert(commitment) # appended as a Merkle leaf # contract escrows exactly 1 ETH # # WITHDRAW (public on chain) -- to a FRESH recipient address: # PUBLIC inputs: root # current Merkle root over all commitments # nullifierHash # = hash(nullifier) # recipient # any address you choose # PRIVATE witness: secret, nullifier, merklePath # # the zk-SNARK proves, revealing nothing else: # 1. commitment == hash(nullifier, secret) # well-formed note # 2. MerkleVerify(merklePath, commitment) == root # it IS in the pool # 3. nullifierHash == hash(nullifier) # the right one-time tag # # contract: verify(proof) AND nullifierHash is UNUSED # -> mark nullifierHash spent, send 1 ETH to recipient # # The proof never reveals WHICH leaf, so the withdrawal could match ANY # deposit in the tree. That set of deposits is your anonymity set.
Two practical details make it work. First, a relayer. A brand-new withdrawal address holds no ETH to pay gas, and funding it from your own wallet would immediately re-link you to the withdrawal. So a third-party relayer broadcasts the withdrawal transaction on your behalf and takes its fee out of the withdrawn amount, leaving the recipient address pristine. Second, the nullifier is the trick that lets a public, anonymous pool prevent double-spends without ever learning who you are: it is a one-time, deterministic tag derived from your deposit, usable exactly once. Reveal it and you can withdraw; the contract simply refuses any nullifier-hash it has seen before.
The anonymity set, made concrete
Everything above buys exactly one thing: an anonymity set — the set of deposits an observer must treat as the possible source of your withdrawal. The bigger the set, the better you are hidden, and we can put a number on it. If `k` indistinguishable deposits could each have funded your withdrawal, an observer's best single guess is correct with probability `1/k`. A set of 2 is almost worthless; a set of 10,000 is genuinely strong. Let us walk one withdrawal through a real-sized pool.
- Start. A 1-ETH zero-knowledge pool already holds 5,000 un-withdrawn deposits. You deposit 1 ETH; the tree now has a 5,001st commitment that is byte-for-byte indistinguishable from the rest.
- Wait. Over the next two weeks, hundreds more people deposit and withdraw, churning the pool. Crucially, you do not touch your deposit during this window — patience is what builds the crowd.
- Withdraw. You submit your zk-SNARK and 1 ETH lands at a brand-new address via a relayer. The contract emits a withdrawal event, but the proof hides which of the thousands of commitments it consumed.
- The observer's problem. Your 1 ETH could have come from any deposit still un-withdrawn at that moment — say ~5,200 of them. Your anonymity set is ~5,200, so a naive guess at the source is right only ~0.02% of the time. That improbability is precisely the privacy a large, busy pool buys you.
Now the honest part — how that set silently shrinks. (1) Amount. Only same-denomination deposits are candidates; deposit a weird amount, or split it oddly, and you carve yourself out of the crowd. (2) Timing. Deposit and withdraw seconds apart and an analyst can pair them directly; your true set is only "deposits plausibly present at your withdrawal time," not the pool's all-time total. (3) The connected-components attack. If you deposit from address X and withdraw to address Y, then later send Y's funds back to X — or to an exchange already linked to X — you have handed the analyst both endpoints and collapsed your own anonymity set to 1. (4) Fingerprints. Reused relayers, idiosyncratic gas settings, and unusual round amounts all leak. Most real-world deanonymisations of mixers come from these user errors, not from broken cryptography.
Sanctions, courts, and the search for a middle path
A tool that severs on-chain links is equally useful to a whistleblower protecting a sensitive donation, an ordinary person who simply doesn't want their salary or net worth public, and a thief laundering stolen coins. Regulators focus on the last. On 8 August 2022, the US Treasury's Office of Foreign Assets Control (OFAC) added Tornado Cash to its SDN sanctions list — the first time autonomous software, rather than a person or company, was sanctioned. OFAC stated the protocol had been used to launder over $7 billion, including hundreds of millions for North Korea's Lazarus Group. Overnight, interacting with the contracts became legally fraught for US persons, and front-ends, relayers, and even code repositories went dark.
The legal aftershocks were severe and are still unfolding. In the Netherlands, developer Alexey Pertsev was convicted of money laundering in May 2024 and sentenced to over five years. In the US, the Department of Justice charged co-founders Roman Storm and Roman Semenov in 2023, and Storm's trial proceeded in 2025. Underneath the cases sits one unresolved question that the whole industry is watching: *is writing and deploying neutral, immutable privacy software itself a crime — or is it protected tooling and speech that some users go on to abuse?*
The sanctions themselves were partly rolled back. In Van Loon v. Treasury (November 2024), the US Fifth Circuit ruled that Tornado Cash's immutable smart contracts are not "property" that anyone can own or control, so OFAC had exceeded its statutory authority in sanctioning them. In March 2025, OFAC formally delisted Tornado Cash. The criminal cases against specific individuals nonetheless continued — drawing a deliberate line between the code (which a court found could not simply be sanctioned as property) and the conduct of particular people accused of knowingly operating a laundering service.
Out of this collision came a serious attempt at a middle path: Privacy Pools, proposed in a 2023 paper co-authored by Vitalik Buterin and others. The idea is selective, voluntary compliance. When you withdraw, your zero-knowledge proof additionally demonstrates that your deposit belongs to an association set of provably legitimate deposits — and, equivalently, is not among a published set of known-illicit ones — all without revealing which deposit is actually yours. Honest users can cryptographically dissociate themselves from criminal funds while keeping their own privacy intact; the pool stops being all-or-nothing. This proof-of-innocence spirit is the same one behind the viewing keys and selective disclosure you will meet in this rung's final guide on privacy versus compliance.