Validity Predicates when executed by Taiga will be run in a crafted runtime environment, which will be passed to the VP in the form of public and private inputs. This section outlines a preliminary design for the VP runtime environment.
In the current Taiga design, every partial transaction has exactly two input notes and two output notes. Data of these notes constitutes the primary bulk of the runtime environment. Since these values are all inputs to the cicuit, they must be encoded as an element of field
Name | Description |
---|---|
spend_note_1_nullifier |
Spend Note #1 Nullifier |
spend_note_2_nullifier |
Spend Note #2 Nullifier |
output_note_1_commitment |
Output Note #1 Commitment (Hash) |
output_note_2_commitment |
Output Note #2 Commitment (Hash) |
owned_note_indicator |
Equals to one of the nullifiers or one of the commitments, points to the note owned by the currently executing VP (i.e., app_vk of the corresponding note refers to this VP). See this and this for details. |
Generally, the note commitment is a point on a curve (see the spec), so it's a 2-element vector output_note_<#>_commitment
is just the
Note that owned_note_indicator
only can point to one note, however, it is possible that there are more then one note in a ptx that have the current VP as their AppVP. In such case, the VP will be executed (proven) several times, once per every note that belongs to it. A future consideration: can this be optimized/improved?
If the note owned by the VP is an output note, then we supply a verifiable encryption of this note as public inputs. TODO: do we supply the encryption key as a private input? If the owned note is an input note, these fields are unused but should still be supplied to the VP (with whatever values). TODO: when unused, these can probably be used as additional custom public inputs?
Name | Description |
---|---|
own_output_note_app_vk |
Encryption of the VP verifying key |
own_output_note_app_data_static |
Encryption of the app_data_static commitment? |
own_output_note_app_data_dynamic |
Encryption of the app_data_dynamic commitment? |
own_output_note_value |
Encryption of the note value field |
own_output_note_rho |
Encryption of the note rho field |
own_output_note_nk |
Encryption of the nullifier key commitment |
own_output_note_psi |
Encryption of the note psi field |
own_output_note_rcm |
Encryption of the note commitment randomness |
We also allow VPs to have custom public inputs. Unlike the custom private inputs (see below), the number of custom public inputs is fixed at 10. This is done to ensure function privacy (so that different VPs can't be distinguished by the number of public inputs), but the concrete number can change in the future.
Name | Description |
---|---|
public_input_ |
Public input number #X, from 1 to 10 |
Private inputs consist of four sets of note info. In the table below <type>
is a stand-in for either spend
or output
; <#>
is a stand-in for note id, either 1
or 2
.
Name | Description |
---|---|
<type>_note_<#>_app_data_static_commitment |
Hash (commitment) of app_data_static field |
<type>_note_<#>_app_data_static_ |
Actual static app data. This is represented as |
<type>_note_<#>_app_vk |
Hash (commitment) of the VP verifying key, uniquely identifies the VP |
<type>_note_<#>_app_data_dynamic_commitment |
Hash of app_data_dynamic field |
<type>_note_<#>_app_data_dynamic_ |
Actual dynamic app data. This is represented as |
<type>_note_<#>_value |
Number representing the value of the note |
<type>_note_<#>_nullifier_key |
A key used to derive the nullifier |
<type>_note_<#>_rho |
|
<type>_note_<#>_psi |
|
<type>_note_<#>_rcm |
Note commitment randomness, ensures that similar notes have different commitments |
<type>_note_<#>_is_merkle_checked |
1 if this is a real note, 0 if it's a dummy/ephemeral note |
Also, for the output notes we have an additional private input output_note_<#>_nullifier
; for input notes we have an additional private parameter input_note_<#>_commitment
.
If the owned note in the partial transaction is an output note, then we supply the VP with a verifiable encryption of that output note. In order to be able to verify the encryption, the VP needs the receiver's public key and the sender's private key, which are used to ferive the note encryption key using DH key exchange. The receiver's public key should be stored in the note's dynamic data (TODO: does it always have to? are there any downsides to this?). The sender's private key (recommended to be an ephemeral key only used once, but that is up to sender) is supplied as a private input.
Name | Description |
---|---|
own_output_note_encryption_sender_key |
Sender's key used for DH key derivation together with the receiver's public key |
In the lifecycle of a partial transaction, in a typical interaction, the validity predicates are proved through the Taiga APIs exposed to the wallet. Typically, to construct and prove the ptx, the user would use their wallet application to interact with the Web3 application, which would then help the wallet to construct the ptx with all the right input and output notes.
Validity predicates may have additional custom private inputs, that are not in the list of standard inputs. These inputs can be anything that the developers decide them to be. It is the job of the Web3 application, which typically would be written by the same developers as the VP, to properly construct the partial transaction with the custom inputs.
The names of the custom inputs can be arbitrary but can't clash with the names of standard private and public inputs. Custom inputs still need to be in the form of field elements. If the data that the developers want to pass to VP is no initially in the form of field elements, it should be properly encoded and te VP should know how to decode it back.
TODO: Juvix should support encoding by default (see here)
TODO: Can we somehow meaningfully fool a VP by shadowing one of the standard variables with a custom input?