# Subtree Update Circuit

Details of subtree update circuit

### Input Encodings

Almost all inputs (listed below) are as defined in the JoinSplit Circuit.

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:

`254 - (2*D - log2(B)) - 3`

`0`

bitsthe 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`accumulatorQueue`

on-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.hashBits`

to refer to the 3 hash bits, and`encodedPathAndHash.path`

to 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`newRoot`

whose claimed`leaf`

is the root of the subtree`EmptySubtreeMembershipProof`

- a depth`2*D - log2(B)`

-bit Merkle membership proof against`oldRoot`

whose claimed`leaf`

is`EMPTY_SUBTREE_ROOT.`

`notes`

- a size`B`

array`EncodedNote`

for 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`B`

array 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`

-`B`

bits indicating which insertions are note insertions and which insertions are note commitment insertions. If`bitmap[i] == 1`

, then the`i`

th insertion should be treated as a`note`

insertion, not a note commitment insertion.`preimage`

- a size`B*256`

bit 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

`i`

th`bit`

of`bitmap`

:`bit`

is`0`

or`1`

if

`bit == 1`

, then`preimage[i*256..(i+1)*256] = sha256(notes[i])`

`leaves[i] = noteCommit(note)`

, where`noteCommit`

computes 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.leaf`

is the root of the depth-`log4(B)`

subtree whose leaves are`leaves`

.`EmptySubtreeMembershipProof.leaf`

is the root of an empty depth-`log4(B)`

subtree.`EmptySubtreeMembershipProof.path`

represents the same path as`encodedPathAndHash.path`

`SubtreeMembershipProof.path`

represents the same path as`encodedPathAndHash.path`

`EmptySubtreeMembershipProof`

is a valid Merkle membership proof against`oldRoot`

. This asserts that the subtree was empty before the insertion.`SubtreeMembershipProof`

is a valid Merkle membership proof against`newRoot`

. This asserts that`newRoot`

is the correct root resulting from the subtree update.

Last updated