Skip to main content

Nullifier Design

The nullifier is the only piece of data that touches the Bitcoin blockchain. Understanding its design is key to understanding how Shielded CSV achieves both privacy and double-spend protection.

What is a nullifier?

A nullifier is a 64-byte cryptographic commitment that marks a coin as spent. It is published on the Bitcoin blockchain as a Taproot Inscription. Full nodes verify one Schnorr signature per nullifier — nothing else.

Evolution (from the paper)

The Shielded CSV paper describes a 5-step optimization that compresses nullifiers from hundreds of bytes to exactly 64:

StepSizeMechanism
1 (naive)Per coinNullifier = (CoinID, TxHash) — no signature protection
2Per TXNullifier = (PubKey, TxHash) — public key replaces CoinID
396 bytes+ Schnorr signature — protects against unauthorized updates
4128 bytesAggregated signatures — multiple nullifiers per TX
5 (final)64 bytesAccounts + Sign-to-Contract + Schnorr Half-Aggregation

Sign-to-Contract

The transaction hash is embedded into the Schnorr signature itself via Sign-to-Contract:

R' = kG                          (random nonce point)
R = R' + H(R', txHash) * G (commit txHash into nonce)
s = k + H(R', txHash) + e * sk (standard Schnorr with committed nonce)

After half-aggregation, the nonce R_i remains the transaction commitment for the i-th nullifier. No additional data is needed on-chain.

Half-Aggregation

Multiple Schnorr signatures are non-interactively aggregated into a single signature approximately half the size. Publishers collect nullifiers from multiple transactions and post them in a single Bitcoin Taproot Inscription.

Publisher role

Publishers are permissionless — anyone can run one:

  1. Collect nullifiers from users
  2. Aggregate signatures via half-aggregation
  3. Post the batch as a single Bitcoin Taproot Inscription
  4. Charge a fee to cover the inscription cost

The current implementation uses a single publisher built into the backend server. The publisher creates Taproot Inscriptions with a commit/reveal pattern and a marker prefix (4242) for identification.

Nullifier Accumulator

Users maintain a local Nullifier Accumulator — a sorted Merkle tree of all published nullifiers:

  • On each new block: scan for nullifiers, insert into accumulator
  • Old subtrees can be pruned without losing the ability to prove non-membership
  • Reduces wallet storage and limits data exposure on wallet compromise

Blockchain reorganization

If Bitcoin reorganizes, nullifiers in orphaned blocks must be removed from the accumulator. The protocol handles this through a Conditional Nullifier Accumulator Value (NAV) — the accumulator state is tied to a specific chain tip.