Basics
All the methods you'll need for generating proofs are included in the sp1_sdk
crate. Most importantly, you'll need to use the ProverClient
to setup a proving key and verifying key for your program and then use the execute
, prove
and verify
methods to execute your program, and generate and verify proofs.
To make this more concrete, let's walk through a simple example of generating a proof for a Fibonacci program inside the zkVM.
Example: Fibonacci
use sp1_sdk::{include_elf, utils, ProverClient, SP1ProofWithPublicValues, SP1Stdin};
/// The ELF we want to execute inside the zkVM.
const ELF: &[u8] = include_elf!("fibonacci-program");
fn main() {
// Setup logging.
utils::setup_logger();
// Create an input stream and write '500' to it.
let n = 1000u32;
// The input stream that the program will read from using `sp1_zkvm::io::read`. Note that the
// types of the elements in the input stream must match the types being read in the program.
let mut stdin = SP1Stdin::new();
stdin.write(&n);
// Create a `ProverClient` method.
let client = ProverClient::from_env();
// Execute the program using the `ProverClient.execute` method, without generating a proof.
let (_, report) = client.execute(ELF, stdin.clone()).run().unwrap();
println!("executed program with {} cycles", report.total_instruction_count());
// Generate the proof for the given program and input.
let (pk, vk) = client.setup(ELF);
let mut proof = client.prove(&pk, stdin).run().unwrap();
println!("generated proof");
// Read and verify the output.
//
// Note that this output is read from values committed to in the program using
// `sp1_zkvm::io::commit`.
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(&proof, &vk).expect("verification failed");
// Test a round trip of proof serialization and deserialization.
proof.save("proof-with-pis.bin").expect("saving proof failed");
let deserialized_proof =
SP1ProofWithPublicValues::load("proof-with-pis.bin").expect("loading proof failed");
// Verify the deserialized proof.
client.verify(&deserialized_proof, &vk).expect("verification failed");
println!("successfully generated and verified proof for the program!")
}
You can run the above script in the script
directory with RUST_LOG=info cargo run --release
. Note that running the above script will generate a proof locally.
WARNING: Local proving often is much slower than the prover network and for certain proof types (e.g. Groth16, PLONK) require a significant amount of RAM. You might only be able to generate proofs for small inputs locally.
We recommend using the prover network to generate proofs. Read more about the recommended workflow for developing with SP1.