Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Integrating ZK Proofs with On-Chain Contracts

This document details the process of integrating Zero-Knowledge (ZK) proofs, generated by a Valence Coprocessor guest program, with the Valence Protocol's on-chain smart contracts. It assumes an understanding of the ZK system as outlined in Valence ZK System Overview and how guest programs are developed as described in Developing Valence Coprocessor Apps.

The core of on-chain integration revolves around submitting the ZK proof and its associated public data to the Authorization.sol contract (for EVM chains), which then collaborates with a VerificationGateway.sol to cryptographically verify the proof's authenticity and correctness.

Preparing Data for On-Chain Submission

After your guest program successfully executes on the ZK Coprocessor and a proof is generated, two key pieces of data are essential for on-chain interaction:

  1. The ZK Proof: This is the raw cryptographic proof data (e.g., SP1 proof bytes) generated by the Coprocessor, attesting to the correct execution of your guest program's ZK circuit.
  2. The Circuit's Public Output: Your ZK circuit is designed to produce a public output (Vec<u8>). This output is critical because it represents the data that, once proven correct by the ZK proof, will be used to form the processorMessage for execution by the on-chain Valence Processor contract. It's important to remember that when the full "public inputs" are presented to the on-chain verifier, the first 32 bytes are a prefix that contains the Coprocessor Root hash. The remaining bytes are relevant for constructing on-chain messages.

An off-chain system, such as a script, bot, or backend service, is responsible for retrieving these pieces of data from the Coprocessor (typically after the guest program stores them in its virtual filesystem) and then initiating the on-chain transaction.

The ZKMessage Structure

To submit a ZK-proven action to the Valence Protocol, the off-chain system must construct a ZKMessage. This structure is specifically designed for the executeZKMessage function within the Authorization.sol contract. The ZKMessage encapsulates all necessary information for the on-chain contracts to process the request:

FieldTypeDescription
registryuint64Unique identifier for the deployed ZK guest program. Used by the Authorization contract to look up the correct Verification Key (VK) from VerificationGateway.
blockNumberuint64Current or recent block number for replay protection. Ensures proofs aren't submitted multiple times, or after that they're no longer relevant.
authorizationContractaddressAddress of the target Authorization contract. Acts as a safeguard to ensure message is processed by the correct instance.
processorMessagebytesCore payload dispatched to Processor contract if ZK proof is valid. Derived from circuit's public output and encoded for ProcessorMessageTypes.

On-Chain Verification Sequence

Once the ZKMessage is constructed and the ZK proof is obtained, the off-chain system submits these to the executeZKMessage function of the Authorization.sol contract. The on-chain processing then unfolds as follows:

  1. Initial Checks by Authorization.sol: The Authorization contract first performs several preliminary checks. It verifies if the msg.sender (the account submitting the transaction) is authorized to provide proofs for the given registry ID. It also typically checks the blockNumber from the ZKMessage against its record of the last executed block for that registry to prevent replay attacks.

  2. Delegation to VerificationGateway.sol: If the initial checks pass, Authorization.sol delegates the task of cryptographic proof verification to the VerificationGateway.sol contract whose address it has been configured with. It calls a verify function on the gateway, passing along the ZK proof, the registry ID (so the gateway can find the correct VK), and a hash derived from the ZKMessage contents (crucially including the processorMessage which represents your circuit's output).

  3. Proof Verification by VerificationGateway.sol: The VerificationGateway retrieves the pre-registered Verification Key (VK) associated with the registry ID. It then uses this VK, the submitted ZK proof, and the public inputs to perform the cryptographic verification. The public inputs are a critical piece of data: they include the Coprocessor Root hash (the first 32 bytes) followed by your circuit's specific output (which is embedded within the hashed ZKMessage). This Coprocessor Root hash acts as a commitment to the integrity of all Coprocessor state. It implicitly contains all the embedded state proofs of the domain relevant to that ZK proof, managed via its Sparse Merkle Tree (SMT). Every new block appended to a chain relevant to the proof's domain is included in this SMT with a ZK domain proof, and the verifications of these inclusions are cryptographically embedded into this Coprocessor Root. If the proof is valid for the VK and these comprehensive public inputs, the gateway returns a success status to the Authorization.sol contract.

  4. Dispatch to Processor.sol: If the VerificationGateway confirms the proof's validity, Authorization.sol considers the processorMessage within the ZKMessage to be authentic and authorized for execution. It then typically updates its state for replay protection (e.g., storing the blockNumber as the last executed for that registry) and dispatches the processorMessage to the appropriate Valence Processor.sol contract.

  5. Execution by Processor.sol: The Processor.sol contract receives the processorMessage and executes the sequence of on-chain actions (e.g., calls to various Valence Libraries or other smart contracts) as defined within that message. This is where the result of your ZK-proven off-chain computation translates into tangible on-chain state changes.

This integration pathway ensures that off-chain computations, once proven correct by the ZK Coprocessor, can be securely and reliably acted upon by the Valence on-chain contracts.