Skip to main content

Circuit Inputs & Outputs

Complete reference for all inputs and outputs of both ZK circuits.

Redemption circuit

Public inputs (8)

IndexNameTypeDescription
0rootFieldMerkle tree root the proof is generated against
1nullifierFieldDerived nullifier = Poseidon2(nullifierSecret, leafIndex)
2withdrawAmountuint256Amount being withdrawn (in aghost)
3recipientaddress (as Field)Address receiving the minted tokens
4changeCommitmentFieldPoseidon hash of the change commitment (0 for full reveal)
5tokenIdFieldToken identifier = keccak256(tokenAddress) % p
6policyIdaddress (as Field)Policy contract address (0 if no policy)
7policyParamsHashFieldPoseidon hash of policy parameters (0 if no policy)

Private inputs

NameTypeDescription
secretFieldUser's private key for this commitment
nullifierSecretFieldUsed to derive the nullifier
amountuint256Full committed amount
blindingFieldRandom blinding factor
pathElements[20]Field[20]Merkle proof sibling hashes
pathIndices[20]bit[20]Merkle proof path directions (0=left, 1=right)
newBlindingFieldBlinding factor for the change commitment

Constraints verified

1. commitment = Poseidon5(secret, nullifierSecret, tokenId, amount, blinding)
2. MerkleProof(commitment, pathElements, pathIndices) == root
3. leafIndex = binaryToDecimal(pathIndices)
4. nullifier == Poseidon2(nullifierSecret, leafIndex)
5. amount == withdrawAmount + changeAmount
6. If changeAmount > 0: changeCommitment == Poseidon5(secret, newNullifierSecret, tokenId, changeAmount, newBlinding)
7. If policyId != 0: commitment includes policyId and policyParamsHash

Access proof circuit

Public inputs (4)

IndexNameTypeDescription
0rootFieldMerkle tree root
1dataHashFieldHash of the sealed data being accessed
2sessionNonceFieldRandom nonce for this session
3accessTagFieldPoseidon2(nullifierSecret, sessionNonce)

Private inputs

NameTypeDescription
secretFieldUser's private key
nullifierSecretFieldUsed to derive the access tag
blindingFieldBlinding factor
pathElements[20]Field[20]Merkle proof sibling hashes
pathIndices[20]bit[20]Merkle proof path directions

Constraints verified

1. commitment = Poseidon5(secret, nullifierSecret, tokenId, amount, blinding)
2. MerkleProof(commitment, pathElements, pathIndices) == root
3. accessTag == Poseidon2(nullifierSecret, sessionNonce)

Field modulus

All field elements must be less than the BN254 scalar field modulus:

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617

This is approximately 22542^{254}. Values that exceed this modulus will wrap around, producing invalid proofs.

Computing the leaf index

The leaf index is derived from the pathIndices array (binary encoding):

leafIndex = pathIndices[0] * 2^0 + pathIndices[1] * 2^1 + ... + pathIndices[19] * 2^19

This index determines the nullifier value through Poseidon2(nullifierSecret, leafIndex).