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:
| Step | Size | Mechanism |
|---|---|---|
| 1 (naive) | Per coin | Nullifier = (CoinID, TxHash) — no signature protection |
| 2 | Per TX | Nullifier = (PubKey, TxHash) — public key replaces CoinID |
| 3 | 96 bytes | + Schnorr signature — protects against unauthorized updates |
| 4 | 128 bytes | Aggregated signatures — multiple nullifiers per TX |
| 5 (final) | 64 bytes | Accounts + 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:
- Collect nullifiers from users
- Aggregate signatures via half-aggregation
- Post the batch as a single Bitcoin Taproot Inscription
- 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.