Transactions
In IronFish, each transaction has 0 or more Spend Descriptions
and 0 or more Output Descriptions
. Every transaction uses zk-SNARK (groth16) Sapling proof both on the Spend and Output description. The circuit construction for these proofs is taken from Sapling primitive gadgets which in turn were constructed using the bellman circuit building tool.
As with any zk-SNARK based system, there are hardcoded parameters that are a result of a trusted setup. In order to generate the Spend Description proof and the Output Description proof one needs access to the appropriate proving key, and the verifier needs access to the appropriate verifying key. These will be generated using a multi party computation to allow as many participants as possible to contribute randomness and ensure the system is sound. Those parameters will be specified here at a later time.
While explaining zk-SNARKs is outside the scope of this paper, for readers who want to learn more, I recommend this excellent tutorial by Maksym Petkus.
The transaction, in plaintext, has the numerical difference between inputs(spends) and outputs which is the transaction fee.
Spend Description
The full format of the Spend Description:
Element | Description |
---|---|
value commitment | |
root anchor – which Merkle root is used for the proof | |
nullifier for the note | |
randomized public key for the authorization key (ak) (private key of the randomized ak): rk is the public key for the randomized authorized key private key | |
sign hash of the spend description using rsk | |
zk-SNARK proof that allows one to hide the private values needed to validate |
Private variables for proof generation:
Element | Description |
---|---|
the Merkle path to the commitment note being spent | |
the position of the commitment note (e.g. index) | |
the diversifier of the public address owning this note | |
the transmission key of the owner | |
value of the note | |
randomness used in the Pedersen Hash for value commitment | |
note commitment of the note being spent | |
the randomness used in the Pedersen Hash for note commitment | |
alpha used to hide the authorization key that signs the spend | |
the owner’s authorization key (that was randomized) | |
the proof authorization key used for the nullifier |
Public variables for verification:
Element | Description |
---|---|
root anchor that was used for the Merkle path in the proof | |
Pedersen Hash (commitment) of the value | |
nullifier to spend the note | |
the randomized authorization public key |
Note Commitment integrity
- Check that the note commitment
(cm)
is derived from , , , and (randomness for the Pedersen Hash)
- Check that the note commitment
Merkle Path Validity
- Check that the Merkle path is valid from the given merkle root to the leaf
Value Commitment
- Check that the value commitment
(cv)
was indeed constructed as
- Check that the value commitment
Nullifier
- Check that the nullifier is derived from
ivk
(the owner’s incoming view key), thecm
(note commitment) andposition
(the index in the Merkle tree on the lowest level)
- Check that the nullifier is derived from
Random Authorization Key
- Check that the random authorization key
(rsk)
that is used to sign theSpend Description
is correctly derived from the spend authorization key and the providedα
. This is so that no spend transactions can ever be linked by signatures using the same key
- Check that the random authorization key
It is important to note that it is necessary to know which notes are spendable and the Merkle Path to them. Logistically, this means that a user or a wallet has to:
- Continuously scan for new notes created and try brute force.
- Be able to create (or otherwise acquire) a valid Merkle Path from the root to the leaf note being spent. This Merkle root must be one that was previously seen by a miner or validator.
Output Description
The full format of the Output Description:
Element | Description |
---|---|
value commitment | |
note commitment | |
ephemeral public key | |
encrypted plaintext of the note | |
ephemeral public key | |
zk-SNARK proof that allows one to hide the private values needed to validate |
Public variables for verification:
Element | Description |
---|---|
value commitment | |
note commitment | |
ephemeral public key |
Private variables for proof generation:
Element | Description |
---|---|
recipient’s diversifier | |
public diversifier address for the recipient | |
value | |
randomness for the value | |
randomness for the note commitment | |
ephemeral private key |
From every Output Description, we create a Merkle Tree Note that consists of:
Element | Description |
---|---|
value commitment | |
note commitment | |
ephemeral public key | |
encrypted plaintext of the note | |
allows the holder of the viewing key to decrypt a decryption key for |
What happens during the Output Description proof generation?
- Value commitment
(cv)
is created correctly using ephemeral randomness(rcv)
- Note commitment
(cm)
is created correctly using the supplied randomness for the note commitment(rcm)
- The ephemeral public key
(epk)
is created correctly given then ephemeral secret key(esk)
for note encryption/decryption - And that the diversifier for the recipient’s public key is a valid one
Transaction Balancing
Both the Spend and Output Description contain a value commitment
which is in a form of a Pedersen commitment where and are known generator points on the Jubjub curve, is the plaintext value of the note, and is the randomness.
The transaction fee is known (plaintext) without ever revealing the plaintext values for any of the value commitments. The transaction also commits to the randomness of every note. Therefore, to check that a transaction committed to a valid transaction fee, we can check that
Verifying transaction fee matches value commitments of the notes:
Transaction Verification
Transaction verification is a process of a miner or a validator performing a series of checks:
- Validate that all the merkle root hashes for each
Spend Description
are ones that have (at some point in the past) been valid merkle roots for the global merkle note tree - Validate all the
Spend Description
proofs inside that transaction against its public parameters - Validate all the
Output Description
proofs inside that transaction against its public parameters