# Tornado.cash 新旧版机制对比

By [mazemax](https://paragraph.com/@mazemax) · 2022-07-07

---

**介绍** Tornado.cash是一个混币协议，其核心是利用零知识证明zk snark技术，来解决以太坊上用户多个地之间转移代币的隐私保护问题。旧版本在2019年投入使用，新版本在2021年底开始beta版使用。旧版本从最早支持以太坊主链（同时支持ETH和多种ERC20代币），到目前已经支持了多种主流链（包括Polygon、BSC等）。旧版本已经完全实现了去中心化，没有后端服务器，链上合约开源且无私钥或多签控制协议，前端代码开源且完全托管在IPFS媒介中。迄今为止，没有被纰漏过重大bug，且广受黑客青睐。新版本在旧版本验证机制的基础上，引入了两个新功能，包括任意代币数量的充提和隐蔽转移（Shield Transfer）。同时使用了Omnibridge跨链桥，并把主体功能部署在了Gnosis Chain上。目前新版本由社区投票掌握，多签可以控制协议相关功能，并没有做到完全去中心化。

**旧版**

*   **结构：**
    

![](https://storage.googleapis.com/papyrus_images/0a6f3107e3687d69fa3f2c378d54b9e15b98c8dfc14ab89d576e23d07d24f8ff.jpg)

*   **角色：**
    
    *   用户：一般有多个地址，部分地址用来向Tornado中存币。另一部分地址用来接受混币后的代币。为了保护隐私，这两种地址应该不存在任何关联。例如，A和B两地址之间存在过链上转账记录，或者和同一个交易所地址有过充提记录，很容易被关联起来，进而破坏了混币的效果。
        
    *   Pools：当前以太坊链存在4个存储ETH池合约，分别用来接收和提币0.1、1、10、100 ETH的单笔交易。旧版不支持用户充值任意数量的ETH（为了增强隐私性，使得充提币记录看起来都是一样的）。
        
    *   Router：路由合约。由于有多个Pool合约，为了方便起见，用户统一从一个合约地址作为入口，这个入口就是Router，用来中转用户的请求到合适的Pool合约。
        
    *   Relayer：中继人。也是为了加强隐私而设立的。因为提币的时候，也需要一个地址来发起交易，而这个交易需要一点ETH作为gas手续费。那么不可避免的需要有人通过一些路径把这笔gas充值到这个提币地址中（例如对于同一个用户来讲，一般从同一个交易所账户提币到不同链上账户，这样链上账户间就有可能被关联，从而导致隐私性受损）。为了解决这个问题，Tornado协议使用了Relayer，让Relayer机器人代替用户发送这笔提币交易到用户指定的收款地址中，同时会奖励给Relayer一定的ETH奖励（一般为提币总金额的0.4%左右）。这样能很好的保护用户隐私。Relayer机器人是中立的，一般通过质押一定的Torn代币才能成为Relayer。
        
*   **存款：**
    
    *   充提币的全过程只涉及到合约和前端代码两部分，Tornado并没有自己的服务器来储存任何数据。所有的计算也发生在前端代码和合约中，例如计算零知识证明circuit的计算写在前端代码里，计算和存储Merkel Tree和验证Proof的有效性写在了链上合约中。前端代码和素材也被托管在了IPFS去中心化媒介中，Tornado项目方并没有前端代码托管服务器。所以整个项目（尤其是老版）的去中心化程度是很高的。
        

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

*   存款调用合约中的deposit方法，用户发交易时需要选定ETH Pool并充值固定数量的ETH，（通过Router合约作为发起并中转到Pool合约）。存款的同时会链下生成一个Note和与之关联的commitment哈希。\*\*Note相当于用户的存款凭证（也可以理解成私钥），用于在提款时提供这个Note来链下生成零知识证明的Proof，然后使用这个Proof通过链上的验证，证明这个Note是有效的。\*\*commitment哈希用来确认链上的存款状态，**具体是把这个哈希当作一个新的叶子节点插入到链上合约储存的Merkel Tree中（\_insert方法就是用来干这个的）**，所以更新这个Merkel Tree的root节点的同时也完成了ETH的deposit，这样就能确认这笔充值在链上是生效的了。
    
    *   Note很关键，必须放在安全的地方秘密存储。如果丢失或者被窃，原用户就永远无法取出这笔存款。
        
*   **提款：**
    
    *   只要拥有了未提款过的Note，任何人都能提款ETH到指定的地址。
        

![](https://storage.googleapis.com/papyrus_images/3b0a7b2651ffb3e5df2aee695f17b4e379d29493a33e5f10c21e24ac852de329.png)

*   提款用户发起提款申请，这个时候可以选择使用Relayer帮忙发起交易，或者不使用Relayer，自己花Gas完成操作。为了保护隐私，这里建议还是尽量使用Relayer，同时recipient地址也就是接收地址用未曾发过交易的地址。
    
    *   提款用户持有Note，这个Note与nullifierHash相关联，且结合root、recipient、relayer、fee、refund等数据，能通过zk snark circuit算法链下构造出一个Proof。如果此时选定了Relayer机器人，就将构造好的上述数据连同Proof发给Relayer，然后由他完成这笔交易。
        

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

![](https://storage.googleapis.com/papyrus_images/22fa9b2220f711e152f4f35e767f9816487e6effa3abae0834e87d6258da6910.png)

*   recipient接收人地址、relayer地址，由提款用户自行指定。一旦通过Note计算好Proof后，就可以发起提款申请。此时Relayer地址会代替用户完成提款操作，Pool中的对应金额的ETH会发送给：a. 用户指定的recipient地址 b. 部分ETH会以小费的形式奖励给Relayer地址。
    
    *   需要注意的是，提款时，Tornado前端页面会提示Time passed和Subsequent deposits。也就是这个Note的存款至今的时间，和在这段时间内已经存过的其他deposits数量。而时间越长、deposits数量越多，越能打破充币和提币地址间的相关联性，越能更好的保护隐私。所以充提币的时间间隔，应尽量拉长。
        
    
    **新版**
    
*   **结构：蓝色为充币过程，红色为提款过程，黑色为隐蔽转账（shielded transfer）过程**
    

![](https://storage.googleapis.com/papyrus_images/5a395c6685391b7059131500d408ef8df760043e92a2f56ae67aa1b5efd97bb8.jpg)

*   **角色：**
    
    *   Shielded Address：这是Nova版本的新增功能。任何用户在首次使用新版本时会自动创建一个新的地址，也就是这个Shielded Address，和这个地址对应的私钥。这个私钥充当着老版本中的Note功能。Shielded Address伴随第一笔deposit交易，会调用Tornado.cash Nova WETH Pool合约中的register方法来把这个地址注册在这个合约中，并且把owner赋予为L1链的存款者地址，也就是user地址。所以在之后，只有这个user地址或者任何持有这个Shielded Address私钥的地址，才有权限转移和提款代币。简而言之，就是创建了一个新的隐私地址的私钥（需要妥善保存），并且把这个隐私地址与user地址绑定在一起，代替了老版本中的Note。这样无论使用多少次充提币的功能，只要一个隐私地址私钥就足够了，相对于之前N多个Note来说，方便了不少。且由于使用了zk snark进行零知识证明与相同的验证机制（Verify2合约与Verify16合约），Gnosis Chain端安全性上也有同样的保障。
        
    *   Tornado.cash Nova WETH Pool：这是部署在Gnosis Chain（xDai）链的WETH代币池地址。与老版本中的各个Pool合约功能一样，主要功能就是充币和提币。这里面不同点在于，老版本中每个充值或提币的金额是固定数量的ETH，而新版本里面，没有对这个数量进行限制，用户可以自行定义想要充值和提币的数量（目前单笔最小0.05ETH，最大不超过10ETH，也可以通过社区投票自治，多签执行来改变这个最大限额），所以新版本也没有多个Pool合约，所有都与这一个池子进行交互。
        
    *   L1 Helper：用户充币时，直接与这个L1 Helper合约交互。可以将用户的ETH转化成WETH并发送跨链桥合约。
        
    *   L1 Unwrapper：用户提币时，由Relayer机器人发起，跨链桥合约调用提币方法。之后将WETH转化成ETH，并发送给接收地址，同时发送小费给Relayer。
        
    *   L1 Omnibridge：部署在以太坊的跨链桥合约。主要用于从L1 Helper中接收用户存款的ETH并发送链上事件（用于通知Gnosis Chain跨链桥生成相应资产）。也负责把WETH发送给L1 Unwrapper以完成提币。
        
    *   Gnosis Chain Omnibridge：部署在Gnosis链的跨链桥合约。主要用于接收L1跨链桥信息并mint新增WETH给到Nova Pool合约，也负责在用户发起提款时，销毁从Nova Pool中发过来的WETH，并发出链上事件通知L1 Omnibridge来完成提款操作。
        
*   **存款：**
    
    *   初次使用会自动生成一个Shielded Address和这个地址的私钥。私钥在功能上相当于旧版本中的Note。
        
    *   如图中蓝色箭头的指示方向，在新版本中，在L1上充币，本质上是把ETH存在了跨链桥合约中，然后在Gnosis链上新mint一个WETH凭证，并没有把ETH存在L1的某个混币池子中。
        

![](https://storage.googleapis.com/papyrus_images/30b3dc7aa73a98dd2092191a4c696c3651e8a2b815a815d4aa8e8ff1a8fc8a9f.png)

\*

![](https://storage.googleapis.com/papyrus_images/2d671d8d1f3f5f56b363b83be39b5ccbbd31cd66eeaeb8c7b299fef1f0fa2831.png)

*   其流程是用户直接与L1 Helper交互（触发wrapAndRelayTokens方法），把WETH发送给L1跨链桥储存，同时在Gnosis Chain的Nova Pool合约中触发onTokenBridged方法来接收L2新增的WETH到池子中并记录这个充值状态（充值状态的确认在原理上和旧版本一样，都是把commitment哈希插入到Merkel Tree中记录状态的）。
    
*   **提款：**
    
    *   提款首先依赖Shield Address私钥持有人构造Proof，参数和旧版本类似。Proof用来在链上验证提款的真实性。
        
    *   构造好Proof之后，如图中红色箭头指示，提款的操作是在Gnosis Chain的选定的Relayer机器人发起的（这个机器人花费的小费相对以太坊链就小的多了）。将Nova Pool中的WETH发给L2跨链桥，并销毁WETH，同时发给L1跨链桥提币请求。
        

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

*   此时L1得到提币消息后，也需要第二个Relayer机器人发起，来完成提币到用户指定地址的交易（此时的小费和旧版本数量类似，并没有很节省成本）。
    
*   **隐私转账（shielded transfer）：**
    
    *   这是Nova新增的功能之一。以往转账的时候需要用户把资金从混币池中提币到另一个地址。在这个新版本中，允许用户资金在不离开Gnosis Nova Pool的情况下，进行池内转账到一个shielded address（前提是这个地址也register过Nova Pool了），转币数量也是任意的，同时需要支付Relayer一笔金额很低的小费。
        
    
    **总结** 由于新版本采用了Omni跨链桥，所以跨链桥面临的安全性问题，Tornado Nova都会面临。新版本的主体功能，也就是WETH的存款池子 Nova Pool本质上是Gnosis链上对L1存款记账的映射。这样做的好处是，由于在Gnosis链上操作，让后续池内转账shield transfer的成本更低。另一个好处就是引入了shield address的私钥，来代替旧版本中的神秘代码Note，简化了用户每次存储的门槛（只需要保管好一个私钥就够了，不用每笔都记录Note）。坏处就是由于使用了跨链桥牺牲了安全性，并且也不能降低充币和提币的成本（同样依赖L1的Relayer机器人）。对于用户来讲，旧版本更可靠，适合低频率大资金的操作需求；新版本更灵活，适合高频率小资金的操作需求。

---

*Originally published on [mazemax](https://paragraph.com/@mazemax/tornado-cash)*
