Verifying Proofs: Solidity & EVM

SP1 recently added support for verifying proofs for onchain usecases. To see an end-to-end example of using SP1 for on-chain usecases, refer to the SP1 Project Template.

Generating a Plonk Bn254 Proof

By default, the proofs generated by SP1 are not verifiable onchain, as they are non-constant size and STARK verification on Ethereum is very expensive. To generate a proof that can be verified onchain, we use performant STARK recursion to combine SP1 shard proofs into a single STARK proof and then wrap that in a SNARK proof. Our ProverClient has a function for this called prove_plonk. Behind the scenes, this function will first generate a normal SP1 proof, then recursively combine all of them into a single proof using the STARK recursion protocol. Finally, the proof is wrapped in a SNARK proof using PLONK.

The PLONK Bn254 prover is only guaranteed to work on official releases of SP1. To use PLONK proving & verification locally, ensure that you have Docker installed.

Example

use sp1_sdk::{utils, ProverClient, SP1Stdin};

/// The ELF we want to execute inside the zkVM.
const ELF: &[u8] = include_bytes!("../../program/elf/riscv32im-succinct-zkvm-elf");

fn main() {
    // Setup logging.
    utils::setup_logger();

    // Create an input stream and write '500' to it.
    let n = 500u32;

    let mut stdin = SP1Stdin::new();
    stdin.write(&n);

    // Generate the proof for the given program and input.
    let client = ProverClient::new();
    let (pk, vk) = client.setup(ELF);
    let mut proof = client.prove_plonk(&pk, stdin).unwrap();

    println!("generated proof");

    // Read and verify the output.
    let _ = proof.public_values.read::<u32>();
    let a = proof.public_values.read::<u32>();
    let b = proof.public_values.read::<u32>();
    println!("a: {}", a);
    println!("b: {}", b);

    // Verify proof and public values
    client
        .verify_plonk(&proof, &vk)
        .expect("verification failed");

    // Save the proof.
    proof
        .save("proof-with-pis.bin")
        .expect("saving proof failed");

    println!("successfully generated and verified proof for the program!")
}

You can run the above script with RUST_LOG=info cargo run --bin plonk_bn254 --release in examples/fibonacci/script.

Advanced: PLONK without Docker

If you would like to run the PLONK prover directly without Docker, you must have Go 1.22 installed and enable the native-plonk feature in sp1-sdk. This path is not recommended and may require additional native dependencies.

sp1-sdk = { features = ["native-plonk"] }

Install SP1 Contracts

SP1 Contracts

This repository contains the smart contracts for verifying SP1 EVM proofs.

Installation

[!WARNING] > Foundry installs the latest release version initially, but subsequent forge update commands will use the main branch. This branch is the development branch and should be avoided in favor of tagged releases. The release process matches a specific SP1 version.

To install the latest release version:

forge install succinctlabs/sp1-contracts

To install a specific version:

forge install succinctlabs/sp1-contracts@<version>

Add @sp1-contracts/=lib/sp1-contracts/contracts/src/ in remappings.txt.

Usage

Once installed, you can use the contracts in the library by importing them:

pragma solidity ^0.8.19;

import {SP1Verifier} from "@sp1-contracts/SP1Verifier.sol";

contract MyContract is SP1Verifier {
}

For more details on the contracts, refer to the sp1-contracts repo.