|=[ RESEARCH :: FILE 04 ]=
HOW "PRIVATE" IS STARKNET'S BUILT-IN PRIVACY, REALLY?
STRK20 · STARKWARE · SHIELDED POOL · STARKNET MAINNETSTRK20 is StarkWare's shielded pool, built into Starknet itself, with compliance handled by an auditor whose viewing keys are held indefinitely. I re-indexed all 113,022 public events the pool emitted from deployment on 20.04.2026 to 18.08.2026: 14,969 deposits from 1,997 accounts, and 10,098 withdrawal legs to 1,616 recipients. The headline: 40.4% of withdrawal legs are certainly linkable to their funding deposit, and the median withdrawal leaks 10.9 of its 11.8 bits of entropy. The typical private withdrawal has effectively one candidate funder.
DATA — 20.04.2026 → 18.08.2026 · STARKNET MAINNET
EVERY PUBLIC EVENT THE POOL EMITS, RE-INDEXED FROM STARKNET MAINNET
FIRST, WHAT IS A SHIELDED POOL DOING INSIDE THE CHAIN ITSELF?
tldr: Not at all.
A privacy protocol that gives a third party viewing keys that are held indefinitely and can be used without a depositor knowledge, in the guise of compliance, is not a privacy protocol.
STRK20 promised privacy as a protocol feature, deploying a shielded pool built into Starknet by StarkWare itself. Their compliance is handled by an auditor holding viewing keys, that are held indefinitely by the auditors and can be used without depositors knowledge.
In theory, privacy pools break the transparent design of a blockchain. You deposit your tokens into a shared pool, wait, and then withdraw it to a fresh wallet. Someone could see both the deposit and withdrawal, but cannot link the wallets just by looking. In my Privacy Pools research, I covered how it was a successor to Tornado Cash, and uses an Association Set to screen illicit funds before your deposit is accepted.
STRK20 is StarkWare’s own design and take on a privacy pool, where the pool is directly built into the blockchain as opposed to a protocol on top of the chain. When depositing into the pool, your balance exists as encrypted notes, essentially sealed envelopes with amounts inside, readable only by their owner (and omniscient auditor). These notes can be split, merged, swapped, and transferred without the amounts ever appearing on the blockchain. An onlooker can see deposits and withdrawals into the pool, but not what happens within the pool.
Instead of an association set or proof of innocence, every user has a viewing key to find and read their balances, and their identity is encrypted to a single auditor key. Starknet’s take on compliance is that you receive privacy against the public, and one designated watcher gets full visibility. Sounds like a panopticon to me.
STRK20's compliance layer is one private key. Its compromise, or its lawful compulsion, retrospectively exposes every initiator and every registered user's full history since deployment. Currently, there is no onchain indication whether this private key has been used, exposed, or not. The system is private except from the one key with no rotation, no threshold, and no way to tell whether it has already been used.
WHAT DID I ACTUALLY DO?
Every action on STRK20 emits a public event, a deposit, a withdrawal, a note created, a note spent, each with a timestamp and, at the boundary, an amount. I re-indexed 113,022 events since the STRK20 launch to August 18ᵗʰ 2026, which covered 14,969 deposits from 1,997 accounts and 10,098 withdrawals to 1,616 recipients. I also looked into the funding history of the depositing accounts, and the Ethereum side of the bridge, to see where the funding originated from.
Taking all this publicly available data, I asked the question: “How often can you work out which deposit paid for which withdrawal?"
It turns out, quite a lot. 40.4% (3,969) of ALL withdrawal legs are certainly linkable to their funding deposit, and 47.7% can be narrowed to a shortlist of candidate funders worth betting on. The median withdrawal leaks 10.9 bits of its 11.8 bits of entropy. The typical private withdrawal has effectively one candidate funder.
Of the certainly linkable deposits and withdrawals, 90.6% are the same asset end to end - USDC↔USDC 1,777 legs, STRK↔STRK 1,497, strkBTC 256. Another 111 legs are internal reshields, where withdrawals are deposited straight back into the pool, with no change. Genuine cross-asset links are just 372 legs (9.1%), mostly STRK↔USDC, where the funding token and withdrawn token are different.

SEVEN LEAKS
I tested seven ways an observer might connect a withdrawal back to its deposit, ranked by the deanonymisation they do. 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
I measure some leaks in bits: each bit halves the population you could be hiding in.
#1 · Sending the money home8,377 of 10,098 withdrawal legs (83.0%) pay an address that has itself already deposited into the pool.
In my Privacy Pools article, I covered that address reused was user error, with one withdrawal in seven reusing the same address they deposited from. On STRK20, it’s built into the product. Five in six users are depositing and withdrawing to the same address, with the SDK itself autofilling the recipient with the connected, note-owning account if you don't specify one. I tested this on xverse, and when you withdraw you do not get the option to choose a different address. The recipient's identity is public before any heuristic runs.

The median gap between an accounts most recent deposit and withdrawal back out is 176 seconds. 555 legs that were funded by that same address’s own prior deposit with the same amount had a median round trip of 91 seconds, and one third completed in under a minute. The STRK20 privacy pool is currently more of a turnstile.
When five in six users are doing the wrong thing, the product design is flawed.

withdrawal legs each have exactly one possible funder in the pool's entire history.
STRK20 pool allows users to deposit arbitrary amounts, deposit 341.7172 STRK, later withdraw exactly that, and the odds two unrelated people chose the same number are effectively zero. Even a repeated amount gives no cover. 194 of these fingerprints appear at least twice in the pool's history, but the extra, unique deposits come after the withdrawal of the first one.
To have any sort of anonymity, depositors need to use round numbers and long waits in between deposits and withdrawals to combat this.

13,784 of 28,280 notes ever created (48.7%) have their exact amount certified by the protocol's own ledger rule.
A quite interesting finding, every transaction in the pool must balance; deposits plus notes spent on one side, and withdrawals plus notes created on the other side. The contract doesn’t want users to mint money out of thin air and enforces this rule. Unfortunately, deposit and withdrawal amounts are public, so whenever a transaction has exactly one hidden amount, you can solve for it using the equation. If a user deposits 500 STRK and withdraws 200 STRK, and creates one encrypted note, we know that there is 300 STRK on that note. This is how the pool balances its books.
There are 2,679 certain links between notes that deposit and spend the same amounts, with 98.1% being the same accounts churning through its own notes with a median lifetime of 98 seconds.
You can use this basic equation to identify users who deposit (d), withdraw (w) and later redeposit exactly d-w-fee. This identifies 3,365 triples across 295 accounts, and zero false matches in 9,302 shuffled controls.
In this case, the cryptography and math are working perfectly; a notes creation and spend are unlinkable. But the design allows an onlooker to pin the hidden amounts whenever a transaction has exactly one spend, and those pinned values deanonymise users.

353 withdrawal legs have exactly one candidate funder because the user hit "send max".
Hit "withdraw max" and the note you spend is worth your withdrawal plus the fee: V = W + f. W alone matches nothing in the deposit history, so you feel invisible, but V is computable from public data, and it matches your original deposit exactly. One depositor was matched to their withdrawals 47 times thanks to this basic maths.

2,402 deposits (16.1%) were preceded, within 24 hours, by an inbound transfer of precisely the deposit amount.
Depositing from a brand new wallet seems like a good idea from the outside, but the new wallet is empty so it first need to be funded. 16.1% of all deposits were funded by a transfer of the exact deposit amount, announcing a trail to follow for where the funds come from and where they are going.
There were 101 addresses that took funds fully out of the pool, and 72% were fresh wallets, first funded by the pool payout. Depsite the lack of instructions on how to preserve privacy, there are some users correctly using the pool.

Among certainly-linked pairs, sub-minute withdrawals are enriched 25 to 55× over chance.
Privacy Pools had an "approval rush", where withdrawals bunched in the minutes after the vetting list updated. STRK20 has no list, and the impatience survives anyway. Among certainly-linked pairs, deposit-to-withdrawal gaps split into a fast swarm with a half-life of 80 seconds and a slow tail measured in days. Timing alone is rarely enough to link addresses, but stacked with the amount filter you can narrow the pool quite quickly.
The median certainly-linked withdrawal was 153 seconds during Shield Rush, an incentive campaign where quest hunters churned through the pool for STRK rewards. Outside of this, the median is 1.6 days and 5 days at the end of the organic population. There are some patient users, but they are far from the median.

28,371 of 28,843 pool transactions (98.4%) route through a single operator's relay.
Much like other privacy tools, a paymaster submits your withdrawal for you and collects a fee in exchange for the service. For onchain privacy, this is great because a user doesn’t need to link another address just to pay for gas fees. The public sees 157 sender wallets instead of 2,000 users, and clustering on senders merges nearly everyone into one useless blob (I tried: one giant non-cluster of 1,954 of 1,997 depositors).

The biggest risk here is offchain. Every one of those transactions passed through ones company’s server with the user’s IP address, timing, and address as part of the service. We are trusting the relayer to not store this information, and if they do log things, that they will not answer subpoenas.
The relay (and auditor) isn't the only watcher. Since a July 9 upgrade, every deposit must carry a screening attestation from Elliptic, a commercial AML provider, fetched seconds before the transaction lands. The screener sees every depositor's address, token, amount, and timestamp. There is no transparency of what they store, what they do with the information, and what they screen against.
STRK20 POPULATION OF ZERO
The naive measure of a pool's privacy is simple: when you withdraw, you could be any of the deposits that came before you. On STRK20 the naive median is 3,578 candidate deposits per withdrawal.
This number is naive, and does not show the entire picture. A withdrawal can only have come from a deposit that was:
- in the same token (a USDC deposit didn't fund your STRK withdrawal, the pool's private swaps don't change this, since a swap shows up as its own same-token withdraw-and-redeposit pair)
- before your withdrawal
- worth exactly the right amount (W, or W + fee for the withdraw-max crowd)
- and not already certainly spent
Using these filters, the median withdrawal leg, in every token, has an honest crowd of zero. No plausible funding deposits in the pool's entire history. Across all legs, 76.9% have no amount-feasible unspent deposit at all, and 86.2% have a crowd of three or fewer (8,705 of 10,098). Even the best case reaches a mean of 34.6 candidates, median still zero. A WBTC withdrawal has a crowd of at most three in 100% of cases.

To be fair, those zeroes are partly protocol mechanics, nearly half of all legs are funded by change notes and merges rather than a single visible deposit, so their residual privacy lives in the internal note graph, which is opaque. For nine out of ten legs, the crowd at the withdrawal boundary is a group of three at most. Whatever cover remains comes from the encrypted interior, and certainly not from the marketing's user counts.
The true anonymity ceiling is the number of live, unspent notes, which is 4,970 live notes at the time of writing. That is the entire pool set across tokens, amounts, and users. The pool ran its first two months at a plateau of 1,370 notes, peaked at 5,034 on July 1 during the burst, and has drained since. Only 16.9% of all notes ever created are still unspent.

THERE REALLY ISN’T ANY COVER TRAFFIC FROM DEPOSITS EITHER
64.5% of all hours in the pool’s lifetime contain zero user deposit. The longest drought ran for 124.5 hours, five full days, from April 29ᵗʰ to May 4ᵗʰ. A few weeks ago between the 7ᵗʰ and 8ᵗʰ August there was a 22.4 hour drought between those deposits. Withdrawals in those windows are provably spending old notes, and their anonymity set is bounded by whatever residue survived the drought.
You can shrink the pool even further, by collapsing accounts under common control. In the data set there are: 14,969 deposit events, 1,997 unique depositor addresses, 1,474 effective entities once collapsed. Of those depositors, 31% (620) belong to a single tagged farm cohort.

HOW NOT TO USE A PRIVACY POOL
Over it’s short life, the STRK20 pool has produced a guidebook for how not to use a privacy pool, which can be distilled into good habits, we can all use:
- Never unshield where you shielded
- Wait randomly before withdrawing
- Deposit round, common amounts
- Don't hit "withdraw max"
- Fund your fresh wallet through a privacy pool
- Do not send the exact deposit amount to your new wallet
- Don't re-shield a payout two minutes later
- Check the population before depositing your token

AN INCENTIVE FARM OR ACTUAL PRIVACY?
85.3% of all deposit volume, and 44.1% of all deposits arrived in the ten-day incentive burst, who behaved like airdrop traffic. Complete three quests and then leave never to come back, of the organic accounts who first deposited during the incentive campaign, only 5.3% returned. The pool seems to be a transit medium as opposed to a pool, the current STRK sitting in the pool is just 7.3% of all the STRK ever deposited, the rest has left.
These incentive farmers are different to the 620 cohort from earlier, who had a much smaller economic footprint, accounting for 15.9% of deposits, 4.6% of STRK, and 8.4% of USDC volume. One is person with multiple sybil accounts, the other is a failed marketing campaign.
It is important to note that some users are using the pool as designed. 93 accounts have been active in three or more distinct weeks, and 125 non-farm accounts have certainly attributed holds of seven days or longer. 51.3% of the withdrawals go to fresh, never before seen accounts, and 10.3% of total pool traffic are internal only private transfers.
Right now, STRK20 has real usage, but is small.

THE PRIVACY TAX
Every transaction pays a flat protocol fee, 4 STRK for most of the pools life, which was raised without announcement 50% to 6 STRK on 5ᵗʰ August. The fee exceeds 1% of the deposit size for 30.5% of deposits, 5% for 23%, 10% for 19%, and for 1.7% of deposits the fee exceeds the deposit outright. Whales pay basis points (median burden 0.28%) while the long tail pays double digits.
The median strkBTC deposit is $4.18 and pays a median fee burden of 4.1%; one in three strkBTC deposits lose more than 10% to the fee. Its dust-sized sibling xstrkBTC pays a 21.4% median.
Doing it properly costs money and time. A minimal private round trip is two transactions (shield, unshield); actual private use (shield, transfer privately, unshield) is three. At current fees plus gas, at market prices, that is about $0.65: roughly 1.6% of principal for the median user (deposit $41), and 16% for the user at the 25th percentile ($4.09).

I CAN FIX YOU (STRK20)
STRK20 cryptography works as intended, but the surrounding UX leaks everything. A default wallet flow that sends money back home, fingerprint amounts, impatience, a conservation invariant that does the observer's arithmetic, and a compliance layer that concentrates god-view into one un-rotated key while a single company carries 98.4% of the traffic.
There is some demand for privacy, underneath the farmers and failed marketing campaign, there are accounts that hold for weeks, pay fresh addresses, and move encrypted notes in ways the public record cannot read. The fixes that would protect them are neither mysterious nor expensive. STRK20’s problem isn’t cryptographic, it’s product UX and can be fixed:
- Fix the default flow. When 83% of withdrawals go back to a depositing address, the problem is the UX, so fix the UX. Wallets should default to a fresh address and warn before sending money home.
- Educate users about holding funds in the pool for longer, and depositing common sizes, and how doing so can increase their privacy. For example, incentivise users to hold their deposits in the pool for X time or for depositing common values.
- Rotate and threshold the auditor key. One static key holding four months of everyone's history is a single point of retrospective failure. The protocol's own paper specifies quorum decryption; deploy it, rotate on a schedule, and publish the rotation log onchain.
- Publish the screening policy. Since July 9 a commercial AML provider pre-clears every deposit, and rejected deposits vanish without a trace: reverted transactions emit no events, so the number screened out is structurally invisible.
Hit me up if you want to know how your privacy protocol can be improved.
As always, thanks to the best proofreader, @FryCookVC.
Want to know how your privacy protocol can be improved? Talk to Ben.
TALK TO BEN →