mirror of
https://github.com/logos-blockchain/lssa-zkvm-testing.git
synced 2026-01-16 04:03:05 +00:00
127 lines
4.1 KiB
Rust
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");
|
|
}
|