diff --git a/README.md b/README.md index 3de4456..11a0c32 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ To install the latest release version: forge install succinctlabs/sp1-contracts ``` -Add `@sp1-contracts/=lib/sp1-contracts/contracts/src/` in `remappings.txt.` +Add `@sp1-contracts/=lib/sp1-contracts/contracts/src/` in `remappings.txt`. -### Usage +## Usage Once installed, you can import the `ISP1Verifier` interface and use it in your contract: @@ -22,7 +22,8 @@ pragma solidity ^0.8.20; import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol"; contract MyContract { - address public constant SP1_VERIFIER = 0x3B6041173B80E77f038f3F2C0f9744f04837185e; + /// @dev Use the gateway address for your chain from the deployments/ folder. + address public SP1_VERIFIER; bytes32 public constant PROGRAM_VKEY = ...; @@ -32,72 +33,160 @@ contract MyContract { } ``` -You can obtain the correct `SP1_VERIFIER` address for your chain by looking in the [deployments](./contracts/deployments) directory, it's recommended to use the `SP1_VERIFIER_GATEWAY` address which will automatically route proofs to the correct verifier based on their version. +You can obtain the correct `SP1_VERIFIER` address for your chain by looking in the [deployments](./contracts/deployments) directory. Use the `SP1_VERIFIER_GATEWAY` address which automatically routes proofs to the correct verifier based on their version. -You can obtain the correct `PROGRAM_VKEY` for your program calling the `setup` function for your ELF: +You can obtain the correct `PROGRAM_VKEY` for your program by calling the `setup` function for your ELF: ```rs - let client = ProverClient::new(); - let (_, vk) = client.setup(ELF); - println!("PROGRAM_VKEY = {}", vk.bytes32()); +let client = ProverClient::new(); +let (_, vk) = client.setup(ELF); +println!("PROGRAM_VKEY = {}", vk.bytes32()); ``` -### Deployments +## Deploy Your Own Verifiers -To deploy the contracts, ensure your [.env](./contracts/.env.example) file is configured with all the chains you want to deploy to. +This section walks through deploying your own SP1 verifier gateway and verifiers. This is useful for testing on testnets or deploying to a chain not yet supported by the canonical deployments. -Then you can use the `forge script` command and specify the specific contract you want to deploy. For example, to deploy the SP1 Verifier Gateway for PLONK you can run: +> For canonical Succinct-managed deployments, see [Deployed Addresses](#deployed-addresses). + +### Prerequisites + +- [Foundry](https://book.getfoundry.sh/getting-started/installation) +- Node.js 18+ +- Git + +### Setup + +```bash +git clone https://github.com/succinctlabs/sp1-contracts.git +cd sp1-contracts/contracts +forge install +``` + +Copy and configure the environment file: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/SP1VerifierGatewayPlonk.s.sol:SP1VerifierGatewayScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +cp .env.example .env ``` -or to deploy the SP1 Verifier Gateway for Groth16 you can run: +Fill in the following values in `.env`: + +| Variable | Description | +|----------|-------------| +| `PRIVATE_KEY` | Deployer EOA private key | +| `CREATE2_SALT` | Salt for deterministic deployment (e.g. `0x0000000000000000000000000000000000000000000000000000000000000001`) | +| `OWNER` | Address that will own the gateway (your deployer address for testing) | +| `CHAINS` | Target chains, comma-separated (e.g. `SEPOLIA`) | +| `RPC_` | RPC endpoint for each chain (e.g. `RPC_SEPOLIA=https://...`) | +| `ETHERSCAN_API_KEY_` | Etherscan API key for contract verification | +| `ETHERSCAN_API_URL_` | Etherscan API URL for each chain | + +Then load the environment: + +```bash +source .env +``` + +> **Note**: The deploy scripts read RPC endpoints from environment variables (`RPC_`), not from the `--rpc-url` CLI flag. + +### Step 1: Deploy Gateways + +Deploy the verifier gateways. The `OWNER` address will be the only address able to add and freeze routes. ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/SP1VerifierGatewayGroth16.s.sol:SP1VerifierGatewayScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +# Groth16 gateway +FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/SP1VerifierGatewayGroth16.s.sol:SP1VerifierGatewayScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast + +# Plonk gateway +FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/SP1VerifierGatewayPlonk.s.sol:SP1VerifierGatewayScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast ``` -### Adding Verifiers +Gateway addresses are written to `deployments/.json`. -You can use the `forge script` command to specify which verifier you want to deploy and add to the gateway. For example to deploy the PLONK verifier and add it to the PLONK gateway you can run: +### Step 2: Deploy Verifiers & Register Routes + +Deploy verifiers and register them with the gateway in a single step. Since you own the gateway, set `REGISTER_ROUTE=true`: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +# Groth16 verifier +REGISTER_ROUTE=true FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/v6.0.0-beta.1/SP1VerifierGroth16.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast + +# Plonk verifier +REGISTER_ROUTE=true FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/v6.0.0-beta.1/SP1VerifierPlonk.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast ``` -or to deploy the Groth16 verifier and add it to the Groth16 gateway you can run: +> Change `v6.0.0-beta.1` to the desired SP1 version. Available versions are in `script/deploy/`. + +Verify the deployment: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0/SP1VerifierGroth16.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +cat deployments/.json | jq . ``` -Change `v3.0.0` to the desired version to add. +### Step 3: Verify On-chain + +Check that routes are registered on the gateway: + +```bash +GATEWAY=$(cat deployments/.json | jq -r '.SP1_VERIFIER_GATEWAY_GROTH16') +VERIFIER=$(cat deployments/.json | jq -r '.V6_0_0_BETA_1_SP1_VERIFIER_GROTH16') -### Freezing Verifiers +SELECTOR=$(cast call $VERIFIER "VERIFIER_HASH()" --rpc-url $RPC_SEPOLIA | cut -c1-10) +cast call $GATEWAY "routes(bytes4)" $SELECTOR --rpc-url $RPC_SEPOLIA +# Should return the verifier address (non-zero) +``` -> [!WARNING] -> **BE CAREFUL** When a freezing a verifier. Once it is frozen, it cannot be unfrozen, and it can no longer be routed to. +### Multi-chain Deployment -To freeze a verifier on the gateway, run: +To deploy across multiple chains, set `CHAINS` to a comma-separated list: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast --sig "freeze()" +CHAINS=SEPOLIA,HOLESKY ``` -Change `v3.0.0` to the desired version to freeze. +Each chain requires its own `RPC_`, `ETHERSCAN_API_KEY_`, and `ETHERSCAN_API_URL_` entries in `.env`. See [`.env.example`](./contracts/.env.example) for all supported chains. + +## Deployed Addresses + +Succinct Labs maintains canonical verifier gateways across all major chains. You can find the full list of deployed addresses at: + +- **Docs**: https://docs.succinct.xyz/docs/sp1/verification/contract-addresses +- **This repo**: [`contracts/deployments/`](./contracts/deployments/) (JSON files keyed by chain ID) + +For production gateway management, see the [production deployment guide](./docs/PRODUCTION_DEPLOYMENT.md). + +## Freezing Verifiers + +> [!WARNING] +> Once frozen, a verifier cannot be unfrozen and can no longer be routed to. + +```bash +FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/v6.0.0-beta.1/SP1VerifierPlonk.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --multi --broadcast --sig "freeze()" +``` -## For Developers: Integrate SP1 Contracts +## Architecture -This repository contains the EVM contracts for verifying SP1 PLONK EVM proofs. +The SP1 verification system uses a gateway pattern: -You can find more details on the contracts in the [`contracts`](./contracts/README.md) directory. +- **SP1VerifierGateway** routes proof verification calls to the correct versioned verifier. The first 4 bytes of the proof are a selector derived from the verifier's `VERIFIER_HASH`, which the gateway uses to look up the registered route. +- Each SP1 version has both **Groth16** and **Plonk** verifier variants, deployed behind separate gateways. +- The gateway owner can **add routes** (register new verifier versions) and **freeze routes** (permanently disable a verifier version). -Note: you should ensure that all the contracts are on Solidity version `0.8.20`. +See [`contracts/`](./contracts/README.md) for more details on the contract structure. ## For Contributors -To update the SP1 contracts, please refer to the [`update`](./UPDATE_CONTRACTS.md) file. +To update the SP1 contracts with a new version, see the [update guide](./UPDATE_CONTRACTS.md). ## Security diff --git a/contracts/.env.example b/contracts/.env.example index 9982f9b..38bd464 100644 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -19,6 +19,7 @@ RPC_OPTIMISM= RPC_OPTIMISM_SEPOLIA= RPC_SCROLL= RPC_SCROLL_SEPOLIA= +RPC_HOODI= RPC_HYPEREVM= # Etherscan API keys for each chain ID diff --git a/contracts/README.md b/contracts/README.md index d4a4ca9..eeb8202 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -1,9 +1,16 @@ # SP1 Contracts -This repository contains the smart contracts for verifying [SP1](https://github.com/succinctlabs/sp1) EVM proofs. +Smart contracts for verifying [SP1](https://github.com/succinctlabs/sp1) EVM proofs. -## Overview -- [`SP1Verifier`](./src/SP1Verifier.sol): The main contract for verifying SP1 EVM proofs. -- [`SP1MockVerifier`](./src/SP1MockVerifier.sol): A mock contract for testing SP1 EVM proofs. -- [`ISP1Verifier`](./src/ISP1Verifier.sol): Interface for SP1Verifier. -- [`PlonkVerifier`](./src/PlonkVerifier.sol): Core logic for verifying Plonk EVM proofs. +## Contracts + +- [`SP1VerifierGateway`](./src/SP1VerifierGateway.sol) — Routes proofs to the correct versioned verifier based on a 4-byte selector derived from `VERIFIER_HASH`. +- [`ISP1Verifier`](./src/ISP1Verifier.sol) — Interface for SP1 verifier contracts. +- [`ISP1VerifierGateway`](./src/ISP1VerifierGateway.sol) — Interface for the gateway. +- [`SP1MockVerifier`](./src/SP1MockVerifier.sol) — Mock verifier for testing. + +Versioned verifier implementations (Groth16 and Plonk) are in `src/v*/` directories. + +## Deployments + +Per-chain contract addresses are in [`deployments/`](./deployments/) as JSON files keyed by chain ID (e.g., `1.json` for Ethereum mainnet). diff --git a/docs/PRODUCTION_DEPLOYMENT.md b/docs/PRODUCTION_DEPLOYMENT.md new file mode 100644 index 0000000..099efb9 --- /dev/null +++ b/docs/PRODUCTION_DEPLOYMENT.md @@ -0,0 +1,176 @@ +# Canonical Verifier Gateway Management + +This guide covers how the canonical SP1 verifier gateways are deployed and managed by Succinct Labs. These are the gateways that SP1 users integrate with to verify proofs on-chain. + +For the full list of deployed gateway addresses, see: https://docs.succinct.xyz/docs/sp1/verification/contract-addresses + +## How It Works + +- Canonical gateways are deployed across all supported chains (Ethereum, Arbitrum, Base, Optimism, Scroll, etc.) with identical addresses via CREATE2. +- Gateways are owned by a multisig. Only the multisig can add or freeze routes. +- When a new SP1 version is released, new verifier contracts are deployed by an EOA, then registered as routes on the gateways via a multisig transaction. +- Problematic versions can be permanently frozen via `freezeRoute()`. +- **Release policy**: only official releases are deployed to mainnets. Testnets may include release candidates. + +## Prerequisites + +### Access + +| Item | Description | +|------|-------------| +| Deployer EOA | EOA with ETH on all target chains (deploys verifier contracts) | +| Multisig signer | Signer on the gateway owner multisig (registers routes) | +| Etherscan API keys | One per target chain for contract verification | + +### Software + +```bash +node --version # 18+ +forge --version # Foundry +git --version +``` + +### Setup + +```bash +git clone https://github.com/succinctlabs/sp1-contracts.git +cd sp1-contracts/contracts +forge install +``` + +Configure `.env` with all target chains (see [`.env.example`](../contracts/.env.example)): + +```bash +cp .env.example .env +# Fill in: PRIVATE_KEY, CREATE2_SALT, all RPC_* and ETHERSCAN_API_KEY_* entries +source .env +``` + +## Phase 1: Deploy Verifiers + +Deploy verifier contracts to all target chains. `REGISTER_ROUTE` defaults to `false` because the deployer EOA is not the gateway owner — route registration happens separately via multisig in Phase 2. + +```bash +# Groth16 +CHAINS=MAINNET,OPTIMISM,ARBITRUM,BASE,SCROLL \ +FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy//SP1VerifierGroth16.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast + +# Plonk +CHAINS=MAINNET,OPTIMISM,ARBITRUM,BASE,SCROLL \ +FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy//SP1VerifierPlonk.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +``` + +> Replace `` with the target version (e.g. `v6.0.0-beta.1`). Available versions are in `script/deploy/`. + +Verify that addresses were written: + +```bash +cat deployments/1.json | jq . | grep +# e.g. grep V6_0_0_BETA_1 +``` + +Commit and push the deployment files: + +```bash +git add deployments/ +git commit -m "deploy: verifiers" +git push +``` + +## Phase 2: Register Routes via Multisig + +### Generate Safe Transaction Builder JSON + +```bash +node script/utils/generate-safe-batch.js --chain=all --version= +``` + +This reads verifier addresses from `deployments/*.json` and generates Safe Transaction Builder JSON files. For example, with `--version=v6.0.0-beta.1`: + +``` +safe-batches/1_v6_0_0_beta_1.json # Ethereum +safe-batches/10_v6_0_0_beta_1.json # Optimism +safe-batches/42161_v6_0_0_beta_1.json # Arbitrum +safe-batches/8453_v6_0_0_beta_1.json # Base +safe-batches/534352_v6_0_0_beta_1.json # Scroll +``` + +Each file contains `addRoute()` transactions for both Groth16 and Plonk verifiers on that chain. + +To generate for a specific chain: + +```bash +node script/utils/generate-safe-batch.js --chain=1 --version= +``` + +### First Signer + +1. Open [Safe UI](https://app.safe.global) for the gateway owner multisig on the target chain. +2. Connect your wallet. +3. Go to **Apps → Transaction Builder**. +4. Upload the generated JSON file for that chain. +5. Verify: correct number of transactions (2 per chain — one Groth16, one Plonk), correct verifier and gateway addresses. +6. **Simulate** — verify `RouteAdded` events appear in the simulation. +7. **Sign** the transaction. + +### Second Signer + +1. Open Safe UI, connect wallet. +2. Find the pending transaction (shows "1 of 2 confirmations"). +3. **Simulate** again to double-check. +4. **Sign & Execute**. +5. Verify `RouteAdded` events in the transaction receipt. + +Repeat for each target chain. + +## Phase 3: Verify + +Check that routes are registered on each chain: + +```bash +GATEWAY=$(cat deployments/1.json | jq -r '.SP1_VERIFIER_GATEWAY_GROTH16') +VERIFIER=$(cat deployments/1.json | jq -r '.V6_0_0_BETA_1_SP1_VERIFIER_GROTH16') + +SELECTOR=$(cast call $VERIFIER "VERIFIER_HASH()" --rpc-url $RPC_MAINNET | cut -c1-10) +cast call $GATEWAY "routes(bytes4)" $SELECTOR --rpc-url $RPC_MAINNET +# Should return the verifier address (non-zero = route registered) +``` + +Repeat for Plonk and for each target chain. + +After verification, ensure the [contract addresses docs page](https://docs.succinct.xyz/docs/sp1/verification/contract-addresses) is updated if new chains were added. + +## Troubleshooting + +| Error | Solution | +|-------|----------| +| `insufficient funds` | Fund the deployer EOA on the target chain | +| `contract already deployed` | Expected with CREATE2 — same salt produces same address. This is fine. | +| Etherscan verification failed | Add `--delay 30` flag to the forge command, or verify manually on Etherscan later | +| Safe simulation failed | Check that the verifier address is correct and the gateway is not frozen | +| `No verifiers for ` | Run Phase 1 first — verifier addresses must exist in `deployments/*.json` | +| `generate-safe-batch.js` not found | Make sure you're running from the `contracts/` directory | + +## Quick Reference + +```bash +# Generate Safe batch for all mainnet chains +node script/utils/generate-safe-batch.js --chain=all --version= + +# Generate for a specific chain +node script/utils/generate-safe-batch.js --chain=1 --version= + +# Check deployment addresses +cat deployments/1.json | jq . + +# Check gateway owner +cast call $(cat deployments/1.json | jq -r '.SP1_VERIFIER_GATEWAY_GROTH16') "owner()" --rpc-url $RPC_MAINNET + +# Check if a route exists +SELECTOR=$(cast call $VERIFIER "VERIFIER_HASH()" --rpc-url $RPC_MAINNET | cut -c1-10) +cast call $GATEWAY "routes(bytes4)" $SELECTOR --rpc-url $RPC_MAINNET +```