<aside> 💡 V神的新论文讲了什么?
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4563364
</aside>
分不同单笔额度的资金池,每个资金池允许用户从一个地址Deposit,然后往另一个地址Withdraw
https://ipfs.io/ipns/tornadocash.eth/
Deposit:生成CommitmentHash并发布,保留私钥
用户随机生成Nullifier和Secret
https://betterprogramming.pub/understanding-zero-knowledge-proofs-through-the-source-code-of-tornado-cash-41d335c5475f
用户计算CommitmentHash = Hash(Nullifier, Secret)
用户打钱到链上合约,同时发布CommitmentHash,记录进Commitment Merkle tree
Withdraw:证明知道某个CommitmentHash的私钥,并发布对应的NullifierHash让其失效
用户计算NullifierHash = Hash(Nullifier)
用户计算zero-knowledge proof
private inputs: Nullifier、Secret、CommitmentHash、Commitment Merkle path
public inputs: NullifierHash、Commitment Merkle root
满足约束
source code(circom)
template Withdraw(levels) {
signal input root;
signal input nullifierHash;
...
signal private input nullifier;
signal private input secret;
signal private input pathElements[levels];
signal private input pathIndices[levels];
component hasher = CommitmentHasher(); // 约束1
hasher.nullifier <== nullifier;
hasher.secret <== secret;
hasher.nullifierHash === nullifierHash; // 约束2
component tree = MerkleTreeChecker(levels); // 约束3
tree.leaf <== hasher.commitment;
tree.root <== root;
for (var i = 0; i < levels; i++) {
tree.pathElements[i] <== pathElements[i];
tree.pathIndices[i] <== pathIndices[i];
}
...
}
用户发布public inputs和proof到链上合约,合约验证,然后打钱给用户
验证NullifierHash未发布过并记录(即这个Deposit没被Withdraw过)
验证Commitment Merkle root历史上存在
结合public inputs验证proof
source code(solidity)
function withdraw(
bytes calldata _proof,
bytes32 _root,
bytes32 _nullifierHash,
address payable _recipient,
address payable _relayer,
uint256 _fee,
uint256 _refund
) external payable nonReentrant {
...
require(!nullifierHashes[_nullifierHash], "..."); // 验证1
require(isKnownRoot(_root), "..."); // 验证2
require(
verifier.verifyProof(
_proof,
[uint256(_root), uint256(_nullifierHash), uint256(_recipient), uint256(_relayer), _fee, _refund]
),
"Invalid withdraw proof"
); // 验证3
nullifierHashes[_nullifierHash] = true;
_processWithdraw(_recipient, _relayer, _fee, _refund);
emit Withdrawal(_recipient, _nullifierHash, _relayer, _fee);
}
证明Withdraw来自于历史Deposit的全集 => 子集(称作Association Set)
Association Set Providers(ASPs)中心化地发布Association Sets,用户选择一个包含自己Deposit的进行证明
Association Set的可以采用包含好的和去除坏的等表示方式
Association Set选取Deposit可以有多种方式