# Tornado 龙卷风混币原理

By [Ethan - if(DAO)](https://paragraph.com/@ethan-if-dao) · 2022-01-18

---

项目背景
----

Tornado（[https://tornado.cash/](https://tornado.cash/)）是以太坊隐私赛道著名的`混币`项目，其混币技术主要使用了 `zk-SNARK 零知识证明`。

1、关于 zk-SNARK 零知识证明的原理可以参见 if(DAO) 之前的文章：

[https://mirror.xyz/0xd05cFA28Eaf8B4eaFD8Cd86d33c6CeD1a1875417/X3qSOjObTknXQ\_iGhDBFYETibD0TVW0twz5QDIthjGI](https://mirror.xyz/0xd05cFA28Eaf8B4eaFD8Cd86d33c6CeD1a1875417/X3qSOjObTknXQ_iGhDBFYETibD0TVW0twz5QDIthjGI)

2、混币的意思是混币者通过 Tornado 合约将**混币者的以太坊地址**和**资金去向地址**失去关联，从而达到隐匿资金去向的目的。

项目原理
----

1、Bob 是第 3 个将自己的代币 Deposit 存入龙卷风合约进行混币的客户。

2、Alice 是第 4 个将自己的代币 Deposit 存入龙卷风合约进行混币的客户。

3、Alice 在 Deposit 时

![](https://storage.googleapis.com/papyrus_images/0c621c5ecd2f0ad1ae5cd632b90c668051044caa66ffb6e786deb00cd8102a84.png)

（1）Alice random k4 ，r4。k4 和 r4 in { 0 ，1 } ^ 256。( k4 ，r4 ) 也是 Alice 未来的取款凭证 note4。

（2）Alice 计算得到 C4 = Hash1( k4 ，r4 )。

（3）Alice 将 Deposit 的金额 100 DAI + C4 + MerkleProof(C4) 发送至 Tornado 合约。

（4）Tornado 合约 verify MerkleProof(C4) ：通过梅克尔证明验证 C4 账户状态的正确性。

（5）通过 C4 + MerkleProof(C4) update Tornado 合约内存储的与 Tornado 业务相关的全局状态 MerkleRoot。

（6）nf 在下面的 Withdraw 操作时才会用到，暂时不表。

4、Bob 在 Withdraw 时

![](https://storage.googleapis.com/papyrus_images/1683a18defdda73cf28cdc5c3bf123e23a6d13d14b762ba6858d2c448d5d904e.png)

（1）Bob random k3 ，r3。k3 和 r3 in { 0 ，1 } ^ 256。

（2）Bob 计算得到 C3 = Hash1( k3 ，r3 )。

（3）Bob 计算得到 nf3 = Hash2( k3 )。

（4）Bob 指定 Bob 混币后的收款地址 A。注意：Bob 必须在 statement 中指定收款地址 A，这样可以防止 Miner 矿工将 Bob 的收款地址更换成自己的地址从而盗取混币后的资金。

（5）Bob 构建 zk-SNARK Proof，即在不泄露自己账户信息的情况下证明自己曾经存入合约 100 DAI。具体做法是通过 ：

public statement **x** = ( MerkleRoot ，nf3 ，A )

secret witness **w** = ( k3 ，r3 ，C3 ，MerkleProof(C3) )

从而构建 zk-SNARK Proof **π**。这个过程和我们之前学习的零知识证明匹诺曹协议是吻合的：

1）TrustSetup ：S ( C ) => ( Sp ，Sv)。（本篇省略了：通过电路 C 构建可信设置并分别生成 Sp 和 Sv，其中 Sp 给 Prover 生成零知识证明 π，Sv 给 Verifier 验证零知识证明 π 的正确性）。

2）P ( Sp ，x ，w ) => Proof π。（Prover 证明者构建零知识证明 π）。

3）V ( Sv ，x ，π ) 是否正确。（Verifier 验证者验证零知识证明 π）。

（6）Tornado 合约将 Bob 提交的 nf3 增加至 nullifier 中存储，用以保证 Bob 的这笔 100 DAI 的混币存款不能被再次 Withdraw。即当 Bob 想再次 Withdraw 此笔存款时，Tornado 合约会检查此笔存款对应的 nf3 是否存在记录，如果存在则拒绝提款。

（7）Tornado 合约返回给 Bob 指定的资金去向地址 A ，金额 100 DAI（因为示例中使用的是 Tornado 100 DAI Pool），完成最终的混币。

`一般的资金转移过程中，Bob 必须向区块链网络提交 From 转出账户 + To 转入账户 + Amount 转账金额。而通过 Tornado 合约，Bob 在取款过程中，只向区块链网络提交了 3 项数据：为了防止 Bob 或攻击者重复 Withdraw 的一个由随机数生成的哈希值 nf + 没有透露任何与 Bob 秘密相关的零知识证明 π + 以太坊公开地址 A 但没人知道这是 Bob 的地址。Bob 最终达到了隐匿取款人和资金去向的目的。`

项目不足
----

上面的分析过程中，我们忽略了一件重要的事：以太坊等主流区块链的协议中一般都是谁发起交易谁承担 gas。在上面的流程中，Bob 在 Withdraw 取款过程中花费了无法隐匿的 gas，数据分析人员可以**关联 Bob 的地址和最终货币的去向地址 A**，从而暴露了 Bob 的身份。

Tornado 的解决方案是让 Bob 、Alice 等使用 Tornado 合约的客户不直接向 Tornado 合约发起 Withdraw 交易，而是让 Relay 这样一个中心化服务器中继 Withdraw 交易，花费 gas：

![](https://storage.googleapis.com/papyrus_images/43339367003956e564ae1f395b1024e6c4a4b3544e2d08439eb32e59bb51e4b1.png)

1、这样做的好处是：所有向 Tornado 合约发起提款交易的地址都是 Relay Address 并由该地址承担 gas，隐匿了 Bob 、Alice 的地址信息。

2、这样做的缺点是：Relay 服务器是中心化的，这也是龙卷风经常被人诟病的一个痛点。

DYOR
----

\================================

\================================

欢迎大佬们的探讨指正～

您可以在这里找到作者 twitter：@ethan\_ifdao

---

*Originally published on [Ethan - if(DAO)](https://paragraph.com/@ethan-if-dao/tornado)*
