Skip to content

Transactions on Hylé

On traditional blockchains, users sign their transactions with a wallet and submit them to a node for block inclusion.

On Hylé, onchain operations are split into two distinct transactions:

  • Blob transaction: describes the intended operation.
  • Proof transaction: proves the correct execution of the operation.

We cut these in two steps because ZK proofs take longer to generate than traditional signature.

Why two steps ? Because zkProof are not as fast to generate as traditional signatures. By sequencing your intent with a blob transaction, you can later update the state with a proof transaction after the proof is ready. For more details, read our pipelined proving principles.

Each proof transaction (unless using recursion) proves a single blob. If a blob transaction contains multiple blobs, a separate proof is needed for each blob.

Once all blobs are proven, the blob transaction is considered settled, and the states of the referenced contracts are updated.

Example: token transfer

For a token transfer, a blob transaction contains two blobs:

  • Identity blob: verifies the sender’s identity and authorizes the transfer.
  • Transfer: executes the token transfer.

These two blobs require two corresponding proof transactions.

Blob transaction structure

A blob transaction includes two key fields:

  • An identity string. See the dedicated page on identity.
  • A list of blobs, each containing:
  • A contract name string.
  • A data binary field, which will be parsed by the contract.

For the token transfer example, the blob transaction looks like this:

{
    "identity": "bob.hydentity",
    "blobs": [
        {
            "contract_name": "hydentity",
             // Binary data for the operation of hydentity contract
             // VerifyIdentity { account: "bob.hydentity", nonce: "2" }
            "data": "[...]" 
        },
        {
            "contract_name": "hyllar",
             // Binary data for the operation of hyllar contract
             // Transfer { recipient: "alice.hydentity", ammount: "20" }
            "data": "[...]"
        }
    ]
}

Proof transaction structure

A Proof transaction is made of

  • A contract name (string)
  • The proof data (binary field), holding:
  • the ZK proof;
  • the smart contract output.

For Risc0 & SP1, the proof data's smart contract output is HyleOutput, as defined in the contract-sdk. It includes the following information:

  • The initial state of the contract
  • The new state of the contract
  • The identity that made the operation
  • A reference to the proven blob, composed of a transaction hash and an index
  • Additional fields for proof validation, built by the SDK.

For the token transfer example, the two proofs will look like this:

{
    "contract_name": "hydentity",
    // Binary proof, holding a HyleOutput with :
    // initial_state: the state of the contract "hydentity" 
    //    before the blob transaction execution 
    //    (nonce of bob is 1)
    // next_state: the state of the contract "hydentity" 
    //    after the blob transaction execution 
    //    (nonce of bob is 2)
    // identity: "bob.hydentity"
    // tx_hash: the above blob transaction hash 
    // index: 0
    "proof": "[...]"
}

and

{
    "contract_name": "hyllar",
    // Binary proof, holding a HyleOutput with :
    // initial_state: the state of the contract "hyllar" 
    //    before the blob transaction execution 
    //    (balance of bob is 100 and alice is 0)
    // next_state: the state of the contract "hyllar" 
    //    after the blob transaction execution 
    //    (balance of bob is 80 and alice is 20)
    // identity: "bob.hydentity"
    // tx_hash: the above blob transaction hash 
    // index: 1
    "proof": "[...]"
}