Appendix A: Cryptographic Proofs
This appendix provides the full cryptographic specifications underlying the Specter Protocol's Ghost Protocol primitive. It covers hash constructions, field arithmetic, proof systems, circuit definitions, nullifier derivation, and the quantum-safe commitment layer.
Poseidon Hash Family
Specter uses the Poseidon algebraic hash function family, chosen for its efficiency inside arithmetic circuits over prime fields. Three width variants are employed, each matched to a specific data shape.
Poseidon2 (2 inputs)
Used wherever exactly two field elements must be compressed:
- Merkle tree nodes — hashing left and right children at each level.
- Nullifier derivation — combining secrets with commitment data (see Nullifier Derivation).
- Access tags — binding a nullifier secret to a session nonce.
- Token ID computation — domain-separated hashing of token identifiers.
Poseidon4 (4 inputs)
Used for data commitments and Open Ghost commitments:
commitment = Poseidon4(secret, nullifierSecret, dataHash, blinding)
This construction binds the owner's secret, an independent nullifier secret, the hash of the protected data, and a random blinding factor into a single hiding, binding commitment.
Poseidon7 (7 inputs)
Used for token commitments in the Ghost Protocol:
commitment = Poseidon7(secret, nullifierSecret, tokenId, amount, blinding, policyId, policyParamsHash)
This extended preimage binds the full token metadata — denomination, quantity, and policy parameters — into the commitment, enabling the redemption circuit to enforce amount conservation and policy compliance without revealing any field.
On-Chain Deployment
Only PoseidonT3 (the 2-input variant with a width-3 internal state) is deployed on-chain, costing approximately 30,000 gas per invocation. The larger variants (Poseidon4, Poseidon7) are computed exclusively off-chain during witness generation; the circuit proves correctness of those evaluations without replaying them in the EVM.
Field Arithmetic
BN254 Scalar Field
All circuit arithmetic operates over the BN254 scalar field:
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
This is an approximately 254-bit prime. Every value entering or leaving a Groth16 circuit — public inputs, private witnesses, hash outputs — must be an element of F_p.
keccak256 Reduction
When keccak256 digests (256 bits) are used as circuit inputs (for example, the quantum commitment layer), the raw output is reduced modulo p:
circuitValue = keccak256(preimage) mod p
Because p is close to 2^254, the resulting distribution over F_p has negligible bias (< 2^-128).
Groth16 Proof System
Specter uses the Groth16 zero-knowledge succinct non-interactive argument of knowledge (zk-SNARK) instantiated over the BN254 curve.
| Property | Value |
|---|---|
| Proof size | 256 bytes (constant) |
| On-chain verification gas | ~220,000 |
| Pairing curve | BN254 (alt_bn128) |
| Pairing precompile | EIP-197 |
| Trusted setup | Per-circuit ceremony |
Verification uses the EIP-197 precompiled contract for optimal ate pairing checks, available on Ethereum and EVM-compatible chains including Specter's own execution layer.
Circuit Specifications
GhostRedemption Circuit
The redemption circuit proves that a party can legitimately withdraw tokens from the Ghost Protocol without revealing the source commitment, the full amount, or any identifying information.
Public inputs (8 field elements):
| Index | Name | Description |
|---|---|---|
| 0 | root | Merkle tree root at the time of proof generation |
| 1 | nullifier | Unique nullifier preventing double-spend |
| 2 | withdrawAmount | Amount being withdrawn |
| 3 | recipient | Address receiving the withdrawal |
| 4 | changeCommitment | New commitment for any remaining balance |
| 5 | tokenId | Identifier of the token being redeemed |
| 6 | policyId | Reveal policy contract address (as field element) |
| 7 | policyParamsHash | Hash of the policy parameters bound at commit time |
Constraints enforced (via quadratic R1CS):
- Knowledge of preimage — The prover knows
(secret, nullifierSecret, tokenId, amount, blinding, policyId, policyParamsHash)such thatPoseidon7(...)equals the committed leaf. - Merkle membership — The commitment is a leaf of the Merkle tree with the declared
root, verified through a 20-level authentication path. - Nullifier correctness — The declared
nullifierequals the deterministic derivation from the commitment's nullifier secret and leaf index (see Nullifier Derivation). - Amount conservation —
withdrawAmount + changeAmount == amount, wherechangeAmountis the balance locked intochangeCommitment. - Change commitment validity —
changeCommitmentis a well-formed Poseidon7 commitment over the change amount and fresh blinding, bound to the same token ID and policy. - Policy binding — The
policyIdandpolicyParamsHashin the proof match those embedded in the original commitment, ensuring the reveal policy cannot be altered after deposit.
Access Proof Circuit
The access proof circuit enables a commitment holder to prove they control a specific data commitment and to derive a session-bound access tag, without revealing any secret material.
Public inputs (4 field elements):
| Index | Name | Description |
|---|---|---|
| 0 | root | Merkle tree root |
| 1 | dataHash | Hash of the data being accessed |
| 2 | sessionNonce | Unique nonce for this access session |
| 3 | accessTag | Derived tag proving control |
Constraints enforced:
- Knowledge of Poseidon4 preimage — The prover knows
(secret, nullifierSecret, dataHash, blinding)such thatPoseidon4(...)equals a committed leaf. - Merkle membership — The commitment exists in the tree under the declared
root, verified through 20 levels. - Access tag correctness —
accessTag = Poseidon2(nullifierSecret, sessionNonce). This binds the proof to a specific session while revealing nothing about the underlying secret or nullifier secret.
Nullifier Derivation
Nullifiers prevent double-spending. Specter derives them deterministically from the commitment's nullifier secret and its position in the Merkle tree:
nullifier = Poseidon2(Poseidon2(nullifierSecret, commitment), leafIndex)
Properties:
- Deterministic — The same commitment at the same leaf index always produces the same nullifier, so the on-chain NullifierRegistry can detect replays.
- Unlinkable — Without knowledge of
nullifierSecret, an observer cannot link a nullifier to its source commitment. - Leaf-index binding — Including
leafIndexprevents nullifier collisions if the same commitment value appears at multiple tree positions.
Quantum-Safe Commitment Layer
Specter includes a commit-reveal scheme that provides defense-in-depth against future quantum adversaries.
Commit Phase
At deposit time, the user generates a random quantumSecret and publishes:
quantumCommitment = keccak256(quantumSecret)
This value is stored alongside the Poseidon commitment in the on-chain vault.
Reveal Phase
At redemption time, the user reveals quantumSecret in the clear. The contract verifies:
keccak256(quantumSecret) == storedQuantumCommitment
Security Argument
The keccak256 hash function has 256-bit output. Under Grover's algorithm, a quantum adversary requires approximately 2^128 oracle calls to find a preimage — a workload that remains computationally infeasible even with fault-tolerant quantum hardware. This layer ensures that even if the BN254 discrete-log problem is broken by a future quantum computer, an attacker still cannot forge a valid reveal without the original quantum secret.