Oleksandr Pravdyvyi 6291e54247 sp1 naming fixes
2024-09-25 13:18:43 +03:00

127 lines
4.1 KiB
Rust

//! An end-to-end example of using the SP1 SDK to generate a proof of a program that can have an
//! EVM-Compatible proof generated which can be verified on-chain.
//!
//! You can run this script using the following command:
//! ```shell
//! RUST_LOG=info cargo run --release --bin evm -- --system plonk
//! ```
//! or
//! ```shell
//! RUST_LOG=info cargo run --release --bin evm -- --system groth16
//! ```
use alloy_sol_types::SolType;
use clap::{Parser, ValueEnum};
use mem_alloc_vec_test_lib::PublicValuesStruct;
use serde::{Deserialize, Serialize};
use sp1_sdk::{HashableKey, ProverClient, SP1ProofWithPublicValues, SP1Stdin, SP1VerifyingKey};
use std::path::PathBuf;
/// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM.
pub const MEM_ALLOC_VEC_TEST_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf");
/// The arguments for the EVM command.
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct EVMArgs {
#[clap(long, default_value = "20")]
n: u32,
#[clap(long, value_enum, default_value = "plonk")]
system: ProofSystem,
}
/// Enum representing the available proof systems
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
enum ProofSystem {
Plonk,
Groth16,
}
/// A fixture that can be used to test the verification of SP1 zkVM proofs inside Solidity.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SP1MemAllocVecTestProofFixture {
a: u32,
b: u32,
n: u32,
vkey: String,
public_values: String,
proof: String,
}
fn main() {
// Setup the logger.
sp1_sdk::utils::setup_logger();
// Parse the command line arguments.
let args = EVMArgs::parse();
// Setup the prover client.
let client = ProverClient::new();
// Setup the program.
let (pk, vk) = client.setup(MEM_ALLOC_VEC_TEST_ELF);
// Setup the inputs.
let mut stdin = SP1Stdin::new();
stdin.write(&args.n);
println!("n: {}", args.n);
println!("Proof System: {:?}", args.system);
// Generate the proof based on the selected proof system.
let proof = match args.system {
ProofSystem::Plonk => client.prove(&pk, stdin).plonk().run(),
ProofSystem::Groth16 => client.prove(&pk, stdin).groth16().run(),
}
.expect("failed to generate proof");
create_proof_fixture(&proof, &vk, args.system);
}
/// Create a fixture for the given proof.
fn create_proof_fixture(
proof: &SP1ProofWithPublicValues,
vk: &SP1VerifyingKey,
system: ProofSystem,
) {
// Deserialize the public values.
let bytes = proof.public_values.as_slice();
let PublicValuesStruct { n, a, b } = PublicValuesStruct::abi_decode(bytes, false).unwrap();
// Create the testing fixture so we can test things end-to-end.
let fixture = SP1MemAllocVecTestProofFixture {
a,
b,
n,
vkey: vk.bytes32().to_string(),
public_values: format!("0x{}", hex::encode(bytes)),
proof: format!("0x{}", hex::encode(proof.bytes())),
};
// The verification key is used to verify that the proof corresponds to the execution of the
// program on the given input.
//
// Note that the verification key stays the same regardless of the input.
println!("Verification Key: {}", fixture.vkey);
// The public values are the values which are publicly committed to by the zkVM.
//
// If you need to expose the inputs or outputs of your program, you should commit them in
// the public values.
println!("Public Values: {}", fixture.public_values);
// The proof proves to the verifier that the program was executed with some inputs that led to
// the give public values.
println!("Proof Bytes: {}", fixture.proof);
// Save the fixture to a file.
let fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/fixtures");
std::fs::create_dir_all(&fixture_path).expect("failed to create fixture path");
std::fs::write(
fixture_path.join(format!("{:?}-fixture.json", system).to_lowercase()),
serde_json::to_string_pretty(&fixture).unwrap(),
)
.expect("failed to write fixture");
}