diff --git a/Cargo.lock b/Cargo.lock index 4e78457..8781d32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1727,41 +1727,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "fibonacci-lib" -version = "0.1.0" -dependencies = [ - "alloy-sol-types", - "hex", - "p256", - "sha2", -] - -[[package]] -name = "fibonacci-program" -version = "0.1.0" -dependencies = [ - "alloy-sol-types", - "fibonacci-lib", - "hex", - "sp1-zkvm", -] - -[[package]] -name = "fibonacci-script" -version = "0.1.0" -dependencies = [ - "alloy-sol-types", - "clap", - "fibonacci-lib", - "hex", - "serde", - "serde_json", - "sp1-helper", - "sp1-sdk", - "tracing", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -2599,6 +2564,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lib" +version = "0.1.0" +dependencies = [ + "alloy-sol-types", + "hex", + "p256", + "serde", + "sha2", +] + [[package]] name = "libc" version = "0.2.155" @@ -5263,6 +5239,31 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sxg-program" +version = "0.1.0" +dependencies = [ + "alloy-sol-types", + "hex", + "lib", + "sp1-zkvm", +] + +[[package]] +name = "sxg-script" +version = "0.1.0" +dependencies = [ + "alloy-sol-types", + "clap", + "hex", + "lib", + "serde", + "serde_json", + "sp1-helper", + "sp1-sdk", + "tracing", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/elf/riscv32im-succinct-zkvm-elf b/elf/riscv32im-succinct-zkvm-elf index 46eafa6..c174359 100755 Binary files a/elf/riscv32im-succinct-zkvm-elf and b/elf/riscv32im-succinct-zkvm-elf differ diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 8b07985..906432d 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "fibonacci-lib" +name = "lib" version = "0.1.0" edition = "2021" @@ -8,7 +8,7 @@ alloy-sol-types = { workspace = true } sha2 = { version = "0.10", default-features = false } p256 = "0.13.2" hex = "0.4.3" - +serde = { version = "1.0",features = ["derive"] } [patch.crates-io] sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-v0.10.8" } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 2d25146..86ec41d 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,5 +1,5 @@ -pub mod constants; pub mod sxg; +pub mod test_cases; use alloy_sol_types::sol; use p256::ecdsa::{signature::Verifier, Signature, VerifyingKey}; @@ -8,24 +8,10 @@ use sha2::{Digest, Sha256}; sol! { /// The public values encoded as a struct that can be easily deserialized inside Solidity. struct PublicValuesStruct { - uint32 n; - uint32 a; - uint32 b; + uint32 result; } } -/// Compute the n'th fibonacci number (wrapping around on overflows), using normal Rust code. -pub fn fibonacci(n: u32) -> (u32, u32) { - let mut a = 0u32; - let mut b = 1u32; - for _ in 0..n { - let c = a.wrapping_add(b); - a = b; - b = c; - } - (a, b) -} - pub fn sha256_hash(bytes: &[u8]) -> [u8; 32] { let mut hasher = Sha256::new(); hasher.update(bytes); @@ -69,7 +55,7 @@ pub fn verify_ecdsa_p256_r_s( #[cfg(test)] mod tests { - use constants::FINAL_PAYLOAD; + use test_cases::FINAL_PAYLOAD; use super::*; diff --git a/lib/src/sxg.rs b/lib/src/sxg.rs index 5ea0f44..5199939 100644 --- a/lib/src/sxg.rs +++ b/lib/src/sxg.rs @@ -1,5 +1,11 @@ -use crate::{sha256_hash, verify_ecdsa_p256_r_s}; - +use crate::{ + sha256_hash, + test_cases::{DATA_TO_VERIFY, FINAL_PAYLOAD, PAYLOAD}, + verify_ecdsa_p256_r_s, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] pub struct SXGInput { pub final_payload: Vec, pub data_to_verify: Vec, @@ -78,43 +84,32 @@ fn base64_encode_mice(input: &[u8]) -> String { result } -pub fn sxg_verify(input: SXGInput) -> Result> { - let SXGInput { - final_payload, - data_to_verify, - data_to_verify_start_index, - integrity_start_index, - payload, - r, - s, - px, - py, - } = input; - - if payload[data_to_verify_start_index..data_to_verify_start_index + data_to_verify.len()] - != data_to_verify - { - return Ok(false); - } - - let mice = base64_encode_mice(&calculate_integrity(&payload, 16384)); - let mice_bytes = mice.as_bytes(); +impl SXGInput { + pub fn verify(&self) -> Result> { + if self.payload[self.data_to_verify_start_index + ..self.data_to_verify_start_index + self.data_to_verify.len()] + != self.data_to_verify + { + return Ok(false); + } - if final_payload[integrity_start_index..integrity_start_index + mice_bytes.len()] - != mice_bytes[..] - { - return Ok(false); - } + let mice = base64_encode_mice(&calculate_integrity(&self.payload, 16384)); + let mice_bytes = mice.as_bytes(); - Ok(verify_ecdsa_p256_r_s(&final_payload, &r, &s, &px, &py).is_ok()) -} + if self.final_payload + [self.integrity_start_index..self.integrity_start_index + mice_bytes.len()] + != mice_bytes[..] + { + return Ok(false); + } -#[cfg(test)] -mod tests { - use crate::constants::{DATA_TO_VERIFY, FINAL_PAYLOAD, PAYLOAD}; + Ok( + verify_ecdsa_p256_r_s(&self.final_payload, &self.r, &self.s, &self.px, &self.py) + .is_ok(), + ) + } - #[test] - fn test_sxg() { + pub fn default_testcase() -> SXGInput { let final_payload = FINAL_PAYLOAD; let data_to_verify = DATA_TO_VERIFY; let payload = PAYLOAD; @@ -134,7 +129,7 @@ mod tests { let px = hex::decode(px).unwrap(); let py = hex::decode(py).unwrap(); - let input = super::SXGInput { + SXGInput { final_payload: final_payload.to_vec(), data_to_verify: data_to_verify.to_vec(), data_to_verify_start_index, @@ -144,8 +139,17 @@ mod tests { s: s.try_into().unwrap(), px: px.try_into().unwrap(), py: py.try_into().unwrap(), - }; + } + } +} - assert!(super::sxg_verify(input).unwrap()); +#[cfg(test)] +mod tests { + use crate::sxg::SXGInput; + + #[test] + fn test_sxg() { + let default_input = SXGInput::default_testcase(); + assert!(default_input.verify().unwrap()); } } diff --git a/lib/src/constants.rs b/lib/src/test_cases.rs similarity index 100% rename from lib/src/constants.rs rename to lib/src/test_cases.rs diff --git a/program/Cargo.toml b/program/Cargo.toml index 94ed674..0e2bb81 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,10 +1,10 @@ [package] version = "0.1.0" -name = "fibonacci-program" +name = "sxg-program" edition = "2021" [dependencies] alloy-sol-types = { workspace = true } sp1-zkvm = "2.0.0" -fibonacci-lib = { path = "../lib" } +lib = { path = "../lib" } hex = "0.4.3" diff --git a/program/src/main.rs b/program/src/main.rs index 98235ab..68fc271 100644 --- a/program/src/main.rs +++ b/program/src/main.rs @@ -1,66 +1,13 @@ -//! A simple program that takes a number `n` as input, and writes the `n-1`th and `n`th fibonacci -//! number as an output. - -// These two lines are necessary for the program to properly compile. -// -// Under the hood, we wrap your main function with some extra code so that it behaves properly -// inside the zkVM. #![no_main] sp1_zkvm::entrypoint!(main); use alloy_sol_types::SolType; -use fibonacci_lib::constants::{DATA_TO_VERIFY, FINAL_PAYLOAD, PAYLOAD}; -use fibonacci_lib::sxg::{sxg_verify, SXGInput}; -use fibonacci_lib::{fibonacci, sha256_hash, verify_ecdsa_p256_signature, PublicValuesStruct}; -use hex; +use lib::sxg::SXGInput; +use lib::PublicValuesStruct; pub fn main() { - // Read an input to the program. - // - // Behind the scenes, this compiles down to a custom system call which handles reading inputs - // from the prover. - - let n = sp1_zkvm::io::read::(); - - let (a, b) = fibonacci(n); - - let final_payload = FINAL_PAYLOAD; - let data_to_verify = DATA_TO_VERIFY; - let payload = PAYLOAD; - - let data_to_verify_start_index = 0; - let integrity_start_index = 694 / 2; - - let px = "45E3943B0705F9EF69B53A4EFB8C668E6A9F90124E9BCF917662CFADEA56C0C1"; - let py = "F3703834F92F6FE70A004BA4098D079BFB5F927E042991EFD5A1572E8F9D39D6"; - - let r = "9970818CBCA38C196795EEAD295BDED48311702DF7DDB0C2BB448276894C393D"; - let s = "729B2F9229D545A553F0F7CBC1792E9A6185E539DBF667FE5BC38D673D90C014"; - - let r = hex::decode(r).unwrap(); - let s = hex::decode(s).unwrap(); - - let px = hex::decode(px).unwrap(); - let py = hex::decode(py).unwrap(); - - let input = SXGInput { - final_payload: final_payload.to_vec(), - data_to_verify: data_to_verify.to_vec(), - data_to_verify_start_index, - integrity_start_index, - payload: payload.to_vec(), - r: r.try_into().unwrap(), - s: s.try_into().unwrap(), - px: px.try_into().unwrap(), - py: py.try_into().unwrap(), - }; - - let result = sxg_verify(input).unwrap(); - - // Encode the public values of the program. - let bytes = PublicValuesStruct::abi_encode(&PublicValuesStruct { n, a, b }); - - // Commit to the public values of the program. The final proof will have a commitment to all the - // bytes that were committed to. + let sxg_input = sp1_zkvm::io::read::(); + let result = sxg_input.verify().unwrap() as u32; + let bytes = PublicValuesStruct::abi_encode(&PublicValuesStruct { result }); sp1_zkvm::io::commit_slice(&bytes); } diff --git a/script/Cargo.toml b/script/Cargo.toml index 58b7e81..775e101 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -1,11 +1,11 @@ [package] version = "0.1.0" -name = "fibonacci-script" +name = "sxg-script" edition = "2021" -default-run = "fibonacci" +default-run = "sxg" [[bin]] -name = "fibonacci" +name = "sxg" path = "src/bin/main.rs" [[bin]] @@ -20,7 +20,7 @@ clap = { version = "4.0", features = ["derive", "env"] } tracing = "0.1.40" hex = "0.4.3" alloy-sol-types = { workspace = true } -fibonacci-lib = { path = "../lib" } +lib = { path = "../lib" } [build-dependencies] sp1-helper = "2.0.0" diff --git a/script/src/bin/evm.rs b/script/src/bin/evm.rs index f694f61..389e088 100644 --- a/script/src/bin/evm.rs +++ b/script/src/bin/evm.rs @@ -12,20 +12,18 @@ use alloy_sol_types::SolType; use clap::{Parser, ValueEnum}; -use fibonacci_lib::PublicValuesStruct; +use lib::{sxg::SXGInput, 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 FIBONACCI_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf"); +pub const SXG_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 = "groth16")] system: ProofSystem, } @@ -40,10 +38,8 @@ enum ProofSystem { /// 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 SP1FibonacciProofFixture { - a: u32, - b: u32, - n: u32, +struct SP1SXGProofFixture { + result: u32, vkey: String, public_values: String, proof: String, @@ -60,13 +56,15 @@ fn main() { let client = ProverClient::new(); // Setup the program. - let (pk, vk) = client.setup(FIBONACCI_ELF); + let (pk, vk) = client.setup(SXG_ELF); // Setup the inputs. let mut stdin = SP1Stdin::new(); - stdin.write(&args.n); - println!("n: {}", args.n); + // TestCase from crema.sh + let sxg_input = SXGInput::default_testcase(); + stdin.write(&sxg_input); + println!("Proof System: {:?}", args.system); // Generate the proof based on the selected proof system. @@ -87,13 +85,11 @@ fn create_proof_fixture( ) { // Deserialize the public values. let bytes = proof.public_values.as_slice(); - let PublicValuesStruct { n, a, b } = PublicValuesStruct::abi_decode(bytes, false).unwrap(); + let PublicValuesStruct { result } = PublicValuesStruct::abi_decode(bytes, false).unwrap(); // Create the testing fixture so we can test things end-to-end. - let fixture = SP1FibonacciProofFixture { - a, - b, - n, + let fixture = SP1SXGProofFixture { + result, vkey: vk.bytes32().to_string(), public_values: format!("0x{}", hex::encode(bytes)), proof: format!("0x{}", hex::encode(proof.bytes())), diff --git a/script/src/bin/main.rs b/script/src/bin/main.rs index b7fd998..900c1ef 100644 --- a/script/src/bin/main.rs +++ b/script/src/bin/main.rs @@ -1,5 +1,4 @@ -//! An end-to-end example of using the SP1 SDK to generate a proof of a program that can be executed -//! or have a core proof generated. +//! An end-to-end example of using the SP1 SDK to generate a proof of a program that verifies SXG input. //! //! You can run this script using the following command: //! ```shell @@ -12,11 +11,11 @@ use alloy_sol_types::SolType; use clap::Parser; -use fibonacci_lib::PublicValuesStruct; +use lib::{sxg::SXGInput, PublicValuesStruct}; use sp1_sdk::{ProverClient, SP1Stdin}; /// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM. -pub const FIBONACCI_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf"); +pub const SXG_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf"); /// The arguments for the command. #[derive(Parser, Debug)] @@ -27,9 +26,6 @@ struct Args { #[clap(long)] prove: bool, - - #[clap(long, default_value = "20")] - n: u32, } fn main() { @@ -43,39 +39,30 @@ fn main() { std::process::exit(1); } - // Setup the prover client. let client = ProverClient::new(); - // Setup the inputs. let mut stdin = SP1Stdin::new(); - stdin.write(&args.n); - println!("n: {}", args.n); + // TestCase from crema.sh + let sxg_input = SXGInput::default_testcase(); + + stdin.write(&sxg_input); if args.execute { - // Execute the program - let (output, report) = client.execute(FIBONACCI_ELF, stdin).run().unwrap(); + let (output, report) = client.execute(SXG_ELF, stdin).run().unwrap(); println!("Program executed successfully."); - // Read the output. let decoded = PublicValuesStruct::abi_decode(output.as_slice(), true).unwrap(); - let PublicValuesStruct { n, a, b } = decoded; - println!("n: {}", n); - println!("a: {}", a); - println!("b: {}", b); + let PublicValuesStruct { result } = decoded; + println!("SXG verification result: {}", result); - let (expected_a, expected_b) = fibonacci_lib::fibonacci(n); - assert_eq!(a, expected_a); - assert_eq!(b, expected_b); - println!("Values are correct!"); + assert_eq!(result, 1); + println!("SXG verification is successful!"); - // Record the number of cycles executed. println!("Number of cycles: {}", report.total_instruction_count()); } else { - // Setup the program for proving. - let (pk, vk) = client.setup(FIBONACCI_ELF); + let (pk, vk) = client.setup(SXG_ELF); - // Generate the proof let proof = client .prove(&pk, stdin) .run() @@ -87,7 +74,6 @@ fn main() { .save("proof-with-io.json") .expect("saving proof failed"); - // Verify the proof. client.verify(&proof, &vk).expect("failed to verify proof"); println!("Successfully verified proof!"); }