Spend Descriptions
Each spend contains an SpendBody and a zk-SNARK spend proof.
Spend zk-SNARK Statements
The spend proof demonstrates the properties enumerated below for the following private witnesses known by the prover:
- Note amount (interpreted as an ) and asset
ID
- Note blinding factor used to blind the note commitment
- Address associated with the note being spent, consisting of diversified basepoint , transmission key , and clue key
- Note commitment
- Blinding factor used to blind the balance commitment
- Spend authorization randomizer used for generating the randomized spend authorization key
- Spend authorization key
- Nullifier deriving key
- Merkle proof of inclusion for the note commitment, consisting of a position
pos
and an authentication path consisting of 72 elements (3 siblings each per 24 levels)
And the corresponding public inputs:
- Merkle anchor of the state commitment tree
- Balance commitment to the value balance
- Nullifier of the note to be spent
- Randomized verification key
Dummy spend
We require each one of the following integrity properties to hold only for notes with non-zero values . This is to allow for dummy spends to pass stateless verification. Dummy spends may be added for metadata resistance (e.g. to ensure there are two spends and two outputs in each transaction).
Note Commitment Integrity
The zk-SNARK certifies that for non-zero values , the note commitment was derived as:
.
using the above witnessed values and where ds
is a constant domain separator:
ds = from_le_bytes(BLAKE2b-512(b"penumbra.notecommit")) mod q
Balance Commitment Integrity
The zk-SNARK certifies that for non-zero values , the public input balance commitment was derived from the witnessed values as:
where is a constant generator and is an asset-specific generator point derived as described in Value Commitments.
Nullifier Integrity
The zk-SNARK certifies that for non-zero values , the revealed nullifier was derived as:
using the witnessed values above and where ds
is a constant domain separator:
ds = from_le_bytes(BLAKE2b-512(b"penumbra.nullifier")) mod q
as described in Nullifiers.
Diversified address Integrity
The zk-SNARK certifies that for non-zero values , the diversified address associated with the note being spent was derived as:
where is the witnessed diversified basepoint and is the incoming viewing key computed using a rate-2 Poseidon hash from the witnessed and as:
ivk = hash_2(from_le_bytes(b"penumbra.derive.ivk"), nk, decaf377_s(ak)) mod r
as described in Viewing Keys.
Randomized verification key Integrity
The zk-SNARK certifies that for non-zero values , the randomized verification key was derived using the witnessed and spend auth randomizer as:
where is the conventional decaf377
basepoint as described in The Decaf377 Group.
Merkle auth path verification
The zk-SNARK certifies that for non-zero values1 , the witnessed Merkle authentication path is a valid Merkle path to the provided public anchor.
Diversified Base is not Identity
The zk-SNARK certifies that for non-zero values , the diversified basepoint associated with the address on the note is not identity.
The spend authorization key is not Identity
The zk-SNARK certifies that for non-zero values , the spend authorization key is not identity.
Note that issue 2135 tracks a bug where dummy spends fail to verify due to the merkle paths.