Privacy & confidential transactions

nullifier

A nullifier is the clever trick that lets a shielded system prevent double-spending without revealing what was spent. In a transparent chain you stop double-spends by deleting a UTXO from a public set everyone can see. But in a private pool the coins are hidden commitments — you cannot point at the one being spent without breaking privacy. The nullifier solves this: when you spend a shielded note, you publish a unique tag derived from it, and the network simply records every nullifier it has seen. A note can be spent only once because spending it twice would publish the same nullifier twice, which is rejected.

The deep property is that the nullifier is deterministic from the note yet unlinkable to it. It is computed with a pseudorandom function keyed by the owner's secret — in Zcash Sapling, roughly nf = PRF(nk, rho) where nk is a nullifier-deriving key and rho a per-note value — so the same note always yields the same nullifier (catching double-spends) but nobody can connect a published nullifier back to which note commitment it nullifies, because doing so would require the owner's secret key. The zero-knowledge proof accompanying the spend convinces the network that the revealed nullifier was correctly derived from some valid, unspent note in the commitment tree, without disclosing which.

This commitment-plus-nullifier pattern is the universal engine of zero-knowledge payment and mixing systems. Tornado Cash uses the same shape: a deposit inserts a commitment into a Merkle tree, and a withdrawal reveals a nullifier hash and a SNARK proving the nullifier corresponds to some commitment in the tree, letting an unrelated address withdraw without linking to the deposit. The contract stores spent nullifiers to block repeat withdrawals. The two halves are symmetric: the commitment is the coin going in, the nullifier is the coin coming out.

A subtle but important point: the nullifier must depend on the note in a way that is collision-resistant and that an attacker cannot grind. If two different notes could ever produce the same nullifier, an honest spend could be blocked (a denial-of-service or 'nullifier collision' bug); if the nullifier leaked information about the note, privacy would fail. Getting the PRF and its key derivation exactly right is one of the most security-critical parts of any shielded protocol.

commitment   = hash(nullifier, secret)   // deposit
nullifierHash = hash(nullifier)           // withdraw, recorded as spent

The commitment goes in, the nullifier comes out; the link between them stays hidden by the SNARK.

Commitments grow the anonymity set; nullifiers shrink it by exactly one per spend. The set of nullifiers is public and append-only, but it is just a list of opaque tags — it reveals how many spends have happened, never which notes they consumed.

Also called
nullifier hashvoided serial number作廢符雜湊