Skip to main content

Access Proof Circuit

The access proof circuit proves knowledge of a commitment's preimage without consuming it. Unlike the redemption circuit, it does not compute a nullifier, so the same commitment can be accessed multiple times. This powers the Persistent Phantom Keys system.

Circuit definition

template AccessProof(levels) {
// Public inputs (4)
signal input root;
signal input dataHash;
signal input sessionNonce;
signal input accessTag;

// Private inputs
signal input secret;
signal input nullifierSecret;
signal input blinding;
signal input pathElements[levels];
signal input pathIndices[levels];
}

What it proves

  1. Commitment preimage — The prover knows (secret, nullifierSecret, blinding) such that:

    commitment = Poseidon5(secret, nullifierSecret, tokenId, amount, blinding)
  2. Merkle membership — The commitment exists in the tree with the given root.

  3. Access tag derivation — The access tag is correctly computed:

    accessTag == Poseidon2(nullifierSecret, sessionNonce)

Public inputs

IndexFieldDescription
0rootMerkle tree root
1dataHashHash of the sealed data being accessed
2sessionNonceRandom nonce for this session
3accessTagDerived tag for anti-replay protection

Key differences from redemption circuit

PropertyRedemptionAccess Proof
Computes nullifierYesNo
Consumes commitmentYes (nullifier registered)No (reusable)
Public inputs84
Use caseToken revealsData access, persistent keys
Anti-replayNullifier (permanent)Access tag (session-scoped)

Use cases

  • Persistent Phantom Keys — Prove you own a key stored in the tree without revealing or consuming it
  • Encrypted data access — Prove authorization to access sealed data
  • Identity verification — Prove knowledge of a credential commitment without exposing it
  • Session-based authentication — The sessionNonce ensures proofs are bound to specific sessions

Access tag

The access tag serves as a session-scoped anti-replay mechanism:

accessTag = Poseidon2(nullifierSecret, sessionNonce)

Since nullifierSecret is private, different sessions produce different tags. An observer cannot link access tags across sessions.