Redemption Circuit
The redemption circuit is the primary ZK circuit in Ghost Protocol. It proves that the prover knows the preimage of a commitment in the Merkle tree and correctly derives the nullifier, all without revealing which commitment is being redeemed.
Circuit definition
template Redemption(levels) {
// Public inputs (8)
signal input root;
signal input nullifier;
signal input withdrawAmount;
signal input recipient;
signal input changeCommitment;
signal input tokenId;
signal input policyId;
signal input policyParamsHash;
// Private inputs
signal input secret;
signal input nullifierSecret;
signal input amount;
signal input blinding;
signal input pathElements[levels];
signal input pathIndices[levels];
signal input newBlinding;
}
The circuit is instantiated with levels = 20 (Merkle tree depth).
What it proves
-
Commitment preimage — The prover knows
(secret, nullifierSecret, tokenId, amount, blinding)such that:commitment = Poseidon5(secret, nullifierSecret, tokenId, amount, blinding) -
Merkle membership — The commitment exists at some leaf position in the tree with the given
root:MerkleProof(commitment, pathElements, pathIndices) == root -
Nullifier derivation — The nullifier is correctly computed:
nullifier == Poseidon2(nullifierSecret, leafIndex)where
leafIndexis derived frompathIndices. -
Amount conservation — The committed amount equals the sum of withdraw and change:
amount == withdrawAmount + changeAmountwhere
changeAmountis embedded inchangeCommitmentvianewBlinding. -
Policy binding — If
policyId != 0, verifies that the commitment includes the policy:commitment == Poseidon7(secret, nullifierSecret, tokenId, amount, blinding, policyId, policyParamsHash)
Partial reveals
The circuit supports partial reveals. If you committed 10 GHOST, you can:
- Withdraw 3 GHOST (
withdrawAmount = 3) - Create a change commitment for 7 GHOST (
changeCommitment = Poseidon5(newSecret, newNullifierSecret, tokenId, 7, newBlinding))
The change commitment is inserted into the tree and can be revealed later.
For a full reveal (no change), set changeCommitment = 0 and withdrawAmount = amount.
Gas cost
On-chain verification costs approximately 200,000 gas via the ecPairing precompile at address 0x08.