I've added notes based on the papers I've read on Merkle trees, Verkle trees, and the Mutator set. For Merkle trees, I reviewed Aztec's work on the index Merkle tree and noted the differences from the sparse Merkle tree.
The current design of nullifier trees leverages Sparse Merkle Trees (SMTs) to facilitate membership checks. SMTs store nullifiers at leaves indexed by their value, with each path from leaf to root representing a membership proof. However, SMTs have limitations when used in cryptographic circuits:
Indexed Merkle Trees (IMTs) address the inefficiencies of SMTs by modifying the structure of each node. In an IMT, each node not only stores a nullifier but also pointers to the next higher nullifier in the tree. This results in a linked list-like structure within the Merkle tree, where nodes are connected in increasing order of nullifier values. The key advantage is that we can now use a much smaller tree depth (e.g., 32 levels), significantly reducing the cost of nullifier insertions.
The IMT facilitates efficient non-membership proofs by allowing nodes to act as “low nullifiers,” representing the next lower and higher values surrounding the queried nullifier. When checking for non-membership, the system confirms that the nullifier falls between two existing values, significantly reducing the number of required hashes.
For example, to prove that a nullifier $v=20$ does not exist in the tree, the system reveals the "low nullifier" (e.g., $v=10$) and shows that its next value ($v_{\text{next}} = 30$) skips over 20. This requires a handful of hashes and range checks, instead of traversing a deep SMT.
Inserting a nullifier in an IMT follows a straightforward protocol:
This results in significantly fewer constraints compared to SMTs, as the tree depth is much smaller and fewer hashing operations are needed.