Skip to main content

Lifecycle Mental Model

Read This First

This section explains what the protocol does and where data lives. Understanding this is essential before building.

What the Protocol Does

Ghost Protocol is a general-purpose ZK-SNARK commit-reveal mechanism that enables anonymous, untraceable data commitments. Users commit data cryptographically and later reveal it with a ZK proof—without exposing the link between commit and reveal.

The protocol uses a commit-reveal mechanism:

  1. Commit: Record a cryptographic commitment on-chain
  2. Reveal: Prove knowledge of secrets with a ZK proof and execute application logic

Between commit and reveal, the commitment exists on-chain but its contents are hidden. Applications can implement any logic in their callbacks—token transfers, access grants, voting, or any other action. After reveal, the commitment can never be used again.

Token Privacy (Vanish/Summon)

One common use case built on Ghost Protocol is token privacy:

  • Vanish: Burn GHOST tokens in onCommit, creating a commitment
  • Summon: Mint GHOST tokens in onReveal to any recipient

This breaks the on-chain link between sender and receiver. But remember: Vanish/Summon is just one application—the core protocol works with any data.

Data Lifecycle

┌─────────────────────────────────────────────────────────────────────────────┐
│ COMMIT PHASE │
│ │
│ OFF-CHAIN (your responsibility): │
│ ├─ Generate: secret, nullifierSecret, blinding (random 32-byte values) │
│ ├─ Compute: dataHash = hash(your application data) │
│ ├─ Compute: commitment = Poseidon(Poseidon(secret, nullifierSecret), │
│ │ Poseidon(dataHash, blinding)) │
│ └─ STORE THESE VALUES. If lost, your commitment is unrecoverable. │
│ │
│ ON-CHAIN (permanent): │
│ └─ commitment is added to Merkle tree at leafIndex │
│ │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│ WAITING PHASE │
│ │
│ The commitment exists on-chain. │
│ No one can determine what was committed without the off-chain secrets. │
│ The Merkle root is updated periodically by the relayer. │
│ Your commitment becomes provable once included in a known root. │
│ │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│ REVEAL PHASE │
│ │
│ OFF-CHAIN (your responsibility): │
│ ├─ Compute: nullifier = Poseidon(Poseidon(nullifierSecret, commitment), │
│ │ leafIndex) │
│ ├─ Generate: ZK proof proving you know the secret for this commitment │
│ └─ The proof ties together: root, nullifier, dataHash, recipient │
│ │
│ ON-CHAIN (permanent): │
│ ├─ Proof is verified │
│ ├─ Nullifier is marked as SPENT (forever) │
│ └─ Application callback executes (if any) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│ TERMINAL STATE │
│ │
│ The nullifier is spent. The commitment can never be revealed again. │
│ The off-chain secrets are now useless. You can delete them. │
│ │
│ If you never revealed: the commitment exists forever, unrevealed. │
│ If you lost your secrets before revealing: the commitment is dead forever. │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

What Exists Where

DataLocationLifetimeWho Controls It
secretOff-chain onlyUntil reveal (then delete)You
nullifierSecretOff-chain onlyUntil reveal (then delete)You
blindingOff-chain onlyUntil reveal (then delete)You
dataHashOff-chain AND in proofPermanentDerived from app data
commitmentOn-chain (Merkle tree)PermanentProtocol
leafIndexOn-chain (from event)PermanentProtocol
rootOn-chain (100 most recent)Rolling windowRelayer updates
nullifierOn-chain after revealPermanent once spentProtocol
proofSubmitted at revealVerified then discardedYou generate

What Happens If...

ScenarioOutcome
You lose secret before revealPermanent loss. Commitment can never be revealed.
You lose nullifierSecret before revealPermanent loss. Cannot compute nullifier.
You lose leafIndexRecoverable. Query events or tree to find it.
Root becomes stale (>100 roots ago)Reveal fails. Wait for new root, regenerate proof.
You try to reveal twiceSecond reveal fails. Nullifier already spent.
Your app reverts in onRevealReveal transaction reverts. Nullifier NOT spent.
Permanent Loss

If you lose secret or nullifierSecret before reveal, your commitment is unrecoverable. There is no recovery mechanism. Store these values securely.

Next Steps