Tornado Privacy Observation Report: Can It Really Achieve 100% Undetectability?
Source: Chuangyu Blockchain Security Laboratory
Introduction
Tornado.Cash, as the most popular decentralized privacy solution on the Ethereum network, breaks the on-chain link between depositors and withdrawers, achieving transaction confidentiality and protecting user privacy.
An increasing number of users with privacy (money laundering) needs are starting to use Tornado.Cash. So how truly private is Tornado.Cash, and can it achieve 100% security?
Chuangyu Blockchain Security Laboratory will conduct a multi-dimensional analysis of Tornado.Cash to explore its true privacy reliability.
How Tornado.Cash Works
Before analyzing Tornado.Cash, we must understand how it works.
Tornado.Cash uses smart contracts (anonymous pools) to receive token deposits from one address and allows withdrawals from different addresses. It blocks the connection between the deposit address and the withdrawal address through zero-knowledge proofs, thereby protecting privacy.
The size of the anonymous pool directly determines the reliability of Tornado.Cash's privacy. Consider if only one deposit enters the anonymous pool; no matter which address withdraws, it is certainly the same person as the deposit address.
Interested readers can refer to the official documentation: how-does-tornado.cash-work.
Preparation
Tornado.Cash currently supports ETH and ERC20 tokens (DAI, cDAI, USDC, USDT, WBTC) for deposit and withdrawal transactions. We selected ETH, which has the highest trading volume, for privacy analysis. We extracted all transaction records of Tornado.Cash contracts before November 4, 2021, as shown in the table below:
It can be seen that after enabling proxy contracts, a large number of transactions are conducted through proxies. From the anonymous pool transaction volume distribution chart (see table below), we can see that the 1 ETH anonymous pool (33%) and the 10 ETH anonymous pool (30%) are the most used anonymous pools.
Transaction Analysis
Transaction Classification
After classifying all transactions into deposits and withdrawals, we counted the total amount (in ETH), number of times, maximum deposit/withdrawal amount, and minimum deposit/withdrawal amount for each address. We obtained 22,714 deposit addresses and 31,737 withdrawal addresses, with the top 10 total deposit/withdrawal amounts as follows:
Top 10 Total Deposits
Top 10 Total Withdrawals
It can be seen that deposit addresses and withdrawal addresses do not correspond one-to-one, and the relationship between deposit and withdrawal addresses cannot be determined.
Mining Address Filtering
Tornado.Cash has introduced anonymous mining incentives (see: anonymity-mining) to increase the number of transactions within the anonymous pool and improve the overall privacy reliability of Tornado.Cash.
Therefore, our first step is to filter out mining transactions within the anonymous pool, which can significantly reduce the number of transactions in the anonymous pool.
Through analysis, we found that mining addresses have the following characteristics:
Mining addresses will withdraw TRON tokens from the Tornado.Cash mining pool contract address 0x746aebc06d2ae31b71ac51429a19d54e797878e9;
Mining addresses do not have privacy protection needs and generally use their own wallet addresses to pay miner fees during withdrawals;
Mining addresses are usually old addresses that are commonly used and have many transactions.
Using this method, we identified 1,051 mining pool addresses that meet the criteria. After excluding mining addresses, the number of deposit and withdrawal addresses changed as follows:
Top 10 Total Deposits After Excluding Mining Addresses
Top 10 Total Withdrawals After Excluding Mining Addresses
Same Address Filtering
Transactions where the deposit address and withdrawal address are the same have no transaction privacy and can also be filtered out (this part is likely to be mining or novice users). After filtering, the data changed as follows:
Top 10 Total Deposits
Top 10 Total Withdrawals
Filtering Relay Addresses
To maximize the privacy and security of withdrawal addresses, most users choose to use relayers to pay miner fees when withdrawing, so a single withdrawal operation will involve two transactions.
One small amount is paid as a fee to the relayer, and the other is the actual withdrawal transaction, as shown in the figure below.
We use the filtering condition: max > 0.8 | (max <= 0.1 & max >= 0.08) to filter relayer transactions. After filtering, the data changed as follows:
Top 10 Withdrawal Counts After Filtering Relay Addresses:
Same User Associated Address Relationships
Next, we analyze whether there are associated relationships among addresses in the Tornado transaction pool. Before the analysis, we first exclude mining addresses and relayer addresses.
The analysis method uses direct trading counterpart analysis. Suppose A is the deposit address and B is the withdrawal address. A and B have no direct relationship, but if address C is a direct trading counterpart of A and C is also a direct trading counterpart of B, then we can determine that A and B are related. The data of direct trading counterparts is obtained directly from the blockchain explorer.
The relationships can be categorized by address type into three types: deposit address to deposit address, withdrawal address to withdrawal address, and deposit address to withdrawal address. These three types of relationships apply to different scenarios.
- Relationship between deposit addresses
Since Tornado only allows deposits of 0.1ETH, 1ETH, 10ETH, and 100ETH, during actual transfers, there may be situations of fund allocation, miner fee allocation, or accumulation of remaining ETH after deposits.
- Relationship between withdrawal addresses
When withdrawals are needed, there may also be accumulation among withdrawal addresses, such as accumulation to exchanges.
- Relationship between deposit addresses and withdrawal addresses
Whether there is still a relationship between deposit addresses and withdrawal addresses is crucial. If a hacker is very familiar with privacy transactions, they may try every possible way to cut off the connection between key addresses. However, in actual operations, since humans are involved, there will inevitably be oversights or omissions, which may leave traces.
Based on the above three scenarios and association types, we first analyze the 100ETH transaction pool. The corresponding association graph is generated based on direct trading counterpart data (the letter 'd' after the address indicates a deposit address, and 'w' indicates a withdrawal address).
First Scenario
There is an association between deposit addresses. Taking 0x0022d8bda338fd7e5c7248f32090252fd6dc11ef as an example:
This address has overlapping trading counterparts with multiple deposit addresses. Analyzing the relationships of these addresses on-chain, it can be determined that after depositing 100ETH and 10ETH into Tornado, the remaining ETH was consolidated into the address 0x6bafcd65f9ad3a99509d8d7d987acfa393db7c39, which then deposited the remaining 0.1ETH into the Tornado transaction pool.
Second Scenario
There is an association between withdrawal addresses. Taking 0x9c67d8383f1eeb6e2ff2b0d296aa6a51ea2858a1 as an example:
This address has established associations with multiple withdrawal addresses, all of which initiated withdrawal actions from the Tornado 100ETH transaction pool, with each address withdrawing 1000ETH.
After the withdrawals, all funds were consolidated into the address 0x120cffb605c8127442c2f8515eb25749cce52947.
Continuing to analyze the subsequent paths, it can be seen that 0x120cffb605c8127442c2f8515eb25749cce52947 has transferred ETH multiple times, eventually reaching addresses like 0x32e9dc9968fab4c4528165cd37b613dd5d229650, and ultimately swapped ETH for other tokens transferred to exchanges like Binance.
In the above two scenarios, privacy transactions only generated associations after the deposit or withdrawal ends. Although some information can be traced back, the connection between deposits and withdrawals remains severed. Now we explore the third scenario.
As the saying goes, no one is perfect; even the most meticulous plans may leave clues. If Tornado users do not completely isolate addresses during use, it is possible to associate them through trading counterpart relationships. Taking 0x167ae15b74cd20482e80f7e425b4ae6d2cc631c4 as an example:
In the above association, all five addresses are associated through the direct trading counterpart 0x4278314c1a50da6014e580cbff34fc383b335049, which can establish the inflow and outflow relationship of these five addresses to a certain extent. If further digging into amounts and subsequent fund flow relationships is conducted, it may be possible to trace back further.
In the entire experiment, the 100ETH pool had 4,132 deposit addresses and 703 withdrawal addresses. After filtering, there were 2,859 associated addresses with overlapping direct trading counterparts, accounting for about 59% of all addresses, indicating that most users did not achieve 100% privacy when using the Tornado privacy protocol due to operational oversights.
Mining out associated addresses also means that tracing Tornado becomes a possibility (this article only sampled direct trading counterparts; if deeper trading counterparts are considered, the accuracy will be higher). After obtaining a large number of associated addresses, real information can be further mined based on exchange address KYC or ENS Twitter channels.
Based on Case Verification Results
We mined historical security incidents from the blockchain explorer's hacker incident database and filtered out addresses related to Tornado used in these incidents for analysis based on the above theory.
Analysis of the KuCoin Theft Incident
Direct trading counterpart associated address analysis
The hacker deposited ETH into the Tornado 100ETH transaction pool through eight addresses. These eight deposit addresses were associated through direct trading counterparts 0x23156749a0acefc8f07b9954d181d50084c1519e and 0x82e6b31b0fe94925b9cd1473d05894c86f277398.
From the above association graph, it can be seen that due to the hacker's oversight, the deposit address 0x34a17418cec67b82d08cf77a987941f99dc87c6 was associated with the withdrawal address 0xc609b3940be560c8c00e593bea47fb6ecef6b2c6 through the direct trading counterpart address 0x82e6b31b0fe94925b9cd1473d05894c86f277398.
0xc609b3940be560c8c00e593bea47fb6ecef6b2c6 only withdrew 2,900ETH (a small portion of the total ETH deposited by the eight deposit addresses).
It can be seen that the hacker, due to insufficient miner fees in 0x82e6b31b0fe94925b9cd1473d05894c86f277398, transferred miner fees from 0xc609b3940be560c8c00e593bea47fb6ecef6b2c6 and 0x23156749a0acefc8f07b9954d181d50084c1519e to 0xc609b3940be560c8c00e593bea47fb6ecef6b2c6.
As a result, the withdrawal address and deposit address were associated.
Continuing to trace the chain, it can be found that the withdrawn ETH was transferred to other addresses. Further deepening the entire chain, it can be found that ETH was dispersed to many addresses, with a large amount of ETH transferred to Binance's deposit address 0x28c6c06298d514db089934071355e5743bf21d60.
At this point, the entire chain tracing is cut off at Binance. If KYC information from Binance can be obtained, personnel can be specifically located.
Liquid Exchange Theft
Four deposit addresses were found to have deposited into the 100ETH pool and were associated through direct trading counterpart 0x5578840aae68682a9779623fa9e8714802b59946.
FinNexus DeFi Project Theft
Two deposit addresses were found to be associated, 0x5271b379f3e1954e20791142d734596a3de28efd and 0x5ebc7d1ff1687a75f76c3edfabcde89d1c09cd5f, both of which deposited ETH into the 100ETH pool and were associated through direct counterpart 0xfe381bc045b85e0acd93e85ecfe65ecb0fec2a44.