
1. 存款不是“转账”,而是一次承诺提交
很多人第一次使用 Tornado官网(龙卷风官网) 时会误以为存款就是“把钱转到某个地址”。实际上,Tornado Cash 的存款是一次密码学承诺的提交:你把一段哈希值写入智能合约,合约并不记录你是谁。
理解这一点,是理解整个协议隐私机制的前提。如果你还不熟悉整体架构,建议先读 Tornado Cash 技术架构全解。
2. 承诺(Commitment)是怎么生成的
存款时,客户端在本地生成两个随机数:
| 参数 | 作用 |
|---|---|
nullifier |
提款时用于防止双花的唯一标识 |
secret |
与 nullifier 一起构成票据的核心秘密 |
commitment |
= hash(nullifier, secret),提交上链 |
关键点:nullifier 和 secret 永远不离开你的设备。上链的只有 commitment 这个哈希值。这就是为什么票据丢失等于资金永久锁死——协议端根本没有能还原票据的信息。
关于承诺与注销码的密码学博弈,可参考 Tornado官网的 承诺与注销码解析。
3. 面额池设计:为什么要固定金额
Tornado Cash 的存款金额是固定的(如 0.1、1、10、100 ETH),而不是任意金额。这不是设计缺陷,而是隐私保护的核心手段。
如果允许任意金额,观察者可以通过金额匹配直接关联存提款。固定面额让所有存款在链上看起来完全一样,匿名集因此显著扩大。这与 Tornado Cash Nova 的“自定义金额”模式形成对比——Nova 牺牲了部分匿名性,换取了灵活性。
4. 从承诺到 Merkle Tree 插入
commitment 提交到合约后,会被插入 Merkle Tree:
- 合约计算新 commitment 的叶子哈希
- 将叶子插入树的下一个空位
- 更新从该叶子到根的路径上的所有哈希
- 新的根哈希写入合约存储
整个过程链上可见,但树上只有哈希,没有地址。观察者能看到“有一笔存款发生了”,但无法知道是谁存的。Merkle Tree 与 zk-SNARK 的协同机制,详见 Merkle Tree 与 zk-SNARKs 协同工作。
5. 存款阶段的隐私风险点
- 存款地址与身份关联:如果存款地址曾与实名交易所、ENS 域名、社交账号产生关联,隐私从存款那一刻就已受损
- 存款时间规律:固定时间、固定频率存款容易被画像
- Gas 支付方式:用有关联的钱包支付 Gas 会暴露存款者身份
- 面额选择:频繁只用同一种面额存款,会缩小匿名集
更多防护建议见 Tornado官网的 隐私保护最佳实践。
6. 与提款阶段的衔接
存款阶段生成的票据,是提款阶段构造 zk-SNARK 证明的唯一输入。整个流程可以概括为:
| 阶段 | 链上可见 | 链下私密 |
|---|---|---|
| 存款 | commitment 哈希、面额、时间 | nullifier、secret、票据 |
| 等待 | — | 票据保管 |
| 提款 | nullifier 哈希、接收地址 | zk-SNARK 证明的构造过程 |
只要存款和提款之间没有链上或链下的关联痕迹,隐私就得以成立。完整的提款操作注意事项,见 提款全流程避坑指南。
💡 常见疑问解答
commitment 上链后能被反向破解吗?
不能。commitment 是 nullifier 和 secret 的哈希值,在不知道原始输入的情况下,反向破解在计算上不可行。这正是密码学承诺的安全基础。
为什么存款金额必须固定?
固定面额让所有同面额存款在链上无法区分,大幅扩大匿名集。如果允许任意金额,金额本身就成了关联存提款的线索。
存款后立刻提款会怎样?
匿名集会非常小。如果池子里只有你这一笔新存款,观察者几乎可以直接关联。建议等待数天到数周,让同期其他资金进入池子。
