
在Tornado官网关于龙卷风币(Tornado Cash)的技术讨论中,抽象的概念常常让新用户感到困惑:Merkle Tree如何存储存款?zk-SNARKs如何实现”零知识”?存款和提款之间到底发生了什么?
为了帮助读者更直观地理解,本文将通过表格和结构化说明,逐步拆解龙卷风币(Tornado Cash)的隐私保护流程。
1. 总体流程概览
下表展示了用户与龙卷风币(Tornado Cash)智能合约交互的完整流程,从存款到提款的四个核心步骤。
| 步骤 | 操作 | 参与方 | 关键产出 |
|---|---|---|---|
| ① | 用户发起存款,准备将ETH或ERC20代币存入 | 用户 | 存款请求 |
| ② | 生成随机票据(Note),包含 nullifier 和 secret | 用户钱包 | 票据 |
| ③ | 通过 Pedersen 哈希计算承诺(Commitment) | 用户钱包 | 承诺 |
| ④ | 将承诺作为叶子节点插入 Merkle Tree,更新树根 | 智能合约 | Merkle Root |
| ⑤ | 存款完成,资金进入混币池,链上仅记录承诺 | 智能合约 | 存款记录 |
| ⑥ | 等待期:建议等待一段时间,让更多存款进入,扩大匿名集 | 用户 | 增强隐私 |
| ⑦ | 用户发起提款,准备提取资金,使用新地址接收 | 用户 | 提款请求 |
| ⑧ | 在本地生成 zk-SNARK 证明(三项核心验证) | 用户钱包 | 零知识证明 |
| ⑨ | 提交证明 + nullifier 哈希至智能合约 | 用户 → 合约 | 验证请求 |
| ⑩ | 智能合约验证证明有效性,检查 nullifier 状态 | 智能合约 | 验证结果 |
| ⑪ | 验证通过:记录 nullifier,防止双花攻击 | 智能合约 | 交易上链 |
| ⑫ | 提款完成:资金发送至用户新地址,交易完全匿名 | 智能合约 → 用户 | 匿名交易 |
流程关键节点说明:
- 步骤 ②-④ 是存款核心,用户生成秘密凭证,链上只记录其”指纹”(承诺)。
- 步骤 ⑥ 是隐私增强的关键,等待时间越长,匿名集越大,隐私保护越强。
- 步骤 ⑧ 是技术的核心,用户在本地生成证明,不透露任何存款细节。
- 步骤 ⑪ 是安全核心,通过记录 nullifier 确保每个票据只能被使用一次。
2. 存款流程详解:承诺如何诞生?
当用户向龙卷风币(Tornado Cash)存款时,会发生以下关键步骤:
| 步骤 | 操作 | 说明 | 关键点 |
|---|---|---|---|
| 1 | 生成随机数 | 钱包生成两个31字节的随机数 —— nullifier(注销码)和 secret(秘密值) |
共同构成唯一票据 |
| 2 | 形成票据 | nullifier + secret 组合成票据(Note) |
用户未来提款的唯一凭证 |
| 3 | Pedersen 哈希 | 通过 Pedersen 哈希将票据压缩成一个唯一的”数字指纹” | 单向加密,不可逆 |
| 4 | 生成承诺 | 哈希计算结果即为 承诺(Commitment) | 存款的”数字指纹” |
| 5 | 插入 Merkle Tree | 承诺作为叶子节点插入 Merkle Tree,并更新树根 | 链上只记录承诺,不记录票据本身 |
此时,用户的资金已进入混币池,链上只留下一个无法被反向推导的”承诺”。
技术细节: 存款时用户提交的是票据的哈希值(承诺),而不是票据本身。由于哈希函数的单向性,外部观察者无法从链上记录反推出票据内容。想深入了解 Merkle Tree 的技术原理,可以阅读我们之前的文章:Merkle Tree 与 zk-SNARKs 协同工作。

3. 提款流程详解:零知识证明如何工作?
提款是理解”零知识”的关键。用户提款时,证明与验证的交互流程如下:
| 阶段 | 操作 | 参与方 | 说明 |
|---|---|---|---|
| 准备阶段 | 用户输入票据(Note) | 用户 → 钱包 | 用户提供 nullifier 和 secret |
| 证明生成 | 钱包在本地生成 zk-SNARK 证明 | 用户钱包 | 证明三项核心内容 |
→ 证明1:知道有效 nullifier 和 secret |
钱包 | 拥有合法票据 | |
| → 证明2:承诺存在于 Merkle Tree 中 | 钱包 | 存款真实存在 | |
→ 证明3:nullifier 未被使用 |
钱包 | 票据未被提取 | |
| 提交验证 | 提交证明 + nullifier 哈希 |
用户 → 合约 | 提款请求 |
| 合约验证 | 验证证明有效性 | 智能合约 | 检查证明是否合法 |
检查 nullifier 哈希是否已记录 |
智能合约 | 确保未被使用 | |
| 结果处理 | ✅ 验证通过:记录 nullifier,发送资金至提款地址 |
智能合约 → 用户 | 提款成功,交易匿名 |
| ❌ 验证失败或已使用:拒绝交易 | 智能合约 | 提款失败 |
关键点解析:
- 证明者(用户) 在本地生成证明,不透露任何存款细节(如存款时间、金额、具体来源地址)。
- 验证者(智能合约) 仅验证证明的有效性和
nullifier的新鲜度。 - 整个过程不会暴露存款的时间、金额或具体来源。
关于龙卷风币(Tornado Cash)的 zk-SNARK 技术原理,可以阅读我们的文章:Tornado Cash 与 zk-SNARK。
4. 核心数据结构:Merkle Tree 说明
Merkle Tree 是龙卷风币(Tornado Cash)存储所有存款承诺的核心数据结构。其结构可以用以下层级说明:
| 层级 | 节点类型 | 内容 | 说明 |
|---|---|---|---|
| 树根 | Merkle Root | 所有存款的”数字指纹” | 任何一笔存款变动都会导致Root改变 |
| 中间节点 | Hash 1-2, Hash 3-4 | 子节点哈希值的组合 | 逐层向上计算,最终汇聚到Root |
| 叶子节点 | 承诺 1, 2, 3, 4… | 每笔存款的承诺值 | 每个叶子代表一笔存款 |
Merkle Tree 的结构特点:
- 高度20:最多可容纳超过一百万个存款记录。
- 高效验证:用户提款时,只需提供从自己的叶子节点到Root的Merkle路径(约20个哈希值),即可证明自己的存款存在于树中。
- 隐私保护:验证过程不透露具体是哪个叶子节点,从而隐藏了存款的时间、金额等关键信息。
5. 完整流程总结
| 阶段 | 核心操作 | 链上记录 | 隐私保护要点 |
|---|---|---|---|
| 存款 | 生成票据 → 计算承诺 → 插入 Merkle Tree | 仅存储承诺 | 票据离线保存,链上无法反推 |
| 等待 | 等待更多存款进入 | 无操作 | 扩大匿名集,增强隐私 |
| 提款 | 生成 zk-SNARK 证明 → 提交验证 | 记录 nullifier 哈希 |
证明不泄露存款细节 |
这些图解不仅适用于龙卷风币(Tornado Cash),也展示了零知识证明和 Merkle Tree 在区块链隐私保护中的经典应用模式。查看龙卷风币(Tornado Cash)的最新链上数据和生态指标,可以访问我们的数据看板。
💡 常见疑问解答
Tornado Cash的存款流程中承诺是如何生成的?
用户存款时,钱包生成两个31字节的随机数nullifier和secret,通过Pedersen哈希压缩成一个唯一的承诺(Commitment),该承诺作为叶子节点插入Merkle Tree,链上只记录承诺而非票据本身。
Tornado Cash提款时零知识证明验证什么内容?
提款时zk-SNARK证明验证三项内容:用户拥有有效的nullifier和secret、承诺存在于Merkle Tree中、nullifier未被使用。验证通过后记录nullifier防止双花。
为什么提款时建议等待一段时间?
等待时间越长,期间有越多的其他存款进入池子,你的交易就会融入更大的匿名集(Anonymity Set)中,使外部观察者更难将你的存款和提款关联起来。
Merkle Tree在Tornado Cash中起什么作用?
Merkle Tree存储所有存款的承诺值,高度为20可容纳超过一百万笔存款。提款时用户提供从叶子节点到根节点的Merkle路径证明存款存在,但不透露具体是哪个叶子节点。
