Phantom Keys
A phantom key is the sole proof of ownership for a Ghost Protocol commitment. It contains all the secret values needed to generate a ZK proof and reveal committed assets. There is no recovery mechanism, no admin override, and no account abstraction — if you lose the key, the committed assets are permanently inaccessible.
Core Principle
The key IS the proof of ownership.
A phantom key is not an access credential for a remote system. It is the cryptographic material itself. The secrets inside the key are the private inputs to the ZK circuit. Without them, it is computationally infeasible to generate a valid proof — even with unlimited access to the smart contracts and Merkle tree data.
There is no "forgot your password" flow. There is no multisig recovery. There is no admin key. This is a deliberate design choice: the same property that makes Ghost Protocol private (no on-chain link between commit and reveal) also makes phantom keys unrecoverable.
Key Formats
ghostchain-v2 (CommitRevealVault)
The standard format for token commitments through the CommitRevealVault:
{
"version": "ghostchain-v2",
"token": "0x0000000000000000000000000000000000000000",
"seed": "a1b2c3d4e5f67890a1b2c3d4e5f67890",
"secret": "1234567890abcdef...",
"nullifierSecret": "fedcba0987654321...",
"blinding": "1122334455667788...",
"amount": "1000000000000000000",
"commitment": "8765432109876543...",
"leafIndex": 42,
"tokenIdHash": "abcdef1234567890...",
"quantumSecret": "deadbeef01234567...",
"policyId": "0",
"policyParamsHash": "0",
"policyParams": ""
}
Field descriptions:
| Field | Type | Description |
|---|---|---|
version | string | Format identifier. Always "ghostchain-v2" |
token | string | Token contract address (zero address for native GHOST) |
seed | string | 16-byte random seed used during key generation (hex) |
secret | string | 31-byte random secret — primary circuit input (field element, decimal) |
nullifierSecret | string | 31-byte random secret for nullifier derivation (field element, decimal) |
blinding | string | Random blinding factor for commitment uniqueness (field element, decimal) |
amount | string | Token amount in base units (e.g., 10^18 for 1 GHOST) |
commitment | string | Poseidon7 hash of all preimage values (field element, decimal) |
leafIndex | number | Position of the commitment in the Merkle tree |
tokenIdHash | string | Poseidon2(tokenAddress, 0) (field element, decimal) |
quantumSecret | string | 32-byte quantum secret for post-quantum protection (hex). Empty string if unused |
policyId | string | Policy contract identifier (field element, decimal). "0" for no policy |
policyParamsHash | string | keccak256(policyParams) % BN254_FIELD (field element, decimal). "0" for no policy |
policyParams | string | ABI-encoded policy parameters (hex). Empty string for no policy |
open-ghost-persistent-v1 (PersistentKeyVault)
The format for persistent phantom keys, which can be accessed multiple times without spending:
{
"version": "open-ghost-persistent-v1",
"persistent": true,
"contentType": "application/json",
"encryptedSecret": "0xaabbccdd...",
"encKeyPartA": "0x11223344...",
"keyVaultId": "9876543210...",
"revokePolicy": "BEARER",
"secret": "1234567890abcdef...",
"nullifierSecret": "fedcba0987654321...",
"dataHash": "5566778899aabbcc...",
"blinding": "1122334455667788...",
"commitment": "8765432109876543...",
"leafIndex": 107,
"createdAt": "2026-01-15T08:30:00.000Z"
}
Field descriptions:
| Field | Type | Description |
|---|---|---|
version | string | Format identifier. Always "open-ghost-persistent-v1" |
persistent | boolean | Always true — distinguishes from one-time keys |
contentType | string | MIME type of the encrypted payload |
encryptedSecret | string | AES-encrypted payload (hex) |
encKeyPartA | string | First half of the AES key — stored in this file |
keyVaultId | string | On-chain identifier for the key's vault entry |
revokePolicy | string | "BEARER" or "ISSUER_ONLY" — who can revoke |
secret | string | ZK circuit secret (field element, decimal) |
nullifierSecret | string | Nullifier derivation secret (field element, decimal) |
dataHash | string | Hash of the encrypted data (field element, decimal) |
blinding | string | Blinding factor (field element, decimal) |
commitment | string | Poseidon4 hash of the preimage (field element, decimal) |
leafIndex | number | Position in the Merkle tree |
createdAt | string | ISO 8601 timestamp of key creation |
Export Formats
Phantom keys must be durably stored outside the browser. Ghost Protocol supports multiple export formats, each optimized for different use cases.
PNG Image
The primary export format. The phantom key JSON is embedded in the PNG file's metadata using steganographic encoding:
┌──────────────────────────────────┐
│ │
│ Visual card design │
│ (amount, token, timestamp) │
│ │
│ ┌────────────────────────────┐ │
│ │ Embedded metadata: │ │
│ │ - Full phantom key JSON │ │
│ │ - Key version │ │
│ │ - Integrity checksum │ │
│ └────────────────────────────┘ │
│ │
└──────────────────────────────────┘
Properties:
- File appears as a normal image — does not look like a cryptographic key
- Can be saved to camera roll, AirDrop, cloud storage
- Integrity checksum verifies the key has not been corrupted
- The import flow reads the embedded metadata from the PNG to reconstruct the key
PDF Voucher
A printable document containing the phantom key as both human-readable data and machine-readable QR codes:
- Full phantom key JSON encoded as a QR code
- Human-readable fields: amount, token, commitment (truncated), creation date
- Instructions for redemption
- Suitable for physical distribution (gift cards, paper wallets)
QR Code
A standalone QR code encoding the phantom key JSON:
- Used for screen-to-screen transfers
- Displayed temporarily in the app for scanning
- Not recommended for long-term storage (no visual context, easy to confuse with other QR codes)
NFC (NTAG 424 DNA)
Phantom keys can be written to NFC hardware cards using the NTAG 424 DNA chip:
┌─────────────────────────────┐
│ NTAG 424 DNA Card │
│ │
│ NDEF Record: │
│ ├── Type: application/json│
│ ├── Payload: phantom key │
│ └── SUN authentication │
│ │
│ Hardware features: │
│ ├── Tamper detection │
│ ├── AES-128 encryption │
│ ├── Rolling SUN counter │
│ └── One-tap NFC read │
│ │
└─────────────────────────────┘
NTAG 424 DNA features:
| Feature | Description |
|---|---|
| SUN (Secure Unique NFC) | Each tap generates a unique authentication code, preventing relay attacks |
| AES-128 | On-chip encryption protects the stored key data |
| Tap counter | Monotonic counter increments on each read — detects cloning attempts |
| Tamper detect | Physical tamper loop can detect if the card has been opened |
NFC cards turn phantom keys into physical bearer instruments — the person holding the card can reveal the committed assets by tapping their phone.
Numeric Code
A human-typeable representation of the phantom key, designed for phone dictation or manual entry:
Format: XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX
└──────────── V4 with quantum secret ────────────┘
The V4 numeric format includes the quantum secret, ensuring that manually entered keys retain full quantum protection. The code uses a restricted character set (digits only) with checksum segments for error detection.
Security Properties
No Recovery
| Scenario | Outcome |
|---|---|
| Lost phantom key (all copies) | Assets permanently locked — no one can generate the ZK proof |
| Corrupted phantom key | Assets permanently locked — incorrect secrets produce invalid proofs |
| Stolen phantom key | Thief can reveal the assets — the key is the only authentication |
| Copied phantom key | First to reveal wins — nullifier prevents second reveal |
| Forgotten password | N/A — phantom keys are not password-protected by default |
Bearer Property
Phantom keys are bearer instruments. Whoever possesses the key can reveal the assets. This is analogous to physical cash:
- Possession = ownership. There is no identity verification, no KYC check, no wallet signature required at reveal time. The ZK proof itself is the authentication.
- Transferability. Sending someone a phantom key (via AirDrop, email, NFC tap) transfers the ability to reveal. This is how Ghost Protocol enables cash-like digital assets.
- Risk. If a key is intercepted, the interceptor can reveal before the intended recipient. For high-value transfers, policies (e.g.,
DestinationRestriction) can mitigate this risk.
Commitment Binding
The phantom key is cryptographically bound to its commitment. Every field in the key is either a direct input to the Poseidon hash or derived from one:
commitment = Poseidon7(
key.secret,
key.nullifierSecret,
key.tokenIdHash, ← derived from key.token
key.amount,
key.blinding,
key.policyId,
key.policyParamsHash
)
If any field is modified, the resulting commitment will not match the on-chain commitment, and the Merkle proof will fail. Phantom keys cannot be forged or tampered with.
Key Lifecycle
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Generate │───►│ Export │───►│ Store │───►│ Import │
│ │ │ │ │ │ │ │
│ secrets │ │ PNG/PDF/ │ │ camera │ │ scan/ │
│ compute │ │ QR/NFC/ │ │ roll, │ │ upload/ │
│ commit │ │ numeric │ │ cloud, │ │ tap NFC │
└──────────┘ └──────────┘ │ NFC card │ └────┬─────┘
└──────────┘ │
▼
┌──────────┐
│ Reveal │
│ │
│ generate │
│ ZK proof │
│ submit │
└──────────┘
- Generate: Random secrets are generated client-side. The commitment is computed. The phantom key JSON is assembled.
- Export: The key is rendered into one or more export formats (PNG, PDF, QR, NFC, numeric).
- Store: The user saves the exported key. This is the critical step — the key must survive browser closure.
- Import: When ready to reveal, the user imports the key by scanning, uploading, or tapping.
- Reveal: The imported key provides all the private inputs needed to generate the ZK proof and submit the reveal transaction.