In SnarkyJS, we currently have Poseidon and a (sparse) Merkle Tree implementation to our hands. We would start by initialized an empty `nullifier_tree`, with all leaves being `0`. ``` H(AB,CD) | | H(A,B) H(C,D) | | | | A B C D | | | | 0 0 0 0 ``` Our nullifier algorithm could be defined as `N = H(value, secret)`, where `value` could be a coin (tornado cash) or transaction data, and the `secret` a password. For sake of simplicity `H` only returns a 2 bit value, so it fits our tree with 4 leaves. We would prove, inside a circuit, the following: ```ts function processTransaction(txData: Field, someSecret: Field, nullifierWitness: MerkleWitness) { let nullifier = N(txData, someSecret); // proving non inclusion // the provided merkle witness needs to be the one that fits the nullifier, we can do that by calculating the index let i = nullifierWitness.calculateIndex(); i.assertEquals(nullifier); // now we know that the merkle witness is valid // we then check if the leaf at pos i is indeed empty let calculatedRoot = nullifierWitness.calculateRoot(Field.zero); calculatedRoot.assertEquals(this.nullifierRoot.get()); // if the proposed nullifier is not part of the tree, we can now add it to the tree let newRoot = nullifierWitness.calculateRoot(nullifier); this.nullifierRoot.set(newRoot); } ``` To visualize this, we would go from an empty nullifier tree to a new one which has one nullifier added to it. ``` H(AB,CD) | | H(A,B) H(C,D) | | | | A B C D | | | | 0 0 0 0 ``` to ``` H(AB,CD) | | H(A,B) H(C,D) | | | | A B C D | | | | 0 01 0 0 ``` Assuming that we provide the merkle witness for `index = 1` and our nullifier hashes to `01`, which is supposed to be at `index = 1`