Subtree Update Circuit
Details of subtree update circuit
Input Encodings
Almost all inputs (listed below) are as defined in the JoinSplit Circuit.
The only special encoding we need for this circuit is to deal with the fact that accumulatorHash is a 256-bit value, which is not guaranteed to fit in an  element.
Another public input for the circuit is the path to the root of the subtree spanning our batch update. The way this is encoded requires a bit more detail about the commitment tree's structure.
Our note commitment tree is quaternary - each branch node has four children, not two. That means the "path" is not a sequence of booleans (left vs right), but a sequence of numbers between 0 and 4. For binary trees, usually people use the fact that the big-endian binary representation of the index of a given leaf is the path - starting at the root, each bit when read left-to-right tells us which way to go.  This would be a D - log2(B) bit unsigned integer, where D is the depth of the tree and B is the batch size.
For our quaternary tree, this is almost identical - the only difference is that we read the big-endian bit representation of the index two bits at a time, giving us a sequence of two-bit numbers 0-4 which tell us which child to traverse instead of a sequence of bits. If our tree is depth D then this will be a 2*D - log2(B) bit number. In our case, D = 16 and B = 16, which means our path will take up 28 bits.
This gives us plenty of room so we can pack the 3 most-significant bits of accumulatorHash into the path's field element. The resulting encoding is as follows:
- accumulatorHashis the element represented by the 253 least-significant bits of the "actual" 256-bit- accumulatorHash
- encodedPathAndHashis the element represented by the following bits, from most-significant to least-significant:- 254 - (2*D - log2(B)) - 3- 0bits
- the 3 most-significant bits of the actual - accumulatorHash
- the - 2*D - log2(B)bits of the path from the root of the commitment tree to the root of the subtree spanning the batch insertion
 
Statement to Prove
The Subtree Update circuit has the following public inputs:
- accumulatorHash- the 253 least-significant bits of the hash at the tip of the- accumulatorQueueon-chain
- encodedPathAndHash- a bit-packed field element containing the path from the root of the commitment tree to the root of the subtree spanning the batch and the 3 most-significant bits of- accumulatorHash.- For notation's sake, I will use - encodedPathAndHash.hashBitsto refer to the 3 hash bits, and- encodedPathAndHash.pathto refer to the- 2*D - log2(B)path bits
 
- oldRoot- the old root of the commitment tree
- newRoot- the claimed new root of the commitment tree
We also define the constant EMPTY_SUBTREE_ROOT, which is the root of the depth-log2(B) subtree containing B zeros.
And requires the following private data:
- SubtreeMembershipProof- a depth- 2*D - log2(B)-bit Merkle membership proof against- newRootwhose claimed- leafis the root of the subtree
- EmptySubtreeMembershipProof- a depth- 2*D - log2(B)-bit Merkle membership proof against- oldRootwhose claimed- leafis- EMPTY_SUBTREE_ROOT.
- notes- a size- Barray- EncodedNotefor each leaf in the tree. For note commitment insertions, the corresponding entry is ignored. These are encoded as defined in the encodings section.
- leaves- a size- Barray containing the leaves of the subtree - that is, the note commitments of every note to be inserted, no matter which insertion case it is.
- bitmap-- Bbits indicating which insertions are note insertions and which insertions are note commitment insertions. If- bitmap[i] == 1, then the- ith insertion should be treated as a- noteinsertion, not a note commitment insertion.
- preimage- a size- B*256bit array containing every insertion digest concatenated together.
We prove that the following conditions hold true, converting to/from big-endian bit representation as needed:
- for the - ith- bitof- bitmap:- bitis- 0or- 1
- if - bit == 1, then- preimage[i*256..(i+1)*256] = sha256(notes[i])
- leaves[i] = noteCommit(note), where- noteCommitcomputes the note commitment of a note.
 
- otherwise, - preimage[i*256 + 2..(i+1)*256] = leaves[i]
 
- encodedPathAndHash.hashBits || accumulatorHash = sha256(preimage)- where - ||denotes concatenation
 
- SubtreeMembershipProof.leafis the root of the depth-- log4(B)subtree whose leaves are- leaves.
- EmptySubtreeMembershipProof.leafis the root of an empty depth-- log4(B)subtree.
- EmptySubtreeMembershipProof.pathrepresents the same path as- encodedPathAndHash.path
- SubtreeMembershipProof.pathrepresents the same path as- encodedPathAndHash.path
- EmptySubtreeMembershipProofis a valid Merkle membership proof against- oldRoot. This asserts that the subtree was empty before the insertion.
- SubtreeMembershipProofis a valid Merkle membership proof against- newRoot. This asserts that- newRootis the correct root resulting from the subtree update.
Last updated
