|=[ RESEARCH :: FILE 01C ]=

HOW PRIVATE IS PRIVACY POOLS?

PRIVACY POOLS · V1 MAINNET · ~14,000 TRANSACTIONS

Privacy Pools v1 lets users deposit specific tokens, prove they are not associated with illicit funds, and withdraw them to a fresh address without revealing which deposit is yours. Since inception there have been ~14,000 transactions on Privacy Pools' Ethereum Mainnet instance, and I applied statistical methods and heuristics across all of them to see how users are using the protocol, and how private the compliant mixer is.

ORIGINAL RESEARCH 7 HEURISTICS AGGREGATED DATA

DATA — 31.03.2025 → 09.08.2026 · ETHEREUM MAINNET

6,333
Deposits
v1 · Ethereum pools
7,944
Withdrawals
v1 · Ethereum pools
14.4%
Self-linked withdrawals
1,145 to the depositing address
~9
Crowd after a root update
rush withdrawals, confidence 0.82
50.4 ETH
Loneliest withdrawal
6 possible funders, ever

EVERY V1 MAINNET EVENT, RE-INDEXED FROM THE CONTRACTS

WHAT IS A MIXER DOING WITH AN APPROVAL LIST?

Blockchains are transparent by design, but many users want to have onchain privacy, and there are many mixers that help users obfuscate funds. Your funds are deposited into a shared pool, you wait, and then later withdraw to a fresh address. As your funds are pooled with others, an onlooker cannot tell which withdrawal belongs to which deposit, and the larger the pool is, the better the anonymity.

Tornado Cash is the most famous mixer. The US government sanctioned it in 2022 after stolen funds, including hundreds of millions taken by North Korean hackers, were washed through the same pot as everyone else's. The sanctions were ruled unlawful and lifted in 2025, but the message had already been sent.

Privacy Pools was built by 0xbow and has been live on Ethereum since March 2025, designed with compliance in mind. You deposit publicly into the pool, and wait for it to be approved and accepted into the Association Set, which screens out illicit funds. To withdraw your funds, you need to prove you own the funds, and that it was accepted by the Association Set Provider (ASP). This is the pitch: privacy for you, a compliance story for the regulator.

WHAT I ACTUALLY DID

Every action on Privacy Pools v1 emits a public event from the smart contracts, which can be [re]-indexed and investigated for links between deposits and withdrawals. Between the launch and 9th August 2026, there were 6,333 deposits and 7,944 withdrawals in the Ethereum pools.

Given this public record, I asked the question: "How often can you work out which deposit paid for which withdrawal?" If you're watching a cloakroom from across the street, you can't see what happens inside, but you can see which coat goes in, which coat comes out, and when they do it. This allows you to infer quite a lot.

A steady hum of activity

6,333 deposits and 7,944 withdrawals, weekly, March 2025 – August 2026

0300600900 deposits withdrawals Apr 25 Jul 25 Oct 25 Jan 26 Apr 26 Jul 26 launch week: 293 depositsMar 31 2025 one spam contract: 820 zero-valuedeposits in a single day (May 24 2025)* busiest withdrawal week: 358week of Mar 23 2026 * excluded from the value-based charts in this essay
Weekly event counts from our own re-indexing of the Privacy Pools Ethereum contracts. The spam burst adds address-count cover but no money; the value charts in this essay exclude it.
A steady hum of activity — 6,333 deposits and 7,944 withdrawals, weekly, March 2025 to August 2026

USDT pool dominates

gross deposited vs withdrawn volume per pool, in USD (ETH converted at $1,920, avg price 10 Aug 2026)

0 $2M $4M $6M $8M USDT $8.56M $2.55M ETH $7.04M $5.03M USDC $4.39M $2.95M fxUSD $1.75M $1.17M BOLD $50.3k $0.3k USDS $13.0k $3.1k frxUSD $11.7k $1.0k DAI $11.5k $5.7k yUSND $4.6k $1.7k deposited (gross) withdrawn + fees
Withdrawn volume includes relayer fees (gross). Stablecoin pools are shown in their $-pegged token units; the ETH pool is converted at $1,920 per ETH (average price, 10 August 2026): ~$7.0M in, ~$5.0M out.
USDT pool dominates — gross deposited vs withdrawn volume per pool, in USD

SEVEN METHODS

I applied seven different ways an observer might be able to connect a withdrawal back to its deposit, ranking them by most deanonymising first. The rank is a product of:

  • Coverage - the size of the population a chosen heuristic can touch
  • Certainty - the strength of the deanonymisation for users in that population

There are some methods that can directly deanonymise users with ease, and some methods that are completely useless. I measured some of these leaks in bits, which measure the amount of unpredictability in the dataset, with each bit halving the crowd you can hide in. For example, 10 bits halves the crowd 10 times.

#1 Reusing the same address.

14.4% (1,145) of Ethereum withdrawals are users withdrawing to the same address they deposited from.

The whole point of using Privacy Pools is you can withdraw your funds to a new address, that has no history. Yet, one in seven withdrawals go to the exact same address, and 50.4% of those users withdrew the same amount, less fees, as they deposited. This heuristic is ranked number one as we can put a full certainty that these users deposited and withdrew to the same address, and threw away their potential anonymity in doing so.

This is not a failure of the protocol design, but a user-hygiene failure, and something that can be solved in v2 of the project.

One withdrawal in seven reuses a deposit address

1,145 of 7,944 withdrawals (14.4%) go back to an address that had already deposited into the same pool

0% 10% 20% 30% 40% ETH 5,502 withdrawals 18.1% USDC 1,544 withdrawals 5.6% USDT 681 withdrawals 2.9% fxUSD 114 withdrawals 16.7% wstETH 37 withdrawals 13.5% BOLD 27 withdrawals 40.7% tiny sample — take lightly all pools: 14.4%
Row-level join: a withdrawal counts if its recipient address appears among the pool’s earlier depositors (deposit time ≤ withdrawal time). Whatever the zero-knowledge proof hid, reusing the address re-links it publicly. Pools with fewer than 20 withdrawals not shown.
Address reuse — withdrawals sent back to the depositing address
#2 Unique amounts are your fingerprint.

9.8% (777) of Ethereum withdrawals can be identified due to the use of weird, unique amounts for deposits and withdrawals.

Mixers like Tornado Cash force users to deposit in fixed sizes: 0.1 ETH, 1 ETH, 10 ETH, precisely so that amounts couldn't identify you. Privacy Pools v1 dropped that feature for user convenience. This means that depositing an amount of 0.48732951 ETH and then withdrawing a similar amount minus the relayer fee, combined with the odds that two unrelated people choose the same eleven digit number are effectively zero, and you can be easily identified. There is a near-certainty for this method, with a median of 11.6 bits.

The instinct is that a random number blends in. It does the opposite. Privacy Pools anonymity comes from how many people share your set, and a majority of users deposit round numbers, where thousands of deposits look identical on withdrawal. The careful majority is untouched by this leak.

One in four deposits is exactly 0.1 ETH — the rest name themselves

4,215 real ETH-pool deposits; 9.8% of all withdrawals (777) have a near-certain 1:1 link from the amount alone

0100200300 640 1,427 0 0.2 0.4 0.6 0.8 1 deposit size (ETH) — bars above 300 are truncated, true counts labeled one in four deposits is exactly 0.1 ETH (1,073 of 4,215 real deposits — the crowd to hide in) the arbitrary tail: amounts like 0.48732951 ETH occur exactly once — a fingerprint
Excludes the 820 zero-value spam deposits of May 24 2025 and 437 deposits above 1 ETH. Round amounts hide in a crowd of identical deposits; a strictly arbitrary amount matches exactly one prior deposit 99% of the time (median 11.6 bits — near-certain).
Unique amounts — weird deposit and withdrawal amounts as fingerprints
#3 Follow the money.

Fresh wallets aren't fresh: 31% of direct ETH deposits come from fresh, single-use wallets.

Instead of funding a fresh wallet from a Privacy Pools withdrawal, 36% of fresh wallets have exactly one inbound transaction, a certain link to who is depositing. One in eight of these wallets were funded by labeled hot wallets of major exchanges, meaning the exchange knows you've deposited into Privacy Pools and can apply any of these heuristics to track your withdrawal. ~10% of the ETH deposits were withdrawals re-depositing into fresh wallets. The median gap between funding the wallet and depositing is seven minutes.

Fresh wallets aren't fresh: who funds a first-time depositor?

All 1,250 fresh single-use wallets that deposited into the ETH pool, by what their funding history shows. Every funding transfer is public.

Exactly one inbound transfer an unambiguous link to whoever paid 36.2% of fresh wallets Funded by a labeled exchange hot wallet Binance, Kraken, Coinbase... one subpoena from a name 12.9% (161 wallets) Funded by the mixer itself withdrawals cycling straight back in as fresh deposits 34% of fresh wallets median time from funding to deposit: 7.2 minutes
Full-population trace of every fresh ETH-pool depositor (nonce ≤ 1, direct deposits), Mar 2025 – Aug 2026.
Fresh wallets aren't fresh — who funds a first-time depositor
#4 The rush after approval.

8.3% (656) of withdrawals occur within 5 minutes of the root updating, and shrink the crowd to ~9 with a confidence of 0.82.

One of the trade-offs of Privacy Pools is waiting to be accepted by the ASP, with the median wait time ~1 hour. Privacy Pools v1 requires your withdrawals to be against the latest approved set. So an impatient user who deposited several days ago, the moment the list is updated and their deposit is accepted, they withdraw the funds immediately.

8.3% of all withdrawals land within five minutes of the latest approved set, and each update accepts ~9 new deposits. Of these 656 withdrawals, 78% matched a deposit from the four days before that update. This collapses an analyst's problem: instead of searching through hundreds of deposits, they only need to go through ~9. Being in a rush costs you ~7-9 bits of entropy; your anonymity set becomes ~300 times smaller. I also ran the same test against a control week, and only matched 8% of those 656 withdrawals. This gives us ~3 bits of confidence that our hypothesis (withdrawals spike after list updates because those users were just approved) is correct.

Clever users can also run this trick in reverse. If your deposit has been sitting in the pool for weeks and you see a fresh 1 ETH deposit get approved, withdraw 1 ETH immediately, in the same minute as the rush. To an observer you look like one of the newly approved deposits, but you are not in that batch, so anyone intersecting with the update's nine new names excludes you.

Withdrawals pounce the moment deposits get approved

7,944 withdrawals timed against 2,242 approval-list updates — the spike at zero is impatient users grabbing freshly-approved money

0%10%20%30%40% 8.3 1.6 0–5 min 15.4 7.8 5–30 min 13.6 9.2 30–60 min 34.2 31.1 1–6 h 17.2 24.9 6–24 h 11.4 25.5 >24 h time since the most recent approval-list update observed chance (random timing) 5× chance in the first 5 minutes 8.3% of withdrawals land right after a list update — and the median update approves only 9 deposits
Chance baseline: the share of time each band covers between list updates. A withdrawal minutes after an update is, with high probability, one of the handful of deposits that update just approved — 36 withdrawals landed within 30 seconds.
The rush after approval — withdrawals clustering in the five minutes after a root update
#5 Relayer concentration.

Withdrawing your deposit to a fresh address that is empty means you cannot pay Ethereum's gas fees without doxxing that wallet by funding it from elsewhere. Privacy Pools uses a relayer service that submits the withdrawal onchain for you, pays the gas fees, and takes a cut of your withdrawal. 73% of relayed withdrawals have come from one single relayer. This risk is entirely offchain. We are trusting the relayer to not store information like IP addresses, timing, destination addresses. We are hoping that if they do log things, they will not answer subpoenas.

One company carries three-quarters of all private withdrawals

29 relayers have ever operated; the top three carry 91.6% of relayed traffic — and 94.1% of all withdrawals are relayed

all withdrawals relayed · 94.1% direct 5.9% the relayed traffic, by operator one company · 73.0% #2 · 12.7% 25 others · 3.2% #4 · 5.3% #3 · 5.8%
Onchain this links nobody — inside the dominant relayer’s stream everyone looks the same. But one company’s servers have likely seen the majority of private withdrawals (IP addresses, timing, destinations) as routine business.
Relayer concentration — 73% of relayed withdrawals through one relayer
#6 Tired of waiting.

Timing links ~3% of withdrawals, but folded into other heuristics lets us discard fifteen of every sixteen candidate deposits.

The most standard mixer advice is to wait a long, random amount of time, so you cannot be linked through timing. Most people don't really adhere to this advice. 20% of deposits are withdrawn within 6 hours, with a peak coming at around 2 weeks, and ~10% hold for more than 3 months. In Privacy Pools v1, timing is inevitable but it is rarely linkable, with only 3% of deposits being identifiable. The power of timing comes when combining it with other heuristics that delivers ~4 bits of entropy, letting us discard fifteen of every sixteen candidate deposits.

Some rinse in hours, some wait months — few do anything between

1,144 withdrawals linked to their own deposit by address reuse; median wait 10.9 days

0100200300 309 0 20 40 60 80 100 days between deposit and withdrawal (minimum per withdrawal) median: 10.9 days 1 in 5 is back within 6 hours the patient tail: 10% wait over 90 days (104 withdrawals beyond this chart — longest 449 days)
Minimum delay per withdrawal (a reused address can deposit many times; we take the shortest plausible wait). Timing alone identifies almost nobody, but it multiplies the other signals.
Tired of waiting — distribution of time between deposit and withdrawal
#7 I know when you sleep.

Transacting at the same time leaks some information about you, but not enough to reveal who you are.

No one can be unmasked by their timezone alone, but transacting at the same time for each withdrawal leaks about 1 bit per withdrawal (0.66 on average, 1.27 for repeat users), shrinking the pool of candidate deposits an analyst needs to consider by roughly half.

The crowd never sleeps — but each person does

the hour you withdraw in is worth 0.66 bits of identity on average; 1.27 bits for repeat users

0% 2% 4% 6% 0 6 12 18 23 everyone: 7,944 withdrawals nearly flat — 2.5–5.7% per hour; dashed = uniform 4.2% hour of day (UTC) three repeat users, three private clocks user A 87 txs user B 21 txs user C 21 txs 0 12 23
Left: all withdrawals by UTC hour — near-uniform. Right: deposit + withdrawal hours of three real repeat users (anonymised). A personal clock survives 72-hour waits and every control we tried; it can nudge a guess, never make one.
I know when you sleep — circadian timing leakage per withdrawal

50.4 ETH IS A LONELY NUMBER

Mixers are meant to be simple: when you withdraw, you could be any of the deposits that came before you, and the bigger the number, the more likely you will be anonymous. In the case of Privacy Pools v1, a withdrawal can only have come from a deposit that was:

  • a) vetted and approved by the ASP
  • b) worth at least as much as the withdrawal
  • c) actually published on the approved list at that moment

These three things mean that your cover is smaller and more transparent than advertised. The actual size of the crowd is smaller than the count of deposits before you by a median factor of 1.26. This gets progressively worse for larger deposits:

  • 1 in 10 withdrawals have a crowd 8.9x smaller
  • 1 in 100 withdrawals have a crowd 42x smaller
  • the worst case has a crowd 375x smaller: a withdrawal of 50.4 ETH that, after the 3 filters, could have only six possible deposits in the pool's entire history.

Privacy is always better when you have friends.

The crowd you're told about vs the crowd you're actually in

Deposits that could possibly fund your withdrawal (approved, rich enough) vs all prior deposits, for 7,551 mainnet withdrawals

0 1,000 2,000 3,000 advertised crowd (all prior deposits) honest crowd Typical withdrawal 2,819 2,195 · 1.3× smaller 1 in 10 withdrawals 1,450 107 · 7× smaller 1 in 100 withdrawals 1,136 22 · 38× smaller The 50.4 ETH withdrawal (worst case) 1,124 3 375× smaller: three possible funders, ever
Honest crowd = earlier deposits that were ASP-approved and worth at least the withdrawal (the paper's third filter, root publication, makes little difference at the median). Typical row = withdrawals within 1.2–1.55× overstatement; rows 2–4 = the 90th, 99th percentile and the maximum. Larger withdrawals have fewer possible funders, so the gap grows with size.
Naive versus honest anonymity set — the crowd is smaller than the deposit count

PRIVACY POOLS V2 FIXES IT ALL (OR DOES IT?)

Privacy Pools v2 will be released soon™ which brings:

  • No more deposit fees
  • Private transfers in the shielded pool
  • Better UX with no more seed phrases to manage
  • Private payment requests
  • In-pool yield
  • Multi-asset pools

Based on the above, Privacy Pools v2 improves and fixes a lot of the leaks that occur in v1. A multi-asset pool means that small pools and large deposits stop being so lonely, and each withdrawal is hidden in a larger pool.

In-pool yield is also a great obfuscation method. If you deposit and withdraw the same, unique amount you have your name written all over the transaction. If your deposit is earning variable yield whilst it sits in the pool, the number that goes in doesn't have to be the number that comes out, and your fingerprint has been smudged.

Onchain privacy is important for everyone, but it has a UX problem the average user cannot comprehend. Most of the leaks in this essay were not cryptography failing; they were product and habit. People reuse addresses, hit send max, and withdraw the second their deposit clears, and no contract upgrade can stop them.

Privacy Pools v2 seems to be at the forefront of fixing that, by making the careful thing the default and actually fixing the UX problem onchain privacy has.

A last word on Tornado Cash, because it deserves one: it did nothing wrong. It was code that did exactly what it promised, for everyone, without asking any questions. It was sanctioned, and developers jailed, for what other people did with it. Roman Storm and Alexey Pertsev are still fighting for their freedom. This essay exists because privacy is a human right, and rights need measuring.

HOW TO ACTUALLY USE IT

Everything above measured, distilled into habits:

  • Deposit round amounts. 0.1, 0.5, 1 ETH. A weird amount is a name tag (#2).
  • Never withdraw where you deposited. Fresh address, every time (#1). In v2, payment requests do this for you.
  • Wait, and wait randomly. Days, not minutes. And whatever you do, don't withdraw in the five minutes after your deposit gets approved; that is exactly when everyone is watching the door (#4).
  • Fund your fresh wallet carefully. Don't hit "send max". Send a round amount with a little extra for gas, and know that if the money comes straight from an exchange, the exchange knows (#3).
  • Use a VPN or Tor when you withdraw. The relayer can't see your wallet history, but it can see your IP address (#5).
  • Don't always transact at the same hour. Your bedtime is a signal (#7).
  • Split large withdrawals. 50.4 ETH had six possible funders in the pool's history. Ten withdrawals of 5 ETH would have had thousands (#crowd).
  • Check the crowd before you use it. More deposits before yours, more places to hide.

IMPORTANT NOTES

With the exception of address reuse and funding analysis, everything else is a probability. It is overwhelmingly likely that a deposit matches a withdrawal, but I cannot say that it is 100% true. I also used aggregated data so that no one is directly doxxed; the goal of this research is to measure the system and understand how we can do better.

Evaluating Privacy Pools but not sure if it fits your product? Talk to Ben.

TALK TO BEN →

FILE UNDER — DEEP DIVES

NEXT READS

PRIVACY POOLS association-set screening, the $9M anonymity-set reality, ragequit PRIVACY POOLS — INTEGRATE the builder page: integration kit, AI brief, native SDK, the gotchas PRIVACY POOLS — RUN AN ASP run your own Association Set Provider: the job, the catch, the legal read

DEEP DIVES · RESEARCH · WORK WITH ME