Tornado.Cash是以太坊上完全去中心化的匿名交易协议,基于zk-SNARK实现,可以切断交易中发送者和接收者的关联,目前支持代币有:ETH, DAI, cDAI(Compound Dai),USDC,USDT,WBTC。
Tornado.Cash支持采用 relayer 进行取款,将资金发送到新生成的地址上。
Tornado.Cash于2019年在以太坊上线,2021年6月,在 BSC 和 Polygon上部署, 分别支持BNB 和 Matic 代币的匿名化。
Tornado.Cash支持一些代币进行匿名挖矿,可以获取TORN治理代币。
匿名交易原理
Tornado.Cash支持deposit 和 withdraw 两种操作, deposit 将用户将资金存入资金池中,经过混币后,再通过withdraw将资金取到一个新的地址中。因此越多人参与,匿名效果越好。
存款
用户要往合约存款,需要生成两个248bits的随机数k,r,k为nullifier,r为随机数,这两个数就是凭证。 计算
commitment = H1(k||r), H1是PedersenHash
commitment是触发TC合约存款函数deposit的唯一参数。
deposit函数主要完成以下工作
- 检查commitment是否已存在(合约要求commitment不能重复)
- 将commitment插入到merkle树中
- 将commitment标记为已存在(mapping(bytes32 => bool) public commitments)
- 如果是针对ERC20的代币,则执行转账,将用户账户的token转到合约账户里。如果是ETH,则不用执行显示转账,在触发合约deposit函数时必须附带指定金额的ETH.
合约deposit执行成功后会emit
event Deposit(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp);
用户可以确定自己的commitment处于叶子节点的位置。
提款
用户要想提款,必须向合约提供proof,证明用户知道某个commitment对应的隐私信息(k,r),同时不能让别人知道(k,r)的任何信息,确保别人不知道花费的是哪个commitment.
具体步骤:
-
用户选择一个收款地址A和fee,fee是根据具体的中继者的收费标准确定。
-
用户选择一个Root,构造证明commitment存在的Merkle path。在合约里,存储里最近100个历史Root,而非所以的历史Root。
-
计算nullifier(即k)的hash, h=H1(k).
-
计算零知识证明的proof,具体算法用的是Groth16。约束条件为:
- h = H1(k)
- commitment = H1(k||r)
- commitment的Merkle证明
公开输入:Root, h,
隐私输入:k, r, l(commitment在叶子节点的位置), path
-
触发合约withdraw函数
withdraw(bytes calldata _proof, bytes32 _root, bytes32 _nullifierHash, address payable _recipient, address payable _relayer, uint256 _fee, uint256 _refund)
withdraw函数完成以下过程:
- 检查_nullifierHash是否被花掉
- 检查_root是否是历史root
- 验证_proof
- _nullifierHash标记为已花掉
- 处理转账:分别转给收款人和中继者(若有)。
- refund:这个字段是针对ERC20 token设置的,用户可以用自己的token跟中继者兑换一些ETH,可以用来支付以后的交易gas费用。
Setup
- TC合约部署时绑定验证proof的合约,存/提款金额,Merkle树高度(20),特权账户(operator).
等trusted setup完成之后,特权账户更新proof的验证密钥VK,然后将特权账户地址更新为0,之后便没有任何人可以更改VK,保证合约的安全性。 - 针对ERC20 token,部署合约时还要绑定对应的ERC20合约。
凭证示例:
tornado-eth-1-5-0xc594a62c82e8772b1731601a90d30f0d5b705fdcdd3147b46c3a1dbe546f58173f2a8ad7b19dce041e46a4626a48ff555b00eaa33ea47a5f6bf812d7c2c1
在deposit时,需要更新20层的Merkle树, 需要消耗较多的gas; withdraw 生成证明的过程相对复杂,但消耗的gas较少。
匿名挖矿
匿名挖矿主要激励用户将资金在资金池存留更长时间,增加匿名池资金, 以提升交易匿名性。激励从2020.12开始, 到2021.12月截止。
支持匿名挖矿的代币有:ETH, WBTC, DAI, cDAI. 资金存款每过一个块会获取固定AP(Anonymity Points) 奖励,AP 可以兑换 TORN代币,汇率是浮动的。
(1) 首先用户发起deposit操作
此时需要构建deposit Mekle 树,叶子节点为hash( address(torando) || commitment || blockNumber):
bytes32 leafHash = keccak256(abi.encode(deposit.instance, deposit.hash, deposit.block));
但是更新Merkle树需要消耗大量的gas费用,因此合约首先记录deposit 的 LeafHash, 更新操作由第(3)步完成。
(2) 等过段时间后,用户发起withdraw 操作.
此时需要构建 withdraw Merkle 树, 叶子节点为: hash(address(tornado) || nullifierHash || blockNumber)
bytes32 leafHash = keccak256(abi.encode(withdrawal.instance, withdrawal.hash, withdrawal.block));
同上,更新Merkle 树由第(3) 步完成,合约记录withdraw 的 LeafHash.
(3) 需要有人调用 updateRoots
, 更新deposit Merkle树和 withdraw Merkle 树,需要消耗大量的gas.
(4) 用户需要利用凭证根据deposit和withdraw时间差获取奖励AP,为了不泄露凭证的信息,需要生成零知识证明,主要包括reward 和withdraw两种操作。
\- reward: 主要为了领取奖励AP:rate * (withdrawalBlock - depositBlock) , 奖励AP以commint 的形式存在于合约Account Merkle树中。
此时需要利用deposit和withdraw 树 生成的零知识证明 构建Accout Merkle 树,叶子点节为: hash( amount || secret || nullifier )
此时可以用匿名挖矿密钥加密 Accout 信息, 在链上存储。 加密密钥又由以太坊密钥加密存储在链上,即使丢失也可以恢复。
为了避免用户重复领取奖励,需要生成:rewardNullifer = noteNullifier
对于累加的奖励,需要生成:accountNullifier.
\- withdraw: 可以取出部分或全部AP,将其转化为TORN代币。
需要根据Account Merkle树生成零知识证明。
为了避免用户重复withdraw, 需要生成 accountNullifer:
用户将AP兑换成TORN代币,采用AMM流动模型,TORN代币线性增加流动池中,AP换成TORN代币的公式为:
BalanceAfter = BalanceBefore * e^(-rewardAmount/poolWeight)
tokens = BalanceBefore - BalanceAfter
链上备份
先前用户需要本地备份凭证,并不方便。目前添加可以在链上存储加密凭证的功能。用户需要设置凭证账户(Note Account), 在deposit时,可以选择利用公钥加密凭证保存链上,可以用对应的私钥解密。
去中心化的Relayer
任何人可以申请成为Realyer, 帮助用户触发withdraw操作,赚取手续费用。采用零知识证明,保证Relayer 无法对withdraw 接收者,手续费,relayer 进行更改。
来源证明
通过提供凭证,可以重新链接发送者和接收者地址,证明资金来源。
合约部署
(1) tornado-core
合约代码:https://github.com/tornadocash/tornado-core.git
部署步骤:
-
部署Verifier.sol
运行:npm run build:circuit 生成 Verifier.sol 合约;
运行:./solc --bin --abi --optimize Verifier.sol 编译合约;
在wallet-cli 利用 deploycontract 部署Verifier.sol 合约
Verifier.sol 合约地址:
https://nile.tronscan.org/#/contract/TYfR63UZJy9XqPwUhZKewnnwgPHEZeX5Wp
-
运行: node compileHasher.js 生成 Hasher的abi 和 字节码;
在wallet-cli利用deploycontract 部署 Hasher 合约。
Hasher 合约地址:https://nile.tronscan.org/#/contract/TZ7GYKy3BwU4fBrK3KQKoXKa8XXHtwMCoi/code
-
编译ETHTornado 合约:./solc --bin --abi --optimize --libraries Hasher:0xFDD12CCE9EF36ABC2C4BD1500FE3322FBECCF3D1 ETHTornado.sol
在wallet-cli 利用 deploycontract 部署ETHTornado合约。
合约地址为:https://nile.tronscan.org/#/contract/TXb7LSgx3BbwqVSzMr9FhMuA3GvgGi1ACA
参考
https://github.com/tornadocash
https://torn.community/t/anonymity-mining-spreadsheet/720
https://github.com/tornadocash/relayer
https://torn.community/t/anonymity-mining-technical-overview/15
https://github.com/tornadocash/tornado-root-updater
https://tornado-cash.medium.com/tornado-cash-governance-proposal-a55c5c7d0703#2084
网友评论