Airdrop Proofs: Sapling
The Sapling claim proof is a Groth16 proof adapted from the Sapling Spend circuit.
Implementation:
- Circuit:
crates/zair-sapling-circuit/ - Prover / verifier:
crates/zair-sapling-proofs/
Patched dependency:
sapling-crypto/from https://github.com/eigerco/sapling-crypto
Proof statement
For a Sapling note, the circuit proves:
- Ownership / spend-style consistency (recipient binding and public rk)
- Snapshot inclusion: the note commitment opens to the note commitment root (anchor)
- Snapshot unspentness: for the note’s private (standard) Sapling nullifier nf, the witness provides adjacent bounds (left, right) and the circuit enforces left < nf < right, plus a Merkle opening of the corresponding gap leaf to the gap-root
- Double-claim prevention: a public airdrop nullifier is derived from the same nullifier preimage, using an airdrop-specific BLAKE2s personalization
- Value binding: a public value commitment matches the note value (native cv or cv_sha256)
Public instance
The public input vector is defined by ClaimPublicInputs::to_vec in
crates/zair-sapling-proofs/src/verifier/mod.rs. The length depends on the value commitment
scheme:
-
Native: 8 BLS12-381 scalars
rk.u,rk.v: randomization keycv.u,cv.v: value commitment (native)anchor: note commitment tree roothiding_nf: airdrop nullifier (256 bits multipacked into 2 scalars)nm_anchor: spent-nullifier gap-tree root
-
SHA-256: 8 BLS12-381 scalars
rk.u,rk.v: randomization keycv_sha256: value commitment (256-bit digest multipacked into 2 scalars)anchor: note commitment tree roothiding_nf: airdrop nullifier (multipacked into 2 scalars)nm_anchor: spent-nullifier gap-tree root
The standard Zcash nullifier nf is computed in-circuit but is never a public input.
Private witness
Spend-style (reused from Sapling Spend):
ak,nsk: proof generation key, derivesrkandnkalpha(ar): randomization scalar forrkg_d: from diversifier, used to derivepk_drcv: value commitment randomnessrcm: note commitment randomnessauth_path: Merkle path toanchorvalue: note value
ZAIR-specific:
nm_left_nf,nm_right_nf: 32-byte gap boundsnm_merkle_path: gap-tree Merkle path tonm_anchor.rcv_sha256: 32-byte randomness (used only with the SHA-256 scheme)