当前位置:首页 > 区块链技术 > Tornado Cash混币器分享

解读Tornado Cash混币器:监管者的眼中钉,却是最精妙的ZK零知识应用

2026-06-14 15:34:58 | 来源: | 作者:佚名
近期 Vitalik 和一些学者联名发表了新论文,其中提到了 Tornado Cash 如何实现反洗钱方案(其实就是让取款人证明,自己的存款记录属于一个不包含黑钱的集合), 但文中缺乏对 Tornado Cash 业务逻辑与原理的细致解读,让人似懂非懂

前阵子被监管者盯上的混币器协议 Tornado Cash,其实是理解 ZK 应用的最佳案例。

近期 Vitalik 和一些学者联名发表了新论文,其中提到了 Tornado Cash 如何实现反洗钱方案(其实就是让取款人证明,自己的存款记录属于一个不包含黑钱的集合), 但文中缺乏对 Tornado Cash 业务逻辑与原理的细致解读,让人似懂非懂。

此外值得一提的是,Tornado 为代表的隐私项目才是真正用到了 ZK-SNARK 算法的零知识性,而大多数打着 ZK 旗号的 Rollup,用到的只是 ZK-SNARK 的简洁性。很多时候人们往往混淆了 Validity Proof 与 ZK 的区别,而 Tornado 恰好是理解 ZK 应用的极佳案例。

延伸阅读:科普|zk-SNARKs是什么?V神定调零知识证明未来十年「非常重要」

本文作者恰好在 2022 年于 Web3Caff Research 写过一篇关于 Tornado 原理的文章,今日将其部分段落节选并拓展,整理成文,以便大家系统的理解 Tornado Cash。

「龙卷风」 的原理

Tornado Cash 是利用了零知识证明的混币器协议,旧版本在 2019 年投入使用,新版本在 2021 年底启动了 beta 版。Tornado 旧版本基本实现了去中心化,链上合约开源且无多签控制,前端代码开源且备份在了 IPFS 网络里。由于旧版 Tornado 的整体结构更简单易懂,所以本文将针对旧版本进行解读。

Tornado 的主要思路是: 把大量的访问款行为混杂在一起,存款者在 Tornado 存入 Token 后,出示 ZK Proof 证明自己存过款,再用一个新地址提款,以此切断访问款地址之间的关联性。

更具体的概括,Tornado 就像一个玻璃箱,混杂了很多人放进去的 Coin 硬币。我们能看到放 Coin 的是哪些人,但这些 Coin 高度同质化,如果有生面孔的人从玻璃箱拿走一枚 Coin,我们很难知道他拿走的 Coin 最初是谁放进去的。

这种场景似乎屡见不鲜:当我们从 Uniswap 池子里 SWAP 几枚 ETH 时,根本无法知道划走的 ETH 是谁提供的,因为曾给 Uniswap 提供流动性的人太多了。但不同之处是,每次用 Uniswap 划走 Token,我们需要用其他 Token 作为等价的成本,且不能把资金 「私密的」 转让给别人;而混币器只需要提款者出示存款凭证就行。

为了让访问款动作看起来有同质性,Tornado 池子的存款地址每次存入的资金、取款地址每次取出的资金都保持一致,比如 某个池子的 100 个存款者和 100 名取款者,虽然公开可见,但看起来彼此没有任何联系,而且每人存入的金额、取出的金额,都是一样的。

这时就可以混淆视听,没法按照访问款金额判断关联性,进而切断资金转移痕迹,显而易见的是,这为洗钱行为提供了天然的便利。

但有一个关键问题:取款者在提款时,怎么证明自己存过款?向混币器发起取款的地址,与所有的存款地址都不关联,那么该如何判断他的提款资格?看起来最直接的方法,是取款者直接披露自己的存款记录是哪一笔,但这就直接泄露了身份。此时零知识证明就派上了用场。

提款者出具一个 ZK Proof,证明自己在 Tornado 合约里有存款记录,且该笔存款尚未被提取,就能顺利发起取款。零知识证明本身就实现了隐私保护,外界只知道:取款人的确往资金池里存过款,但不知道他对应哪个存款者。

要证明 「我在 Tornado 资金池里存过款」 可以被转化为 「我的存款记录可以在 Tornado 合约里找到」。如果用 Cn 表示存款记录,问题就归纳为:

已知 Tornado 的存款记录集合为 {C1,C2,…C100…},取款者 Bob 证明自己曾用手上的密钥,生成了存款记录里的某个 Cn,但通过 ZK 不泄露 Cn 具体是哪个。

这里要用到 Merkle Proof 的特殊性质。因为 Tornado 的所有存款记录,都存进了链上构造的一棵 MerkleTree,作为其最底层的叶子结点,而叶子总数约为 2 的 20 次方 > 100 万,大多数都处于空白状态(赋予了初始值)。每当有新存款行为产生时,合约就会把其对应的特征值 Commitment 写入一个叶子里,然后更新 Merkle Tree 的 root。

比如,Bob 的存款操作是 Tornado 有史以来第 1 万笔,那么与这笔存款有关联的一个特征值 Cn 会写入 Merkle Tree 的第 1 万个叶子结点,也即 C10000= Cn。然后合约会自动算出新的 Root,update 一下。(ps:为了节约计算量,Tornado 合约会缓存之前一批有变化的节点的数据,比如下图中的 Fs1 和 Fs2、Fs0)

而 MerkleProof 本身很简洁轻便,它利用了树状数据结构在检索 / 溯源过程中的简洁性。若想对外证明某笔交易 TD 存在于 MerkleTree 中,只要给出 Root 对应的 MerkleProof(如下图中右边的部分),它相当简洁。如果 Merkle Tree 格外庞大,底层叶子有 2 的 20 次方个,也就是包含 100 万笔存款记录,Merkle Proof 也只需要包含 21 个节点的数值,非常短。

如果要证明某笔交易 H3 的确包含在 Merkle Tree 中,设法证明用 H3 和 Merkle Tree 上其他的部分数据,可以生成 Root,而生成 Root 所需要的那部分数据(包括 Td 在内)就构成了 Merkle Proof。

而 Bob 在取款时,要证明自己拥有的凭证对应着 Merkle Tree 上有记录的某笔存款hash Cn。也就是说,他要证明两件事:

・Cn 存在于链上 Tornado 合约里的 Merkle Tree 中,具体可以构造一个 Merkle Proof,里面包含 Cn;

・Cn 与 Bob 手上的存款凭证有关联。

Tornado 业务逻辑详解

Tornado 用户界面的前端代码中事先实现了很多功能,当一名存款者打开 TornadoCash 网页并点击存款按钮后,前端代码附带的程序会在本地生成 2 个随机数 K 和 r,随后会计算出 Cn=Hash (K,r) 的值,再把 Cn(就是下图中的 commitment)传入 Tornado 合约,插入到后者记录的 Merkle Tree 里。说白了,K 和 r 相当于私钥。它们很重要,系统会提示用户妥善保存。后面提款时仍然要用到 K 和 r。

值得注意的是,以上工作皆发生于链下,也就是说:Tornado 合约和外界观察者都不知晓 K 和 r。 如果 K 和 r 被泄露了,就类似于钱包私钥被盗。

Tornado 合约收到用户存款,并收到用户提交的 Cn=Hash (K,r) 后,便将 Cn 插入到 Merkle 树的最底层,作为新的叶子结点,同时会更新 Root 的数值。 所以,Cn 和用户的存款动作是一对一关联的,外界可以知道每个 Cn 对应着哪个用户,知道有哪些人往混币器里存入了 Token,并且知道每个存款者对应的存款记录 Cn。

在取款步骤中,取款者在前端网页里输入凭证 / 私钥(存款时生成的随机数 K 和 r),TornadoCash 前端代码中的程序会使用 K 和 r、Cn=Hash (K,r)、Cn 对应的 Merkle Proof 作为输入参数,生成 ZK Proof,证明 Cn 是存在于 Merkle Tree 上的某笔存款记录,而 K 和 r 是对应 Cn 的凭证。

这一步就相当于证明:我知道某笔记录于 Merkle Tree 上的存款记录对应的密钥。当 ZK Proof 被提交给 Tornado 合约时,上述 4 个参数均被隐藏,外界(包括 Tornado 合约)无法获知,借此保障了隐私。

生成 ZKProof 涉及的其他参数还包括: 取款时 Tornado 合约里 Merkle Tree 的根 root、自定义的收款地址 A、防止重放攻击的标识符 nf (后面会讲)。这 3 个参数会公开发布到链上,外界可以获知,但不影响隐私。

延伸阅读:重入攻击是什么?Curve池内的7000万美元如何丢的?

这里面有个细节,就是存款操作生成 Cn 时,用了 2 个随机数 K 和 r 来生成 Cn,而不是单个随机数。这是因为单个随机数不够安全,有一定概率发生碰撞,比如,采用单随机数可能导致两个不同的存款者恰巧采用 1 个同样的随机数,导致生成的 Cn 撞车。

至于上图中的 A,代表接收提款的地址,由提款者自己填写。nf 则是一个防止重放攻击的标识符,其数值 nf=Hash(K),K 就是存款生成 Cn 那一步用到的 2 个随机数之一(K 和 r)。这样一来,nf 就与 Cn 关联了起来,换言之,每个 Cn 都有对应的 nf,两者一一关联。

为什么要防止重放攻击呢? 由于混币器在设计上的特性,取款时不知道用户提走的币对应 Merkle 树的哪个叶子 Cn,也就不知道提款人和哪些存款人关联,就不知道提款人到底存过几次款。提款者可以利用这一特性频繁提款,发起重放攻击,多次从混币器池里取走 Token,直到把资金池抽干。

在这里,nf 标识符的作用类似于每个以太坊地址都有的交易计数器 nonce,都是为了防止某笔交易被重放而设置。当一笔取款发生时,取款者需要提交一个 nf,检查这个 nf 是否已被使用过(记录在案):如果有,此次取款无效。如果没有,表示该 nf 尚未被使用,取款有效,对应的 nf 会被记录下来。下次再有人提交这个 nf 时,对应的取款动作直接判定为无效。

如果有人胡乱生成一个合约没记录过的 nf 行不行? 当然不行,因为取款者生成 ZK Proof 时,需要保证 nf=Hash(K),而随机数 K 与存款记录 Cn 关联,也就是说,nf 与某笔有记录的存款 Cn 关联。如果随便编造一个 nf,这个 nf 与存款记录中的所有存款都对不上号,就不能顺利生成有效的 ZK Proof,后续的工作就无法顺利完成,取款操作就不会成功。

可能也有人会问:不用 nf 行不行?既然提款者在提款时需要提交 ZK 证明,证明自己和某个 Cn 有关联,那么每当提款动作发生时,查找对应的 ZK Proof 是否被提交到链上过,不就行了吗?

但事实上,这样做的成本很高,因为 Tornado cash 合约不会永久保存过去提交的 ZK Proof,因为这会严重浪费保存空间。与其比较每个新交到链上的 ZKProof 和既有的 Proof 是否一致,还不如设置个占地很小的标识符 nf 并将其永久保存来的更划算。

按照取款函数的代码示例,其需要的参数和业务逻辑如下:

用户提交 ZKProof、nf(NullifierHash)=Hash(K),自定义一个接收提款的地址 recipent,ZKProof 隐藏了 Cn 和 K、r 的数值,让外界无法获取判断用户身份。recipent 往往会填写一个干净的新地址,也不会泄露个人信息。

但这里面有个小问题,就是用户在取款时,为了不可溯源,往往用新申请的地址发起取款交易,此时新地址没有 ETH 来支付 gas 费。所以取款地址发起取款时,要显式声明一个中继者 relayer,由它代付 gas 费,之后混币器合约会直接从用户提款里扣掉一部分交给 relayer,作为回报。

综上所述,TornadoCash 可以隐瞒取款者与存款者的关联,在用户量很大的情况下,就如同一个闹市区,犯人混进人群后警方就难以追踪。取款过程中需要用到 ZK-SNARK,被隐藏起来的 witness 部分包含取款人关键信息,这是整个混币器最关键的一点。目前看来,Tornado 可能是与 ZK 相关的最巧妙的应用层项目之一。

免责声明:本文只为提供市场讯息,所有内容及观点仅供参考,不构成投资建议,不代表本站观点和立场。投资者应自行决策与交易,对投资者交易形成的直接或间接损失,作者及本站将不承担任何责任。!
Tag:混币器   Cash   Tornado  

你可能感兴趣的文章

币圈快讯

  • Pump.fun日收入198万美元反超Hyperliquid

    2026-10-25 18:03
    Solana链上memecoin发射平台Pump.fun过去24小时协议收入达198万美元,超过去中心化永续合约交易所Hyperliquid的196万美元,实现日收入反超。Hyperliquid在更长的7天维度仍保持领先。这一变化反映memecoin板块活跃度上升。另据Polymarket数据,Hyperliquid于2026年底触及100美元目标的YES概率降至27.5%,较24小时前的36%明显回落,市场认为或与Pump.fun亮眼收入表现影响对其信心有关。市场将关注Pump.fun能否在后续数日维持对Hyperliquid的收入领先。
  • Keystone硬件钱包官网遭入侵客户姓名地址订单信息泄露

    2026-10-25 17:47
    10月25日,香港自托管硬件钱包品牌Keystone(以全隔离、二维码签名著称)披露其官网于10月20日遭未授权访问,暴露客户姓名、联系方式、收货地址及订单详情(含购买商品与价格)。公司10月23日经与Shopify核对API活动后确认第三方获取客户发货信息。Keystone强调,支付卡与银行信息、助记词、私钥及钱包密码均未泄露。公司已封堵访问、修补漏洞、启动调查并邮件通知受影响客户,警告诈骗者可能冒充Keystone以退款或换设备为由行骗,提醒客户勿点可疑链接、勿泄露助记词与私钥,并计划数日内发布详细报告。同业中Trezor(8月物流商ShipMonk泄露)、Ledger(本月改装真机窃助记词)亦曾发生安全事件。
  • Solana联合创始人Toly提出验证者权益加权预言机构想拟抵押铸造新SOL

    2026-10-25 17:24
    10月25日,Solana联合创始人AnatolyYakovenko(代号Toly)在X发文提出"验证者权益加权预言机"(validatorstake-weightedoracle)早期构想。机制上,由Solana验证者充当价格裁判,按其质押SOL比例加权投票,为代币化抵押品定价,系统据此铸造新SOL以助网络交易,并对相关利润征税以增加网络收入。该构想紧接10月21日Alpenglow升级(交易最终性提至约150毫秒、精简验证者投票)提出。目前仅为社交媒体构想,非正式治理提案,无投票安排或实施时间表。潜在争议:铸造新SOL改变供应,需说服持有者新发行为安全背书而非稀释;验证者同时掌控安全与定价引发激励及操纵风险;对Pyth、RedStone等现有预言机构成潜在竞争或互补。
  • 高盛将韩国KOSPI指数12个月目标位下调25%

    2026-10-25 16:53
    10月25日,高盛集团的策略师们将韩国KOSPI指数的目标位下调了25%。此前,他们曾在今年多次上调该指数的目标位,但随着市场对AI相关交易的担忧加剧,他们如今选择了下调。以蒂莫西·莫为首的分析师团队将KOSPI指数的12个月目标位从12,000点下调至9,000点。他们指出,鉴于该基准指数已较6月份的高点下跌超过35%,估值假设需要变得更加审慎。这些策略师认为,此轮抛售已使韩国股市处于被严重低估的状态;即便在下调目标位后,该指数仍有超过60%的上涨空间。(金十)
  • 麻吉大哥黄立成ETH25倍多单遭强平后重新入场现持115枚ETH

    2026-10-25 16:34
    10月25日,链上数据显示,受昨日晚间加密市场暴跌影响,麻吉大哥黄立成的25倍以太坊多单于今晨遭全部强平,净亏损超18万美元。随后黄立成再次入场开多并小额加仓,目前仓位仅持有115枚ETH,仓位价值约26.9万美元,当前清算价2316美元。
  • 查看更多