On-chain Proof Verification

Note

If you've successfully performed fast-track migration, you do not need to follow the steps on this page.

The cryptographic fault proofs generated by Kailua require the existence of a RISC Zero verifier contract on the parent chain (ethereum).

Tip

Use the Kailua CLI config command to retrieve the address of the officially deployed RISC Zero verifier for your parent chain. If one is available, you can use that address as your verifier and skip the steps in this section.

This section explains how to deploy a verifier suited to your needs, but you'll need to maintain it in case of adopting any updates to Kailua that change the RISC Zero zkVM version used for proving.

Verifier Contracts

This section describes the contracts that make up the on-chain proof verification pipeline.

Verifier Router

The RISCZeroVerifierRouter contract routes proofs from different sources to their correct verifier. This allows your application (and Kailua) to leverage proofs generated using different zkVM versions, or aggregated through the Boundless proving network, while delegating the complexity of managing the verifier version to the router contract.

Depending on your needs, you may need to deploy and manage your own verifier instead of relying on the pre-deployed router managed by RISC Zero.

Warning

The verifier deployment made by Kailua does not yet utilize the Emergency stop contract in the pre-deployed RISC Zero verifier, which allows anyone to permissionlessy disable a verification backend in the router by proving a false statement.

Groth16 Verifier

The RISCZeroGroth16Verifier only accepts valid Groth16 proofs generated using its hardcoded RISC Zero zkVM version determined by the control root and id constructor parameters. This verifier is intended to be deployed and then added as a possible backend to a router instead of being used directly on its own. However, it is possible to call and use this verifier directly if the prover and verifier versions align.

Set Verifier (Boundless Network)

The RISCZeroSetVerifier accepts aggregated proofs, which are generated through recursively verifying other proofs inside an aggregator program. This verifier only verifies "inclusion proofs", and delegates the verification of the cryptographic proof of correct aggregation to another verifier (such as the router or the Groth16 verifier directly). This means it must be paired with another verifier contract.

Fake Proof Verifier (INSECURE)

This verifier accepts fake proofs generated while running the RISC Zero zkVM in "dev mode". It is only useful for testing out the zkVM in a development environment without being delayed by proving time.

Danger

Do not use the fake proof verifier anywhere near production.

Deployment

This section will walk you through creating your own verifier deployment that supports individual and aggregated proofs. The commands below will be using Foundry's forge and cast utilities, which you should have installed as part of the foundry prerequisite.

Note

The below foundry commands expect both a parameter that determines the wallet to use and the rpc endpoint of the parent chain. You will have to add these two parameters manually to every command below. For more information, refer to forge create --help, cast call --help, and cast send --help

First, change your working directory to crates/contracts/foundry for forge to work:

cd crates/contracts/foundry

Router

constructor(address admin) Ownable(admin)

The RISCZeroVerifierRouter constructor requires a single admin address, which is an account authorised to modify the router in one of two ways after it is deployed:

  1. Add a new verification backend through addVerifier:
  2. Permanently disable a verification backend through removeVerifier:

To deploy a new router, invoke the following command

forge create RiscZeroVerifierRouter --constructor-args [ADMIN_ADDRESS]

On success, you should see output similar to the following:

Deployer: [YOUR_DEPLOYER_WALLET_ADDRESS]
Deployed to: [YOUR_DEPLOYED_ROUTER_CONTRACT]
Transaction hash: [YOUR_DEPLOYMENT_TRANSACTION_HASH]

Success

Make sure to note down the YOUR_DEPLOYED_ROUTER_CONTRACT address. We will use this in the following commands when adding proving backends. The router cannot verify any proofs on its own.

Aggregate Verifier

constructor(IRiscZeroVerifier verifier, bytes32 imageId, string memory _imageUrl)

The aggregate verifier requires two main parameters to construct it, an address for a verifier to use to validate proofs of aggregation, and an image id defining the program to use for aggregating proofs. The third parameter specifies where the aggregation program is hosted, and can be left blank.

We will reuse the router contract we just deployed as the verifier, and the SET_BUILDER_ID value we got from running kailua-cli config.

To deploy a new aggregate verifier

forge create RiscZeroSetVerifier --constructor-args \
  [YOUR_DEPLOYED_ROUTER_CONTRACT] \
  [SET_BUILDER_ID] \
  ""

On success, you should see output similar to the following:

Deployer: [YOUR_DEPLOYER_WALLET_ADDRESS]
Deployed to: [YOUR_DEPLOYED_AGGREGATE_VERIFIER_CONTRACT]
Transaction hash: [YOUR_DEPLOYMENT_TRANSACTION_HASH]

The next step is to now add this aggregate verifier contract as a backend for our router to use to verify any aggregated proofs it receives. For this, we will first to need to query the aggregate verifier for its "selector" using foundry's cast utility:

cast call \
  [YOUR_DEPLOYED_AGGREGATE_VERIFIER_CONTRACT] \
  "SELECTOR() returns (bytes4)"

This should return a short string similar to the following:

0x9cc26c32

We can now use this selector to add the aggregate verifier to the router using the admin wallet you specified while deploying the router:

cast send \
  [YOUR_DEPLOYED_ROUTER_CONTRACT] \
  "addVerifier(bytes4 selector, address verifier)" \
  [YOUR_AGGREGATE_VERIFIER_SELECTOR] \
  [YOUR_DEPLOYED_AGGREGATE_VERIFIER_CONTRACT]

The output from successfully issuing this transaction should resemble the following:

blockHash               0x9cb7f77cab555ff8907a62d19165795e7dbd51d558ee29a7383ced32daea18ab
blockNumber             821
contractAddress         
cumulativeGasUsed       414546
effectiveGasPrice       1000000007
from                    0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc
gasUsed                 46831
logs                    []
logsBloom               0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
root                    
status                  1 (success)
transactionHash         0x1446eeeb02008e6ef37dc60556f6a45848f106e175d0ea597fc41370918022c9
transactionIndex        1
type                    2
blobGasPrice            
blobGasUsed             
authorizationList       
to                      0x0116686E2291dbd5e317F47faDBFb43B599786Ef

Make sure that the status field in your output indicates success!

Success

You've now connected your verifier router to the aggregate verifier. However, this pair still cannot verify any proofs on its own! Next, we will install a cryptographic verifier for this task.

Groth16 Verifier

The Groth16 verifier validates stand-alone cryptographic proofs generated using the RISC Zero zkVM and compressed using the RISC Zero STARK-to-SNARK wrapper.

This verifier can be deployed as follows using the control root and id from the kailua-cli config command output:

forge create RiscZeroGroth16Verifier --constructor-args \ 
  [YOUR_CONTROL_ROOT] \
  [YOUR_CONTROL_ID]

The output should again give you the relevant addresses:

Deployer: [YOUR_DEPLOYER_WALLET_ADDRESS]
Deployed to: [YOUR_DEPLOYED_GROTH16_VERIFIER_CONTRACT]
Transaction hash: [YOUR_DEPLOYMENT_TRANSACTION_HASH]

We again need to query this verifier's selector:

cast call [YOUR_DEPLOYED_GROTH16_VERIFIER_CONTRACT] \
  "SELECTOR() returns (bytes4)"

Yielding another 4-byte selector:

0xc101b42b

And finally we need to add this verifier to our router:

cast send \
  [YOUR_DEPLOYED_ROUTER_CONTRACT] \
  "addVerifier(bytes4 selector, address verifier)" \
  [YOUR_GROTH16_SELECTOR] \
  [YOUR_DEPLOYED_GROTH16_VERIFIER_CONTRACT]

Success

You now have a RISC Zero verifier contract for stand-alone and aggregated ZK (fault) proofs!