mirror of https://github.com/tornadocash/docs
GitBook: [#8] Describing Tree Update witness
This commit is contained in:
parent
cd4d273ef8
commit
4beb783e73
|
@ -22,7 +22,7 @@ Registering a withdrawal is the essentially the same as registering a deposit, e
|
|||
|
||||
The `registerDeposit` and `registerWithdrawal` contract methods of the Tornado Trees contract each emit a corresponding event, `DepositData` and `WithdrawalData` containing the same values as were included in the computed hash, plus an additional event field indication the order in which they entered into the queue.
|
||||
|
||||
### Chunked Merkle Tree updates in Zero Knowledge
|
||||
### Chunked Merkle Tree Update
|
||||
|
||||
Standard Merkle Trees are fairly expensive to store and update, especially if you want to commit to a large number of leaves. Depositing a note into the Tornado.cash deposit contracts can cost upwards of 1.2M gas, which can be hundreds of dollars worth of ETH if depositing on Ethereum mainnet. Most of this gas cost results from simply inserting a commitment into the deposit contract Merkle Tree.
|
||||
|
||||
|
@ -54,7 +54,7 @@ The leaves of the tree are then populated from left to right with the leaf hashe
|
|||
|
||||
Now that we have the "old root", we can proceed to take a chunk of pending events (256 of them), compute their Poseidon hashes, and insert them into the tree. After updating the non-leaf nodes up to the root, we will have the "new root".
|
||||
|
||||
Next, we need to collect a list of path elements starting from the right-most non-zero leaf in the tree, as well as an array of `0/1` bits indicating whether each path element is to the left or right of its parent node.
|
||||
Next, we need to collect a list of path elements starting from the subtree leaf, as well as an array of `0/1` bits indicating whether each path element is to the left or right of its parent node.
|
||||
|
||||
#### Computing the Args Hash
|
||||
|
||||
|
@ -64,13 +64,45 @@ Construct a message that is the concatenation of these fields:
|
|||
|
||||
1. The old root label (32 bytes)
|
||||
2. The new root label (32 bytes)
|
||||
3. The path indices as bits, left-padded with zeroes (4 bytes)
|
||||
3. The path indices as an integer, left-padded with zeroes (4 bytes)
|
||||
4. For each event
|
||||
1. The commitment/nullifier hash (32 bytes)
|
||||
2. The Tornado instance address (20 bytes)
|
||||
3. The block number (4 bytes)
|
||||
|
||||
Compute the SHA-256 hash of this message, and then compute its modulus against the BN128 group modulus found in the `SNARK_FIELD` constant of the Tornado Trees contract.
|
||||
Compute the SHA-256 hash of this message, and then modulus the hash against the BN128 group modulus found in the `SNARK_FIELD` constant of the Tornado Trees contract.
|
||||
|
||||
#### Inputs to a Tree Update Proof
|
||||
### Generating a Merkle Tree Update Witness
|
||||
|
||||
#### Inputs to a Tree Update Witness
|
||||
|
||||
The [Batch Tree Update](https://github.com/tornadocash/tornado-trees/blob/master/circuits/BatchTreeUpdate.circom) circuit takes a single public input, which is the resulting SHA-256 args hash in the BN128 field.
|
||||
|
||||
The additional private inputs for a Tree Update witness are:
|
||||
|
||||
1. The old root
|
||||
2. The new root
|
||||
3. The path indices as an integer, left-padded with zeroes
|
||||
4. An array of path elements
|
||||
5. For the pending events being inserted
|
||||
1. An array of commitment/nullifier hashes
|
||||
2. An array of Tornado instance addresses
|
||||
3. An array of block numbers
|
||||
|
||||
#### Proven Claim
|
||||
|
||||
To prove that we have updated the tree correctly, we don't have to provide a proof that spans the entire tree. Instead, we can prove just that a subtree of the 8-level chunk size, with a list of specified leaves, was added in place of the left-most zero leaf of a 12-level tree.
|
||||
|
||||
#### Proving the Args Hash
|
||||
|
||||
Instead of specifying all of the inputs publicly, we can take the Args Hash that we computed earlier and compare it to the result of computing the same hash within the ZK circuit, using the private inputs. This makes for a much more efficient proof verification execution.
|
||||
|
||||
#### Build the Subtree
|
||||
|
||||
Taking the three fields of each pending event in the order (instance, commitment/nullifier, block number), we compute the Poseidon hash of each leaf. We then construct the Merkle Tree just for the subtree that we're updating. Since the subtree is full, we don't need to worry about any zero leaves.
|
||||
|
||||
#### Verify the Subtree Insertion
|
||||
|
||||
Lastly, we verify that inserting the subtree root at the proposed position results in the old root transforming to the new root. This works essentially the same way as for the [Merkle Tree Check](core-deposit-circuit.md#computing-the-witness) in the core deposit circuit, except using Poseidon instead of MiMC.
|
||||
|
||||
The [Merkle Tree Updater](https://github.com/tornadocash/tornado-trees/blob/master/circuits/MerkleTreeUpdater.circom) first verifies that the specified path contains a zero leaf by computing what the root would be given the path elements, path indices, and a zero leaf. It compares this against the specified old root, and then repeats that process again with the proposed subtree leaf, comparing the resulting root to the new root.
|
||||
|
|
Loading…
Reference in New Issue