Scheme

Let be defined as in the section PoseidonHash Function.

Transfer

This function transfers value by burning a set of coins , and minting a set of coins, such that the value spent and created are equal.

  • Wallet:
    • Builder: src/contract/money/src/client/transfer_v1/builder.rs
    • Convenience methods: src/contract/money/src/client/transfer_v1/mod.rs
    • Build proofs: src/contract/money/src/client/transfer_v1/proof.rs
  • WASM VM code: src/contract/money/src/entrypoint/transfer_v1.rs
  • ZK proofs:
    • src/contract/money/proof/burn_v1.zk
    • src/contract/money/proof/mint_v1.zk

Function Params

Let be defined as in Inputs and Outputs.

Define the Money transfer function params

/// Parameters for `Money::Transfer` and `Money::OtcSwap`
pub struct MoneyTransferParamsV1 {
    /// Anonymous inputs
    pub inputs: Vec<Input>,
    /// Anonymous outputs
    pub outputs: Vec<Output>,
}

Contract Statement

Let be defined as in ZK Proofs.

ZK Proofs

Mint_V1

Using the Mint_V1 circuit, we are able to create outputs in our UTXO set. It is used along with the Burn_V1 circuit in MoneyFunction::TransferV1 where we perform a payment to some address on the network.

Denote this proof by .

Circuit witnesses:

  • - Public key of the recipient which goes into the coin commitment (pallas curve point)
  • - Value of the coin commitment (unsigned 64-bit integer)
  • - Token ID of the coin commitment (pallas base field element)
  • - Unique serial number of the coin commitment (pallas base field element)
  • - Spend hook, allows composing this ZK proof to invoke other contracts (pallas base field element)
  • - Data passed from this coin to the invoked contract (pallas base field element)
  • - Random blinding factor for a Pedersen commitment to (pallas scalar field element)
  • - Random blinding factor for a commitment to (pallas base field element)

Circuit public inputs:

  • - Coin commitment
  • - Pedersen commitment to
  • - Token ID commitment

Circuit:

and are constant well-known generators that are in the codebase as VALUE_COMMIT_VALUE and VALUE_COMMIT_RANDOM:

  • src/sdk/src/crypto/constants/fixed_bases/value_commit_v.rs
  • src/sdk/src/crypto/constants/fixed_bases/value_commit_r.rs

Burn_V1

Using the Burn_V1 circuit, we are able to create inputs in our UTXO set. It is used along with the Mint_V1 circuit in MoneyFunction::TransferV1 where we perform a payment to some address on the network.

Denote this proof by .

Circuit witnesses:

  • - Value of the coin being spent (unsigned 64-bit integer)
  • - Token ID of the coin being spent (pallas curve base field element)
  • - Random blinding factor for a Pedersen commitment to (pallas scalar field element)
  • - Random blinding factor for a commitment to (pallas base field element)
  • - Unique serial number of the coin commitment (pallas base field element)
  • - Spend hook, allows composing this ZK proof to invoke other contracts (pallas base field element)
  • - Data passed from this coin to the invoked contract (pallas base field element)
  • - Blinding factor for encrypting (pallas base field element)
  • - Secret key used to derive (nullifier) and (public key) from the coin (pallas base field element)
  • - Leaf position of in the Merkle tree of all coin commitments (unsigned 32-bit integer)
  • - Merkle path to the coin in the Merkle tree (array of 32 pallas base field elements)
  • - Secret key used to derive public key for the tx signature

Circuit public inputs:

  • - Published nullifier to prevent double spending
  • - Pedersen commitment to
  • - Token ID commitment
  • - Merkle root calculated from and
  • - Commitment to
  • - Spend hook
  • - Public key derived from used for transaction signing

Circuit:

and are the same generators used in Mint_V1, is the generator in the codebase known as NULLIFIER_K:

  • src/sdk/src/crypto/constants/fixed_bases/nullifier_k.rs

ZeroCond is a conditional selection: f(a, b) = if a == 0 {a} else {b}. We use this because the Merkle tree is instantiated with a fake coin of value 0 and so we're able to produce dummy inputs of value 0.

Contract call creation

Assuming a coin exists on the blockchain on leaf position and does not have a corresponding published nullifier , it can be spent. To create the necessary proofs, Alice uses the known values of her coin and picks other values that are needed to create a new coin that will be minted to Bob after is spent.

Values for Burn_V1:

  1. Alice picks a random element from to use as the secret key in order to sign the transaction.
  2. Alice picks a random element from to use as the blinding factor for .
  3. Alice picks a random element from to use as the blinding factor for .
  4. Alice creates the Burn_V1 ZK proof using the existing known values of her coin and the values picked above.

Values for Mint_V1:

  1. Alice picks a random element from to use as a unique serial number for the new coin .
  2. Alice optionally chooses a contract ID to use as or uses ZERO if does not have to call another contract.
  3. Alice optionally chooses necessary data for or uses ZERO if no data has to be passed.
  4. Alice chooses the corresponding to be able to enforce the Pedersen commitment correctness ( has to evaluate to )
  5. Alice creates the Mint_V1 ZK proof using the existing known values and the values picked above.

After creating the proofs, Alice builds a transaction containing a number of inputs that were created with Burn_V1 and a number of outputs created with Mint_V1.

/// Parameters for `Money::Transfer` and `Money::OtcSwap`
pub struct MoneyTransferParamsV1 {
    /// Anonymous inputs
    pub inputs: Vec<Input>,
    /// Anonymous outputs
    pub outputs: Vec<Output>,
}

This gets encoded into the Transaction format and the transaction is signed with a Schnorr signature scheme using the secret key chosen in Burn_V1.

Contract call execution

For MoneyFunction::TransferV1, we have the following functions, in order: