Zorb logoZorb
ZORB Cash

Nullifier Epochs

How ZORB Cash keeps storage costs low

Nullifier Epochs

TL;DR: ZORB Cash prunes old nullifier data instead of storing it forever. This makes the protocol ~100x cheaper to operate long-term.


The Problem

Every privacy protocol needs to prevent double-spending. When you spend a note, it creates a "nullifier"—a unique identifier that gets recorded so the same note can't be spent twice.

Most protocols store nullifiers forever. This works, but storage costs grow without bound. On Solana, this means paying rent for an ever-growing list of spent notes.


Our Solution: Epochs

ZORB Cash uses a two-layer system:

  1. Recent nullifiers — Stored as individual on-chain accounts (PDAs)
  2. Historical nullifiers — Compressed into a Merkle tree

Every ~5 minutes, an epoch advances. Nullifiers from old epochs get inserted into the Merkle tree, and their individual accounts can be closed.

Epoch 0    Epoch 1    Epoch 2    ...    Epoch 30    Current
────────────────────────────────────────────────────────────
           │          Provable Range (30 epochs)          │
           └──────────────────────────────────────────────┘

Epochs older than 30 can be pruned:
  • Close EpochRootAccount → reclaim ~64 bytes rent
  • Close NullifierAccount → reclaim ~56 bytes rent

Why This Works

The key insight: once a nullifier is in the Merkle tree, we don't need its individual account anymore. The tree proves the nullifier exists.

We keep a 30-epoch window (~2.5 hours) to give transactions time to finalize. After that, the data can be safely pruned.


Economic Incentive

Anyone can call the cleanup instructions and keep the reclaimed rent. This creates a natural incentive for keepers to maintain the protocol.

No coordination needed—if cleanup is profitable, someone will do it.


The Numbers

MetricValue
Epoch duration~5 minutes (configurable)
Retention window30 epochs (~2.5 hours)
EpochRootAccount size64 bytes
NullifierAccount size56 bytes
Tree capacity67 million nullifiers

See Also