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
-
Commitment preimage — The prover knows
(secret, nullifierSecret, blinding)such that:commitment = Poseidon5(secret, nullifierSecret, tokenId, amount, blinding) -
Merkle membership — The commitment exists in the tree with the given
root. -
Access tag derivation — The access tag is correctly computed:
accessTag == Poseidon2(nullifierSecret, sessionNonce)
Public inputs
| Index | Field | Description |
|---|---|---|
| 0 | root | Merkle tree root |
| 1 | dataHash | Hash of the sealed data being accessed |
| 2 | sessionNonce | Random nonce for this session |
| 3 | accessTag | Derived tag for anti-replay protection |
Key differences from redemption circuit
| Property | Redemption | Access Proof |
|---|---|---|
| Computes nullifier | Yes | No |
| Consumes commitment | Yes (nullifier registered) | No (reusable) |
| Public inputs | 8 | 4 |
| Use case | Token reveals | Data access, persistent keys |
| Anti-replay | Nullifier (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
sessionNonceensures 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.