Data Types and Commitment Variants
The Ghost Protocol supports multiple commitment structures, each optimized for a different class of data. All variants share the same underlying Poseidon hash function and the same Merkle tree infrastructure. They differ in the number and semantics of their inputs, which determines what properties the ZK proof can attest to.
This page describes the three commitment variants — Open Ghost, Token, and Access Proof — and shows how different real-world data types map to them.
Commitment Variant 1: Open Ghost (4-Input)
The Open Ghost commitment is the general-purpose variant. It commits to an arbitrary data hash with no assumptions about the data's structure or semantics.
| Input | Description |
|---|---|
secret | Random value known only to the committer. Required for proof generation. |
nullifierSecret | Random value used to derive the nullifier. Separate from secret to allow delegation of reveal rights without compromising the secret. |
dataHash | Poseidon(data) — the hash of the actual payload. Can be the hash of a credential, an image, an API key, an encryption key, or any other data. |
blinding | Random blinding factor that ensures two commitments to the same data produce different commitment values. Prevents deduplication attacks. |
The dataHash field is the protocol's point of extensibility. Because dataHash is simply the Poseidon hash of arbitrary data, the Open Ghost commitment can encode anything. The protocol does not interpret dataHash — it only verifies that the prover knows a preimage of the commitment that includes this hash.
Reveal Public Inputs
When an Open Ghost commitment is revealed, the ZK proof exposes:
| Public Input | Purpose |
|---|---|
root | The Merkle tree root at the time of proof generation. Verifier checks this is a recognized root. |
nullifierHash | Poseidon(nullifierSecret, leafIndex) — recorded on-chain to prevent double-reveal. |
dataHash | The hash of the underlying data. Allows the verifier or receiving contract to act on the data type without seeing the plaintext. |
accessTag | An optional tag binding the proof to a specific context (session, contract, purpose). Prevents proof reuse across contexts. |
Commitment Variant 2: Token (7-Input)
The Token commitment extends the Open Ghost structure with fields specific to fungible and non-fungible token operations. It encodes the token identity, amount, and policy bindings directly in the commitment.
| Input | Description |
|---|---|
secret | Random value known only to the committer. |
nullifierSecret | Random value for nullifier derivation. |
tokenId | Identifier for the token type (e.g., GHOST native token, an ERC-20 equivalent, or an NFT identifier). |
amount | The quantity of tokens committed. Encoded as a field element. For NFTs, this is 1. |
blinding | Random blinding factor. |
policyId | Identifier for the policy bound to this commitment (e.g., timelock, destination restriction). Zero if no policy. |
policyParamsHash | Poseidon(policyParams) — hash of the policy parameters. Allows the circuit to verify policy compliance without revealing the full policy. |
The additional inputs allow the ZK circuit to verify token-specific properties:
- The amount revealed matches the amount committed (no inflation)
- The token ID matches (no type substitution)
- The policy conditions are satisfied (timelock has elapsed, destination is approved, threshold is met)
Reveal Public Inputs
| Public Input | Purpose |
|---|---|
root | Recognized Merkle root. |
nullifierHash | Prevents double-spending. |
recipient | The address that will receive the minted tokens. |
amount | The token quantity to mint. Verified in-circuit to match the committed amount. |
Commitment Variant 3: Access Proof (4 Public Inputs)
The Access Proof variant is designed for non-consumptive data access — proving knowledge of committed data without spending the commitment. Unlike the Open Ghost and Token variants, an Access Proof does not record a nullifier. The commitment remains in the Merkle tree and can be proven against repeatedly.
This variant is used for persistent credentials, ongoing access rights, and any scenario where the user needs to prove the same fact multiple times.
Public Inputs
| Public Input | Purpose |
|---|---|
root | Recognized Merkle root. |
dataHash | The data hash being proven. Allows the verifier to check what type of data the prover claims to hold. |
sessionNonce | A nonce binding the proof to a specific session or time window. Prevents proof replay across sessions while allowing repeated use within a session. |
accessTag | A tag binding the proof to a specific verifier, contract, or purpose. Prevents a proof generated for one context from being used in another. |
Differences from Consumptive Reveals
| Property | Open Ghost / Token (Consumptive) | Access Proof (Non-Consumptive) |
|---|---|---|
| Nullifier recorded | Yes — commitment can only be revealed once | No — commitment can be proven repeatedly |
| Commitment consumed | Yes — after reveal, the commitment is "spent" | No — commitment remains active in the tree |
| Use case | One-time redemption (tokens, bearer instruments) | Ongoing access (credentials, subscriptions, identity) |
| Replay protection | Nullifier registry | Session nonce + access tag |
| Supply effect (tokens) | Burns on commit, mints on reveal | No supply effect — proof only |
Data Type Mapping
The following table shows how different real-world data types map to the commitment variants, circuits, and retrieval modes.
| Data Type | Commitment Variant | Commitment Inputs | Vault | Circuit | Retrieval Mode |
|---|---|---|---|---|---|
| Credentials | Open Ghost (4-input) | secret, nullifierSecret, Poseidon(credential), blinding | General Merkle tree | Open Ghost circuit or Access Proof circuit | Access Proof (non-consumptive) — prove credential repeatedly |
| Images | Open Ghost (4-input) | secret, nullifierSecret, Poseidon(imageHash), blinding | General Merkle tree | Open Ghost circuit | Consumptive (provenance claim) or Access Proof (ongoing proof) |
| API Keys | Open Ghost (4-input) | secret, nullifierSecret, Poseidon(apiKey), blinding | General Merkle tree | Open Ghost circuit | Consumptive — key rotation spends old commitment, creates new |
| Encryption Keys | Open Ghost (4-input) | secret, nullifierSecret, Poseidon(pubKey), blinding | General Merkle tree | Access Proof circuit | Access Proof — prove key ownership without revealing key |
| Tokens (GHOST) | Token (7-input) | secret, nullifierSecret, tokenId, amount, blinding, policyId, policyParamsHash | Token Merkle tree | Token redemption circuit | Consumptive — burn on Vanish, mint on Summon |
| Bearer Instruments | Open Ghost (4-input) | secret, nullifierSecret, Poseidon(instrument), blinding | General Merkle tree | Open Ghost circuit | Consumptive — single-use redemption via nullifier |
Vault Separation
The protocol maintains separate Merkle trees (vaults) for different commitment types:
- General Merkle tree: Stores Open Ghost commitments for all non-token data types. Shared across credentials, images, keys, and other generic data.
- Token Merkle tree: Stores Token commitments. Separated to allow independent scaling and to isolate the token supply accounting from general data operations.
Both trees use the same depth (20 levels, supporting approximately 1 million entries each), the same Poseidon hash function, and the same proof verification infrastructure. The separation is a logical choice for operational clarity, not a cryptographic necessity.
Extensibility
Adding support for a new data type requires:
- Define the data hash computation: Specify how the new data type is hashed into a
dataHashfield element. For simple data, this isPoseidon(data). For structured data, it may bePoseidon(field1, field2, ..., fieldN). - Choose a commitment variant: Open Ghost (4-input) for most data types. Token (7-input) only if the data has an amount, identity, and policy binding.
- Choose a retrieval mode: Consumptive (one-time reveal with nullifier) or non-consumptive (repeated access proofs with session nonces).
- Implement application logic: Write the smart contract or module that interprets the revealed
dataHashand takes the appropriate action.
No changes to the ZK circuits are required for new data types that fit within existing commitment structures. The Poseidon hash accepts arbitrary field elements, and the Merkle tree stores arbitrary commitments. The protocol is extensible at the application layer without modifying the cryptographic layer.
Example: Adding a New Data Type
Suppose an application wants to commit signed documents to the Ghost Protocol.
- Data hash:
dataHash = Poseidon(documentHash, signerPubKeyHash, timestamp) - Commitment variant: Open Ghost (4-input)
- Retrieval mode: Access Proof (non-consumptive) — the signer wants to prove the document exists and was signed by them, repeatedly, without consuming the commitment.
- Application logic: A verifier contract checks the revealed
dataHashagainst a registry of accepted document formats and signer public keys.
The ZK circuit does not change. The Merkle tree does not change. Only the application-layer interpretation of dataHash is new. This is the power of a data-agnostic commitment protocol.