diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index ceb72c905..259497a7d 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -132,7 +132,7 @@ jobs: - name: Install SP1 CLI run: | cd cli - cargo install --locked --path . + cargo install --force --locked --path . cd ~ - name: Run cargo check @@ -161,7 +161,7 @@ jobs: - name: Install SP1 CLI run: | cd cli - cargo install --locked --path . + cargo install --force --locked --path . cd ~ - name: Run cargo prove new diff --git a/Cargo.lock b/Cargo.lock index 27a887dc0..3a0e9cb91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4337,6 +4337,7 @@ dependencies = [ "strum", "strum_macros", "tempfile", + "thiserror", "tiny-keccak", "tracing", "tracing-forest", @@ -4435,6 +4436,7 @@ dependencies = [ "sp1-recursion-program", "subtle-encoding", "tempfile", + "thiserror", "tokio", "tracing", "tracing-appender", diff --git a/core/Cargo.toml b/core/Cargo.toml index e477ec263..4758fc939 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -58,6 +58,7 @@ strum = "0.26" web-time = "1.1.0" rayon-scan = "0.1.1" serial_test = "3.1.1" +thiserror = "1.0.60" [dev-dependencies] tiny-keccak = { version = "2.0.2", features = ["keccak"] } diff --git a/core/benches/main.rs b/core/benches/main.rs index 86e608344..ca63a750f 100644 --- a/core/benches/main.rs +++ b/core/benches/main.rs @@ -1,7 +1,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use sp1_core::io::SP1Stdin; use sp1_core::runtime::{Program, Runtime}; -use sp1_core::utils::{run_and_prove, BabyBearPoseidon2}; +use sp1_core::utils::{prove, BabyBearPoseidon2}; #[allow(unreachable_code)] pub fn criterion_benchmark(c: &mut Criterion) { @@ -13,14 +13,14 @@ pub fn criterion_benchmark(c: &mut Criterion) { let program = Program::from_elf(&elf_path); let cycles = { let mut runtime = Runtime::new(program.clone()); - runtime.run(); + runtime.run().unwrap(); runtime.state.global_clk }; group.bench_function( format!("main:{}:{}", p.split('/').last().unwrap(), cycles), |b| { b.iter(|| { - run_and_prove( + prove( black_box(program.clone()), &SP1Stdin::new(), BabyBearPoseidon2::new(), diff --git a/core/src/cpu/trace.rs b/core/src/cpu/trace.rs index e5d5b8320..7000fe062 100644 --- a/core/src/cpu/trace.rs +++ b/core/src/cpu/trace.rs @@ -662,7 +662,7 @@ mod tests { fn generate_trace_simple_program() { let program = simple_program(); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); let chip = CpuChip::default(); let trace: RowMajorMatrix = chip.generate_trace(&runtime.record, &mut ExecutionRecord::default()); diff --git a/core/src/lookup/debug.rs b/core/src/lookup/debug.rs index d9d1dd241..c58d882b7 100644 --- a/core/src/lookup/debug.rs +++ b/core/src/lookup/debug.rs @@ -223,7 +223,7 @@ mod test { let machine = RiscvAir::machine(config); let (pk, _) = machine.setup(&program); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); let shards = machine.shard(runtime.record, &ShardingConfig::default()); let ok = debug_interactions_with_all_chips(&machine, &pk, &shards, InteractionKind::all_kinds()); diff --git a/core/src/memory/global.rs b/core/src/memory/global.rs index e5fa81d37..5c9974e09 100644 --- a/core/src/memory/global.rs +++ b/core/src/memory/global.rs @@ -185,7 +185,7 @@ mod tests { fn test_memory_generate_trace() { let program = simple_program(); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); let shard = runtime.record.clone(); let chip: MemoryChip = MemoryChip::new(MemoryChipType::Initialize); @@ -211,7 +211,7 @@ mod tests { let program = simple_program(); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); let chip = MemoryChip::new(MemoryChipType::Initialize); @@ -229,7 +229,7 @@ mod tests { let program = sha_extend_program(); let program_clone = program.clone(); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); let machine: crate::stark::StarkMachine> = RiscvAir::machine(BabyBearPoseidon2::new()); let (pkey, _) = machine.setup(&program_clone); @@ -252,7 +252,7 @@ mod tests { let program = sha_extend_program(); let program_clone = program.clone(); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); let machine = RiscvAir::machine(BabyBearPoseidon2::new()); let (pkey, _) = machine.setup(&program_clone); let shards = machine.shard( diff --git a/core/src/runtime/io.rs b/core/src/runtime/io.rs index 14ba34450..0be9da0e1 100644 --- a/core/src/runtime/io.rs +++ b/core/src/runtime/io.rs @@ -60,7 +60,7 @@ pub mod tests { use super::*; use crate::runtime::Program; use crate::utils::tests::IO_ELF; - use crate::utils::{self, prove_core, BabyBearBlake3}; + use crate::utils::{self, prove_simple, BabyBearBlake3}; use serde::Deserialize; #[derive(Serialize, Deserialize, Debug, PartialEq)] @@ -93,7 +93,7 @@ pub mod tests { let points = points(); runtime.write_stdin(&points.0); runtime.write_stdin(&points.1); - runtime.run(); + runtime.run().unwrap(); let added_point = runtime.read_public_values::(); assert_eq!( added_point, @@ -113,8 +113,8 @@ pub mod tests { let points = points(); runtime.write_stdin(&points.0); runtime.write_stdin(&points.1); - runtime.run(); + runtime.run().unwrap(); let config = BabyBearBlake3::new(); - prove_core(config, runtime); + prove_simple(config, runtime).unwrap(); } } diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs index d7df28228..282ce0365 100644 --- a/core/src/runtime/mod.rs +++ b/core/src/runtime/mod.rs @@ -28,13 +28,13 @@ use std::io::Write; use std::rc::Rc; use std::sync::Arc; +use thiserror::Error; + use crate::memory::MemoryInitializeFinalizeEvent; use crate::utils::env; use crate::{alu::AluEvent, cpu::CpuEvent}; -pub const MAX_SHARD_CLK: usize = (1 << 24) - 1; - -/// An implementation of a runtime for the SP1 VM. +/// An implementation of a runtime for the SP1 RISC-V zkVM. /// /// The runtime is responsible for executing a user program and tracing important events which occur /// during execution (i.e., memory reads, alu operations, etc). @@ -68,10 +68,8 @@ pub struct Runtime { /// A buffer for writing trace events to a file. pub trace_buf: Option>, - /// Whether the runtime should fail on panic or not. - pub fail_on_panic: bool, - /// Whether the runtime is in constrained mode or not. + /// /// In unconstrained mode, any events, clock, register, or memory changes are reset after leaving /// the unconstrained block. The only thing preserved is writes to the input stream. pub unconstrained: bool, @@ -85,6 +83,20 @@ pub struct Runtime { pub emit_events: bool, } +#[derive(Error, Debug)] +pub enum ExecutionError { + #[error("execution failed with exit code {0}")] + HaltWithNonZeroExitCode(u32), + #[error("invalid memory access for opcode {0} and address {1}")] + InvalidMemoryAccess(Opcode, u32), + #[error("unimplemented syscall {0}")] + UnsupportedSyscall(u32), + #[error("breakpoint encountered")] + Breakpoint(), + #[error("got unimplemented as opcode")] + Unimplemented(), +} + impl Runtime { // Create a new runtime from a program. pub fn new(program: Program) -> Self { @@ -105,8 +117,8 @@ impl Runtime { None }; - let syscall_map = default_syscall_map(); // Determine the maximum number of cycles for any syscall. + let syscall_map = default_syscall_map(); let max_syscall_cycles = syscall_map .values() .map(|syscall| syscall.num_extra_cycles()) @@ -114,7 +126,6 @@ impl Runtime { .unwrap_or(0); let shard_size = env::shard_size() as u32; - Self { record, state: ExecutionState::new(program.pc_start), @@ -125,7 +136,6 @@ impl Runtime { cycle_tracker: HashMap::new(), io_buf: HashMap::new(), trace_buf, - fail_on_panic: true, unconstrained: false, unconstrained_state: ForkState::default(), syscall_map, @@ -215,6 +225,7 @@ impl Runtime { Entry::Vacant(entry) => { // If addr has a specific value to be initialized with, use that, otherwise 0. let value = self.state.uninitialized_memory.remove(&addr).unwrap_or(0); + // Do not emit memory initialize events for address 0 as that is done in initialize. if addr != 0 { self.record @@ -262,6 +273,7 @@ impl Runtime { Entry::Vacant(entry) => { // If addr has a specific value to be initialized with, use that, otherwise 0. let value = self.state.uninitialized_memory.remove(&addr).unwrap_or(0); + // Do not emit memory initialize events for address 0 as that is done in initialize. if addr != 0 { self.record @@ -502,7 +514,7 @@ impl Runtime { } /// Execute the given instruction over the current state of the runtime. - fn execute_instruction(&mut self, instruction: Instruction) { + fn execute_instruction(&mut self, instruction: Instruction) -> Result<(), ExecutionError> { let mut pc = self.state.pc; let mut clk = self.state.clk; let mut exit_code = 0u32; @@ -578,7 +590,9 @@ impl Runtime { } Opcode::LH => { (rd, b, c, addr, memory_read_value) = self.load_rr(instruction); - assert_eq!(addr % 2, 0, "addr is not aligned"); + if addr % 2 != 0 { + return Err(ExecutionError::InvalidMemoryAccess(Opcode::LH, addr)); + } let value = match (addr >> 1) % 2 { 0 => memory_read_value & 0x0000FFFF, 1 => (memory_read_value & 0xFFFF0000) >> 16, @@ -590,7 +604,9 @@ impl Runtime { } Opcode::LW => { (rd, b, c, addr, memory_read_value) = self.load_rr(instruction); - assert_eq!(addr % 4, 0, "addr is not aligned"); + if addr % 4 != 0 { + return Err(ExecutionError::InvalidMemoryAccess(Opcode::LW, addr)); + } a = memory_read_value; memory_store_value = Some(memory_read_value); self.rw(rd, a); @@ -604,7 +620,9 @@ impl Runtime { } Opcode::LHU => { (rd, b, c, addr, memory_read_value) = self.load_rr(instruction); - assert_eq!(addr % 2, 0, "addr is not aligned"); + if addr % 2 != 0 { + return Err(ExecutionError::InvalidMemoryAccess(Opcode::LHU, addr)); + } let value = match (addr >> 1) % 2 { 0 => memory_read_value & 0x0000FFFF, 1 => (memory_read_value & 0xFFFF0000) >> 16, @@ -630,7 +648,9 @@ impl Runtime { } Opcode::SH => { (a, b, c, addr, memory_read_value) = self.store_rr(instruction); - assert_eq!(addr % 2, 0, "addr is not aligned"); + if addr % 2 != 0 { + return Err(ExecutionError::InvalidMemoryAccess(Opcode::SH, addr)); + } let value = match (addr >> 1) % 2 { 0 => (a & 0x0000FFFF) + (memory_read_value & 0xFFFF0000), 1 => ((a & 0x0000FFFF) << 16) + (memory_read_value & 0x0000FFFF), @@ -641,7 +661,9 @@ impl Runtime { } Opcode::SW => { (a, b, c, addr, _) = self.store_rr(instruction); - assert_eq!(addr % 4, 0, "addr is not aligned"); + if addr % 4 != 0 { + return Err(ExecutionError::InvalidMemoryAccess(Opcode::SW, addr)); + } let value = a; memory_store_value = Some(value); self.mw_cpu(align(addr), value, MemoryAccessPosition::Memory); @@ -711,9 +733,9 @@ impl Runtime { // System instructions. Opcode::ECALL => { + // We peek at register x5 to get the syscall id. The reason we don't `self.rr` this + // register is that we write to it later. let t0 = Register::X5; - // We peek at register x5 to get the syscall id. The reason we don't `self.rr` this register - // is that we write to it later. let syscall_id = self.register(t0); c = self.rr(Register::X11, MemoryAccessPosition::C); b = self.rr(Register::X10, MemoryAccessPosition::B); @@ -721,7 +743,6 @@ impl Runtime { let syscall_impl = self.get_syscall(syscall).cloned(); let mut precompile_rt = SyscallContext::new(self); - let (precompile_next_pc, precompile_cycles, returned_exit_code) = if let Some(syscall_impl) = syscall_impl { // Executing a syscall optionally returns a value to write to the t0 register. @@ -730,16 +751,23 @@ impl Runtime { if let Some(val) = res { a = val; } else { - // Default to syscall_id if no value is returned from syscall execution. a = syscall_id; } + + // If the syscall is `HALT` and the exit code is non-zero, return an error. + if syscall == SyscallCode::HALT && precompile_rt.exit_code != 0 { + return Err(ExecutionError::HaltWithNonZeroExitCode( + precompile_rt.exit_code, + )); + } + ( precompile_rt.next_pc, syscall_impl.num_extra_cycles(), precompile_rt.exit_code, ) } else { - panic!("Unsupported syscall: {:?}", syscall); + return Err(ExecutionError::UnsupportedSyscall(syscall_id)); }; // Allow the syscall impl to modify state.clk/pc (exit unconstrained does this) @@ -751,9 +779,8 @@ impl Runtime { self.state.clk += precompile_cycles; exit_code = returned_exit_code; } - Opcode::EBREAK => { - todo!() + return Err(ExecutionError::Breakpoint()); } // Multiply instructions. @@ -814,14 +841,15 @@ impl Runtime { self.alu_rw(instruction, rd, a, b, c); } + // See https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md#instruction-aliases Opcode::UNIMP => { - // See https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md#instruction-aliases - panic!("UNIMP encountered, we should never get here."); + return Err(ExecutionError::Unimplemented()); } } // Update the program counter. self.state.pc = next_pc; + // Update the clk to the next cycle. self.state.clk += 4; @@ -840,12 +868,14 @@ impl Runtime { self.memory_accesses, exit_code, ); - } + }; + + Ok(()) } /// Executes one cycle of the program, returning whether the program has finished. #[inline] - fn execute_cycle(&mut self) -> bool { + fn execute_cycle(&mut self) -> Result { // Fetch the instruction at the current program counter. let instruction = self.fetch(); @@ -853,7 +883,7 @@ impl Runtime { self.log(&instruction); // Execute the instruction. - self.execute_instruction(instruction); + self.execute_instruction(instruction)?; // Increment the clock. self.state.global_clk += 1; @@ -865,23 +895,23 @@ impl Runtime { self.state.clk = 0; } - self.state.pc.wrapping_sub(self.program.pc_base) - >= (self.program.instructions.len() * 4) as u32 + Ok(self.state.pc.wrapping_sub(self.program.pc_base) + >= (self.program.instructions.len() * 4) as u32) } /// Execute up to `self.shard_batch_size` cycles, returning the events emitted and whether the program ended. - pub fn execute_record(&mut self) -> (ExecutionRecord, bool) { + pub fn execute_record(&mut self) -> Result<(ExecutionRecord, bool), ExecutionError> { self.emit_events = true; - let done = self.execute(); - (std::mem::take(&mut self.record), done) + let done = self.execute()?; + Ok((std::mem::take(&mut self.record), done)) } /// Execute up to `self.shard_batch_size` cycles, returning a copy of the prestate and whether the program ended. - pub fn execute_state(&mut self) -> (ExecutionState, bool) { + pub fn execute_state(&mut self) -> Result<(ExecutionState, bool), ExecutionError> { self.emit_events = false; let state = self.state.clone(); - let done = self.execute(); - (state, done) + let done = self.execute()?; + Ok((state, done)) } fn initialize(&mut self) { @@ -907,18 +937,19 @@ impl Runtime { tracing::info!("starting execution"); } - pub fn run(&mut self) { + pub fn run(&mut self) -> Result<(), ExecutionError> { self.emit_events = true; - while !self.execute() {} + while !self.execute()? {} + Ok(()) } pub fn dry_run(&mut self) { self.emit_events = false; - while !self.execute() {} + while !self.execute().unwrap() {} } /// Executes up to `self.shard_batch_size` cycles of the program, returning whether the program has finished. - fn execute(&mut self) -> bool { + fn execute(&mut self) -> Result { // If it's the first cycle, initialize the program. if self.state.global_clk == 0 { self.initialize(); @@ -929,7 +960,7 @@ impl Runtime { let mut current_shard = self.state.current_shard; let mut num_shards_executed = 0; loop { - if self.execute_cycle() { + if self.execute_cycle()? { done = true; break; } @@ -947,7 +978,7 @@ impl Runtime { self.postprocess(); } - done + Ok(done) } fn postprocess(&mut self) { @@ -1019,7 +1050,7 @@ pub mod tests { use crate::{ runtime::Register, - utils::tests::{FIBONACCI_ELF, SSZ_WITHDRAWALS_ELF}, + utils::tests::{FIBONACCI_ELF, PANIC_ELF, SSZ_WITHDRAWALS_ELF}, }; use super::{Instruction, Opcode, Program, Runtime}; @@ -1041,14 +1072,26 @@ pub mod tests { Program::from(SSZ_WITHDRAWALS_ELF) } + pub fn panic_program() -> Program { + Program::from(PANIC_ELF) + } + #[test] fn test_simple_program_run() { let program = simple_program(); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 42); } + #[test] + #[should_panic] + fn test_panic() { + let program = panic_program(); + let mut runtime = Runtime::new(program); + runtime.run().unwrap(); + } + #[test] fn test_add() { // main: @@ -1062,7 +1105,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 42); } @@ -1079,7 +1122,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 32); } @@ -1096,7 +1139,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 32); } @@ -1114,7 +1157,7 @@ pub mod tests { let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 37); } @@ -1131,7 +1174,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 5); } @@ -1148,7 +1191,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 1184); } @@ -1165,7 +1208,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 1); } @@ -1182,7 +1225,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 1); } @@ -1199,7 +1242,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1216,7 +1259,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1233,7 +1276,7 @@ pub mod tests { let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 84); } @@ -1249,7 +1292,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 5 - 1 + 4); } @@ -1265,7 +1308,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 10); } @@ -1281,7 +1324,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 47); } @@ -1297,7 +1340,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1311,7 +1354,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 80); } @@ -1325,7 +1368,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 2); } @@ -1339,7 +1382,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 2); } @@ -1353,7 +1396,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1367,7 +1410,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1386,7 +1429,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.registers()[Register::X5 as usize], 8); assert_eq!(runtime.registers()[Register::X11 as usize], 100); assert_eq!(runtime.state.pc, 108); @@ -1400,7 +1443,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); assert_eq!(runtime.registers()[Register::X12 as usize], expected); } @@ -1618,7 +1661,7 @@ pub mod tests { fn test_simple_memory_program_run() { let program = simple_memory_program(); let mut runtime = Runtime::new(program); - runtime.run(); + runtime.run().unwrap(); // Assert SW & LW case assert_eq!(runtime.register(Register::X28), 0x12348765); diff --git a/core/src/stark/machine.rs b/core/src/stark/machine.rs index 89638765f..948ceca9a 100644 --- a/core/src/stark/machine.rs +++ b/core/src/stark/machine.rs @@ -254,9 +254,7 @@ impl>> StarkMachine { // Display some statistics about the workload. let stats = record.stats(); - for (k, v) in stats { - log::info!("{} = {}", k, v); - } + log::info!("Shard: {:?}", stats); // For each chip, shard the events into segments. record.shard(config) @@ -520,7 +518,7 @@ pub mod tests { use crate::runtime::Opcode; use crate::runtime::Program; use crate::utils; - use crate::utils::run_and_prove; + use crate::utils::prove; use crate::utils::run_test; use crate::utils::setup_logger; use crate::utils::BabyBearPoseidon2; @@ -671,7 +669,7 @@ pub mod tests { setup_logger(); let program = fibonacci_program(); let stdin = SP1Stdin::new(); - run_and_prove(program, &stdin, BabyBearPoseidon2::new()); + prove(program, &stdin, BabyBearPoseidon2::new()).unwrap(); } #[test] diff --git a/core/src/syscall/halt.rs b/core/src/syscall/halt.rs index 68e3a39f4..9572beecb 100644 --- a/core/src/syscall/halt.rs +++ b/core/src/syscall/halt.rs @@ -10,14 +10,6 @@ impl SyscallHalt { impl Syscall for SyscallHalt { fn execute(&self, ctx: &mut SyscallContext, exit_code: u32, _: u32) -> Option { - let rt = &mut ctx.rt; - - if rt.fail_on_panic && exit_code != 0 { - panic!( - "RISC-V runtime halted during program execution with non-zero exit code {}. This likely means your program panicked during execution.", - exit_code - ); - } ctx.set_next_pc(0); ctx.set_exit_code(exit_code); None diff --git a/core/src/syscall/hint.rs b/core/src/syscall/hint.rs index d11b86dbc..e79fedfec 100644 --- a/core/src/syscall/hint.rs +++ b/core/src/syscall/hint.rs @@ -75,7 +75,7 @@ mod tests { use crate::{ io::SP1Stdin, runtime::Program, - utils::{run_and_prove, setup_logger, BabyBearPoseidon2}, + utils::{prove, setup_logger, BabyBearPoseidon2}, }; const HINT_IO_ELF: &[u8] = @@ -96,6 +96,6 @@ mod tests { let program = Program::from(HINT_IO_ELF); let config = BabyBearPoseidon2::new(); - run_and_prove(program, &stdin, config); + prove(program, &stdin, config).unwrap(); } } diff --git a/core/src/syscall/precompiles/keccak256/air.rs b/core/src/syscall/precompiles/keccak256/air.rs index 36360af21..ceda18305 100644 --- a/core/src/syscall/precompiles/keccak256/air.rs +++ b/core/src/syscall/precompiles/keccak256/air.rs @@ -134,7 +134,7 @@ mod test { use crate::io::{SP1PublicValues, SP1Stdin}; use crate::runtime::Program; use crate::stark::{RiscvAir, StarkGenericConfig}; - use crate::utils::{run_and_prove, setup_logger, tests::KECCAK256_ELF, BabyBearPoseidon2}; + use crate::utils::{prove, setup_logger, tests::KECCAK256_ELF, BabyBearPoseidon2}; use rand::Rng; use rand::SeedableRng; @@ -169,7 +169,7 @@ mod test { let config = BabyBearPoseidon2::new(); let program = Program::from(KECCAK256_ELF); - let (proof, public_values) = run_and_prove(program, &stdin, config); + let (proof, public_values) = prove(program, &stdin, config).unwrap(); let mut public_values = SP1PublicValues::from(&public_values); let config = BabyBearPoseidon2::new(); diff --git a/core/src/syscall/precompiles/keccak256/mod.rs b/core/src/syscall/precompiles/keccak256/mod.rs index f0b0a7114..b44ce53f0 100644 --- a/core/src/syscall/precompiles/keccak256/mod.rs +++ b/core/src/syscall/precompiles/keccak256/mod.rs @@ -75,7 +75,7 @@ pub mod permute_tests { utils::setup_logger(); let program = keccak_permute_program(); let mut runtime = Runtime::new(program); - runtime.run() + runtime.run().unwrap(); } #[test] diff --git a/core/src/utils/env.rs b/core/src/utils/env.rs index 371bdc561..2ee11fef5 100644 --- a/core/src/utils/env.rs +++ b/core/src/utils/env.rs @@ -1,6 +1,7 @@ -use crate::runtime::MAX_SHARD_CLK; use crate::utils::log2_strict_usize; +pub const MAX_SHARD_CLK: usize = (1 << 24) - 1; + /// Gets the number of rows which by default should be used for each chip to maximize padding. pub fn shard_size() -> usize { let value = match std::env::var("SHARD_SIZE") { diff --git a/core/src/utils/programs.rs b/core/src/utils/programs.rs index 839a55b37..58af5a08c 100644 --- a/core/src/utils/programs.rs +++ b/core/src/utils/programs.rs @@ -105,4 +105,7 @@ pub mod tests { pub const VERIFY_PROOF_ELF: &[u8] = include_bytes!("../../../tests/verify-proof/elf/riscv32im-succinct-zkvm-elf"); + + pub const PANIC_ELF: &[u8] = + include_bytes!("../../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); } diff --git a/core/src/utils/prove.rs b/core/src/utils/prove.rs index 515672a64..47a96d1c1 100644 --- a/core/src/utils/prove.rs +++ b/core/src/utils/prove.rs @@ -1,26 +1,30 @@ use std::fs::File; +use std::io; use std::io::{Seek, Write}; use web_time::Instant; -use crate::air::MachineAir; -use crate::io::{SP1PublicValues, SP1Stdin}; pub use baby_bear_blake3::BabyBearBlake3; use p3_challenger::CanObserve; use p3_field::PrimeField32; use serde::de::DeserializeOwned; use serde::Serialize; use size::Size; +use thiserror::Error; +use crate::air::MachineAir; +use crate::io::{SP1PublicValues, SP1Stdin}; use crate::lookup::InteractionBuilder; +use crate::runtime::ExecutionError; use crate::runtime::{ExecutionRecord, ShardingConfig}; use crate::stark::DebugConstraintBuilder; +use crate::stark::MachineProof; use crate::stark::ProverConstraintFolder; use crate::stark::StarkVerifyingKey; use crate::stark::Val; use crate::stark::VerifierConstraintFolder; use crate::stark::{Com, PcsProverData, RiscvAir, ShardProof, StarkProvingKey, UniConfig}; use crate::stark::{MachineRecord, StarkMachine}; -use crate::utils::env::shard_batch_size; +use crate::utils::env; use crate::{ runtime::{Program, Runtime}, stark::StarkGenericConfig, @@ -29,119 +33,56 @@ use crate::{ const LOG_DEGREE_BOUND: usize = 31; -/// Runs a program and returns the public values stream. -pub fn run_test_io( - program: Program, - inputs: SP1Stdin, -) -> Result> { - let runtime = tracing::info_span!("runtime.run(...)").in_scope(|| { - let mut runtime = Runtime::new(program); - runtime.write_vecs(&inputs.buffer); - runtime.run(); - runtime - }); - let public_values = SP1PublicValues::from(&runtime.state.public_values_stream); - let _ = run_test_core(runtime)?; - Ok(public_values) -} - -pub fn run_test( - program: Program, -) -> Result< - crate::stark::MachineProof, - crate::stark::MachineVerificationError, -> { - let runtime = tracing::info_span!("runtime.run(...)").in_scope(|| { - let mut runtime = Runtime::new(program); - runtime.run(); - runtime - }); - run_test_core(runtime) +#[derive(Error, Debug)] +pub enum SP1CoreProverError { + #[error("failed to execute program: {0}")] + ExecutionError(ExecutionError), + #[error("io error: {0}")] + IoError(io::Error), + #[error("serialization error: {0}")] + SerializationError(bincode::Error), } -#[allow(unused_variables)] -pub fn run_test_core( +pub fn prove_simple( + config: SC, runtime: Runtime, -) -> Result< - crate::stark::MachineProof, - crate::stark::MachineVerificationError, -> { - let config = BabyBearPoseidon2::new(); - let machine = RiscvAir::machine(config); - let (pk, vk) = machine.setup(runtime.program.as_ref()); - - let record = runtime.record; - run_test_machine(record, machine, pk, vk) -} - -#[allow(unused_variables)] -pub fn run_test_machine( - record: A::Record, - machine: StarkMachine, - pk: StarkProvingKey, - vk: StarkVerifyingKey, -) -> Result, crate::stark::MachineVerificationError> +) -> Result, SP1CoreProverError> where - A: MachineAir - + for<'a> Air> - + Air>> - + for<'a> Air> - + for<'a> Air, SC::Challenge>>, - SC: StarkGenericConfig, - SC::Val: p3_field::PrimeField32, SC::Challenger: Clone, + OpeningProof: Send + Sync, Com: Send + Sync, PcsProverData: Send + Sync, - OpeningProof: Send + Sync, ShardMainData: Serialize + DeserializeOwned, + ::Val: PrimeField32, { - #[cfg(feature = "debug")] - { - let mut challenger_clone = machine.config().challenger(); - let record_clone = record.clone(); - machine.debug_constraints(&pk, record_clone, &mut challenger_clone); - } - let stats = record.stats().clone(); - let cycles = stats.get("cpu_events").unwrap(); + // Setup the machine. + let machine = RiscvAir::machine(config); + let (pk, _) = machine.setup(runtime.program.as_ref()); - let start = Instant::now(); + // Prove the program. let mut challenger = machine.config().challenger(); - let proof = machine.prove::>(&pk, record, &mut challenger); - let time = start.elapsed().as_millis(); + let proving_start = Instant::now(); + let proof = machine.prove::>(&pk, runtime.record, &mut challenger); + let proving_duration = proving_start.elapsed().as_millis(); let nb_bytes = bincode::serialize(&proof).unwrap().len(); - let mut challenger = machine.config().challenger(); - machine.verify(&vk, &proof, &mut challenger)?; - + // Print the summary. tracing::info!( "summary: cycles={}, e2e={}, khz={:.2}, proofSize={}", - cycles, - time, - (*cycles as f64 / time as f64), + runtime.state.global_clk, + proving_duration, + (runtime.state.global_clk as f64 / proving_duration as f64), Size::from_bytes(nb_bytes), ); Ok(proof) } -fn trace_checkpoint(program: Program, file: &File) -> ExecutionRecord { - let mut reader = std::io::BufReader::new(file); - let state = bincode::deserialize_from(&mut reader).expect("failed to deserialize state"); - let mut runtime = Runtime::recover(program.clone(), state); - let (events, _) = tracing::debug_span!("runtime.trace").in_scope(|| runtime.execute_record()); - events -} - -fn reset_seek(file: &mut File) { - file.seek(std::io::SeekFrom::Start(0)) - .expect("failed to seek to start of tempfile"); -} - -pub fn run_and_prove( +pub fn prove( program: Program, stdin: &SP1Stdin, config: SC, -) -> (crate::stark::MachineProof, Vec) +) -> Result<(MachineProof, Vec), SP1CoreProverError> where SC::Challenger: Clone, OpeningProof: Send + Sync, @@ -150,83 +91,87 @@ where ShardMainData: Serialize + DeserializeOwned, ::Val: PrimeField32, { - let mut challenger = config.challenger(); + let proving_start = Instant::now(); - let machine = RiscvAir::machine(config); + // Execute the program. let mut runtime = Runtime::new(program.clone()); runtime.write_vecs(&stdin.buffer); for proof in stdin.proofs.iter() { runtime.write_proof(proof.0.clone(), proof.1.clone()); } + + // Setup the machine. + let machine = RiscvAir::machine(config); let (pk, vk) = machine.setup(runtime.program.as_ref()); - let should_batch = shard_batch_size() > 0; // If we don't need to batch, we can just run the program normally and prove it. - if !should_batch { - runtime.run(); + if env::shard_batch_size() == 0 { + // Execute the runtime and collect all the events.. + runtime.run().map_err(SP1CoreProverError::ExecutionError)?; + + // If debugging is enabled, we will also debug the constraints. #[cfg(feature = "debug")] { - let record_clone = runtime.record.clone(); - machine.debug_constraints(&pk, record_clone, &mut challenger); + let mut challenger = machine.config().challenger(); + machine.debug_constraints(&pk, runtime.record.clone(), &mut challenger); } + + // Generate the proof and return the proof and public values. let public_values = std::mem::take(&mut runtime.state.public_values_stream); - let proof = prove_core(machine.config().clone(), runtime); - return (proof, public_values); + let proof = prove_simple(machine.config().clone(), runtime)?; + return Ok((proof, public_values)); } // Execute the program, saving checkpoints at the start of every `shard_batch_size` cycle range. - let mut cycles = 0; - let mut prove_time = 0; let mut checkpoints = Vec::new(); - let (public_values_stream, public_values) = - tracing::info_span!("runtime.state").in_scope(|| loop { - // Get checkpoint + move to next checkpoint, then save checkpoint to temp file - let (state, done) = runtime.execute_state(); - let mut tempfile = tempfile::tempfile().expect("failed to create tempfile"); - let mut writer = std::io::BufWriter::new(&mut tempfile); - bincode::serialize_into(&mut writer, &state).expect("failed to serialize state"); - writer.flush().expect("failed to flush writer"); - drop(writer); - tempfile - .seek(std::io::SeekFrom::Start(0)) - .expect("failed to seek to start of tempfile"); - checkpoints.push(tempfile); - if done { - return ( - std::mem::take(&mut runtime.state.public_values_stream), - runtime.record.public_values, - ); - } - }); + let (public_values_stream, public_values) = loop { + // Execute the runtime until we reach a checkpoint. + let (checkpoint, done) = runtime + .execute_state() + .map_err(SP1CoreProverError::ExecutionError)?; + + // Save the checkpoint to a temp file. + let mut tempfile = tempfile::tempfile().map_err(SP1CoreProverError::IoError)?; + let mut writer = std::io::BufWriter::new(&mut tempfile); + bincode::serialize_into(&mut writer, &checkpoint) + .map_err(SP1CoreProverError::SerializationError)?; + writer.flush().map_err(SP1CoreProverError::IoError)?; + drop(writer); + tempfile + .seek(std::io::SeekFrom::Start(0)) + .map_err(SP1CoreProverError::IoError)?; + checkpoints.push(tempfile); + + // If we've reached the final checkpoint, break out of the loop. + if done { + break ( + std::mem::take(&mut runtime.state.public_values_stream), + runtime.record.public_values, + ); + } + }; // For each checkpoint, generate events, shard them, commit shards, and observe in challenger. let sharding_config = ShardingConfig::default(); let mut shard_main_datas = Vec::new(); + let mut challenger = machine.config().challenger(); + vk.observe_into(&mut challenger); + for checkpoint_file in checkpoints.iter_mut() { + let mut record = trace_checkpoint(program.clone(), checkpoint_file); + record.public_values = public_values; + reset_seek(&mut *checkpoint_file); - // If there's only one batch, it already must fit in memory so reuse it later in open multi - // rather than running the runtime again. - let reuse_shards = checkpoints.len() == 1; - let mut all_shards = None; + // Shard the record into shards. + let checkpoint_shards = + tracing::info_span!("shard").in_scope(|| machine.shard(record, &sharding_config)); - vk.observe_into(&mut challenger); - for file in checkpoints.iter_mut() { - let mut events = trace_checkpoint(program.clone(), file); - events.public_values = public_values; - - reset_seek(&mut *file); - cycles += events.cpu_events.len(); - let shards = - tracing::debug_span!("shard").in_scope(|| machine.shard(events, &sharding_config)); + // Commit to each shard. let (commitments, commit_data) = tracing::info_span!("commit") - .in_scope(|| LocalProver::commit_shards(&machine, &shards)); - + .in_scope(|| LocalProver::commit_shards(&machine, &checkpoint_shards)); shard_main_datas.push(commit_data); - if reuse_shards { - all_shards = Some(shards.clone()); - } - - for (commitment, shard) in commitments.into_iter().zip(shards.iter()) { + // Observe the commitments. + for (commitment, shard) in commitments.into_iter().zip(checkpoint_shards.iter()) { challenger.observe(commitment); challenger.observe_slice(&shard.public_values::()[0..machine.num_pv_elts()]); } @@ -234,17 +179,14 @@ where // For each checkpoint, generate events and shard again, then prove the shards. let mut shard_proofs = Vec::>::new(); - for mut file in checkpoints.into_iter() { - let shards = if reuse_shards { - Option::take(&mut all_shards).unwrap() - } else { - let mut events = trace_checkpoint(program.clone(), &file); + for mut checkpoint_file in checkpoints.into_iter() { + let checkpoint_shards = { + let mut events = trace_checkpoint(program.clone(), &checkpoint_file); events.public_values = public_values; - reset_seek(&mut file); + reset_seek(&mut checkpoint_file); tracing::debug_span!("shard").in_scope(|| machine.shard(events, &sharding_config)) }; - let start = Instant::now(); - let mut new_proofs = shards + let mut checkpoint_proofs = checkpoint_shards .into_iter() .map(|shard| { let config = machine.config(); @@ -265,59 +207,130 @@ where ) }) .collect::>(); - prove_time += start.elapsed().as_millis(); - shard_proofs.append(&mut new_proofs); + shard_proofs.append(&mut checkpoint_proofs); } + let proof = MachineProof:: { shard_proofs }; - let proof = crate::stark::MachineProof:: { shard_proofs }; - - // Prove the program. - let nb_bytes = bincode::serialize(&proof).unwrap().len(); - + // Print the summary. + let proving_time = proving_start.elapsed().as_secs_f64(); tracing::info!( "summary: cycles={}, e2e={}, khz={:.2}, proofSize={}", - cycles, - prove_time, - (cycles as f64 / prove_time as f64), - Size::from_bytes(nb_bytes), + runtime.state.global_clk, + proving_time, + (runtime.state.global_clk as f64 / proving_time as f64), + bincode::serialize(&proof).unwrap().len(), ); - (proof, public_values_stream) + Ok((proof, public_values_stream)) } -pub fn prove_core( - config: SC, +/// Runs a program and returns the public values stream. +pub fn run_test_io( + program: Program, + inputs: SP1Stdin, +) -> Result> { + let runtime = tracing::info_span!("runtime.run(...)").in_scope(|| { + let mut runtime = Runtime::new(program); + runtime.write_vecs(&inputs.buffer); + runtime.run().unwrap(); + runtime + }); + let public_values = SP1PublicValues::from(&runtime.state.public_values_stream); + let _ = run_test_core(runtime)?; + Ok(public_values) +} + +pub fn run_test( + program: Program, +) -> Result< + crate::stark::MachineProof, + crate::stark::MachineVerificationError, +> { + let runtime = tracing::info_span!("runtime.run(...)").in_scope(|| { + let mut runtime = Runtime::new(program); + runtime.run().unwrap(); + runtime + }); + run_test_core(runtime) +} + +#[allow(unused_variables)] +pub fn run_test_core( runtime: Runtime, -) -> crate::stark::MachineProof +) -> Result< + crate::stark::MachineProof, + crate::stark::MachineVerificationError, +> { + let config = BabyBearPoseidon2::new(); + let machine = RiscvAir::machine(config); + let (pk, vk) = machine.setup(runtime.program.as_ref()); + + let record = runtime.record; + run_test_machine(record, machine, pk, vk) +} + +#[allow(unused_variables)] +pub fn run_test_machine( + record: A::Record, + machine: StarkMachine, + pk: StarkProvingKey, + vk: StarkVerifyingKey, +) -> Result, crate::stark::MachineVerificationError> where + A: MachineAir + + for<'a> Air> + + Air>> + + for<'a> Air> + + for<'a> Air, SC::Challenge>>, + SC: StarkGenericConfig, + SC::Val: p3_field::PrimeField32, SC::Challenger: Clone, - OpeningProof: Send + Sync, Com: Send + Sync, PcsProverData: Send + Sync, + OpeningProof: Send + Sync, ShardMainData: Serialize + DeserializeOwned, - ::Val: PrimeField32, { - let mut challenger = config.challenger(); - - let machine = RiscvAir::machine(config); - let (pk, _) = machine.setup(runtime.program.as_ref()); + #[cfg(feature = "debug")] + { + let mut challenger_clone = machine.config().challenger(); + let record_clone = record.clone(); + machine.debug_constraints(&pk, record_clone, &mut challenger_clone); + } + let stats = record.stats().clone(); + let cycles = stats.get("cpu_events").unwrap(); - // Prove the program. let start = Instant::now(); - let cycles = runtime.state.global_clk; - let proof = machine.prove::>(&pk, runtime.record, &mut challenger); + let mut challenger = machine.config().challenger(); + let proof = machine.prove::>(&pk, record, &mut challenger); let time = start.elapsed().as_millis(); let nb_bytes = bincode::serialize(&proof).unwrap().len(); + let mut challenger = machine.config().challenger(); + machine.verify(&vk, &proof, &mut challenger)?; + tracing::info!( "summary: cycles={}, e2e={}, khz={:.2}, proofSize={}", cycles, time, - (cycles as f64 / time as f64), + (*cycles as f64 / time as f64), Size::from_bytes(nb_bytes), ); - proof + Ok(proof) +} + +fn trace_checkpoint(program: Program, file: &File) -> ExecutionRecord { + let mut reader = std::io::BufReader::new(file); + let state = bincode::deserialize_from(&mut reader).expect("failed to deserialize state"); + let mut runtime = Runtime::recover(program.clone(), state); + let (events, _) = + tracing::debug_span!("runtime.trace").in_scope(|| runtime.execute_record().unwrap()); + events +} + +fn reset_seek(file: &mut File) { + file.seek(std::io::SeekFrom::Start(0)) + .expect("failed to seek to start of tempfile"); } #[cfg(debug_assertions)] diff --git a/eval/src/main.rs b/eval/src/main.rs index ee637ba69..c11e4413f 100644 --- a/eval/src/main.rs +++ b/eval/src/main.rs @@ -5,7 +5,7 @@ use clap::{command, Parser}; use csv::WriterBuilder; use serde::Serialize; use sp1_core::runtime::{Program, Runtime}; -use sp1_core::utils::{prove_core, BabyBearBlake3, BabyBearKeccak, BabyBearPoseidon2}; +use sp1_core::utils::{prove_simple, BabyBearBlake3, BabyBearKeccak, BabyBearPoseidon2}; use sp1_prover::utils::get_cycles; use sp1_prover::SP1Stdin; use std::fmt; @@ -139,12 +139,12 @@ fn run_evaluation(hashfn: &HashFnId, program: &Program, _elf: &[u8]) -> (f64, f6 HashFnId::Blake3 => { let mut runtime = Runtime::new(program.clone()); let execution_start = Instant::now(); - runtime.run(); + runtime.run().unwrap(); let execution_duration = execution_start.elapsed().as_secs_f64(); let config = BabyBearBlake3::new(); let prove_start = Instant::now(); - let _proof = prove_core(config.clone(), runtime); + let _proof = prove_simple(config.clone(), runtime); let prove_duration = prove_start.elapsed().as_secs_f64(); let verify_start = Instant::now(); @@ -156,12 +156,12 @@ fn run_evaluation(hashfn: &HashFnId, program: &Program, _elf: &[u8]) -> (f64, f6 HashFnId::Poseidon => { let mut runtime = Runtime::new(program.clone()); let execution_start = Instant::now(); - runtime.run(); + runtime.run().unwrap(); let execution_duration = execution_start.elapsed().as_secs_f64(); let config = BabyBearPoseidon2::new(); let prove_start = Instant::now(); - let _proof = prove_core(config.clone(), runtime); + let _proof = prove_simple(config.clone(), runtime); let prove_duration = prove_start.elapsed().as_secs_f64(); let verify_start = Instant::now(); @@ -173,12 +173,12 @@ fn run_evaluation(hashfn: &HashFnId, program: &Program, _elf: &[u8]) -> (f64, f6 HashFnId::Keccak256 => { let mut runtime = Runtime::new(program.clone()); let execution_start = Instant::now(); - runtime.run(); + runtime.run().unwrap(); let execution_duration = execution_start.elapsed().as_secs_f64(); let config = BabyBearKeccak::new(); let prove_start = Instant::now(); - let _proof = prove_core(config.clone(), runtime); + let _proof = prove_simple(config.clone(), runtime); let prove_duration = prove_start.elapsed().as_secs_f64(); let verify_start = Instant::now(); diff --git a/prover/Cargo.toml b/prover/Cargo.toml index 4b3d0885f..8c08fa743 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -40,18 +40,7 @@ indicatif = "0.17.8" futures = "0.3.30" subtle-encoding = "0.5.1" serial_test = "3.1.1" - -[[bin]] -name = "fibonacci_sweep" -path = "scripts/fibonacci_sweep.rs" - -[[bin]] -name = "tendermint_sweep" -path = "scripts/tendermint_sweep.rs" - -[[bin]] -name = "fibonacci_groth16" -path = "scripts/fibonacci_groth16.rs" +thiserror = "1.0.60" [[bin]] name = "build_groth16" diff --git a/prover/src/build.rs b/prover/src/build.rs index 0c3325e43..e3b79386e 100644 --- a/prover/src/build.rs +++ b/prover/src/build.rs @@ -75,16 +75,16 @@ pub fn dummy_proof() -> (StarkVerifyingKey, ShardProof) { tracing::info!("prove core"); let mut stdin = SP1Stdin::new(); stdin.write(&500u32); - let core_proof = prover.prove_core(&pk, &stdin); + let core_proof = prover.prove_core(&pk, &stdin).unwrap(); tracing::info!("compress"); - let compressed_proof = prover.compress(&vk, core_proof, vec![]); + let compressed_proof = prover.compress(&vk, core_proof, vec![]).unwrap(); tracing::info!("shrink"); - let shrink_proof = prover.shrink(compressed_proof); + let shrink_proof = prover.shrink(compressed_proof).unwrap(); tracing::info!("wrap"); - let wrapped_proof = prover.wrap_bn254(shrink_proof); + let wrapped_proof = prover.wrap_bn254(shrink_proof).unwrap(); (prover.wrap_vk, wrapped_proof.proof) } diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 5281728cb..266884e7e 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -1,4 +1,4 @@ -//! An end-to-end-prover implementation for SP1. +//! An end-to-end-prover implementation for the SP1 RISC-V zkVM. //! //! Seperates the proof generation process into multiple stages: //! @@ -14,11 +14,13 @@ pub mod build; pub mod install; -mod types; +pub mod types; pub mod utils; -mod verify; +pub mod verify; use std::borrow::Borrow; +use std::env; +use std::path::PathBuf; use crate::utils::RECONSTRUCT_COMMITMENTS_ENV_VAR; use p3_baby_bear::BabyBear; @@ -28,27 +30,23 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::prelude::*; use sp1_core::air::PublicValues; pub use sp1_core::io::{SP1PublicValues, SP1Stdin}; -use sp1_core::runtime::Runtime; -use sp1_core::stark::MachineVerificationError; -use sp1_core::stark::{Challenge, StarkProvingKey}; -use sp1_core::utils::DIGEST_SIZE; +use sp1_core::runtime::{ExecutionError, Runtime}; +use sp1_core::stark::{Challenge, MachineVerificationError, StarkProvingKey}; use sp1_core::{ runtime::Program, stark::{ LocalProver, RiscvAir, ShardProof, StarkGenericConfig, StarkMachine, StarkVerifyingKey, Val, }, - utils::{run_and_prove, BabyBearPoseidon2}, + utils::{BabyBearPoseidon2, SP1CoreProverError, DIGEST_SIZE}, }; use sp1_primitives::hash_deferred_proof; use sp1_recursion_circuit::witness::Witnessable; -use sp1_recursion_compiler::config::InnerConfig; -use sp1_recursion_compiler::config::OuterConfig; +use sp1_recursion_compiler::config::{InnerConfig, OuterConfig}; use sp1_recursion_compiler::ir::Witness; -use sp1_recursion_core::runtime::RecursionProgram; -use sp1_recursion_core::stark::RecursionAir; use sp1_recursion_core::{ - air::RecursionPublicValues, runtime::Runtime as RecursionRuntime, - stark::config::BabyBearPoseidon2Outer, + air::RecursionPublicValues, + runtime::{RecursionProgram, Runtime as RecursionRuntime}, + stark::{config::BabyBearPoseidon2Outer, RecursionAir}, }; pub use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof; use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Prover; @@ -60,8 +58,6 @@ use sp1_recursion_program::machine::{ SP1RecursionMemoryLayout, SP1RecursiveVerifier, SP1ReduceMemoryLayout, SP1RootMemoryLayout, SP1RootVerifier, }; -use std::env; -use std::path::PathBuf; use tracing::instrument; pub use types::*; use utils::words_to_bytes; @@ -83,7 +79,7 @@ pub type ReduceAir = RecursionAir; pub type CompressAir = RecursionAir; pub type WrapAir = RecursionAir; -/// A end-to-end prover implementation for SP1. +/// A end-to-end prover implementation for the SP1 RISC-V zkVM. pub struct SP1Prover { /// The program that can recursively verify a set of proofs into a single proof. pub recursion_program: RecursionProgram, @@ -217,30 +213,34 @@ impl SP1Prover { /// Generate a proof of an SP1 program with the specified inputs. #[instrument(name = "execute", level = "info", skip_all)] - pub fn execute(elf: &[u8], stdin: &SP1Stdin) -> SP1PublicValues { + pub fn execute(elf: &[u8], stdin: &SP1Stdin) -> Result { let program = Program::from(elf); let mut runtime = Runtime::new(program); runtime.write_vecs(&stdin.buffer); for (proof, vkey) in stdin.proofs.iter() { runtime.write_proof(proof.clone(), vkey.clone()); } - runtime.run(); - SP1PublicValues::from(&runtime.state.public_values_stream) + runtime.run()?; + Ok(SP1PublicValues::from(&runtime.state.public_values_stream)) } /// Generate shard proofs which split up and prove the valid execution of a RISC-V program with /// the core prover. #[instrument(name = "prove_core", level = "info", skip_all)] - pub fn prove_core(&self, pk: &SP1ProvingKey, stdin: &SP1Stdin) -> SP1CoreProof { + pub fn prove_core( + &self, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + ) -> Result { let config = CoreSC::default(); let program = Program::from(&pk.elf); - let (proof, public_values_stream) = run_and_prove(program, stdin, config); + let (proof, public_values_stream) = sp1_core::utils::prove(program, stdin, config)?; let public_values = SP1PublicValues::from(&public_values_stream); - SP1CoreProof { + Ok(SP1CoreProof { proof: SP1CoreProofData(proof.shard_proofs), stdin: stdin.clone(), public_values, - } + }) } /// Reduce shards proofs to a single shard proof using the recursion prover. @@ -250,10 +250,8 @@ impl SP1Prover { vk: &SP1VerifyingKey, proof: SP1CoreProof, deferred_proofs: Vec>, - ) -> SP1ReduceProof { - // Set the batch size for the reduction tree. + ) -> Result, SP1RecursionProverError> { let batch_size = 2; - let shard_proofs = &proof.proof.0; // Setup the reconstruct commitments flags to false and save its state. @@ -267,11 +265,10 @@ impl SP1Prover { leaf_challenger.observe(proof.commitment.main_commit); leaf_challenger.observe_slice(&proof.public_values[0..self.core_machine.num_pv_elts()]); }); + // Make sure leaf challenger is not mutable anymore. let leaf_challenger = leaf_challenger; - let mut core_inputs = Vec::new(); - let mut reconstruct_challenger = self.core_machine.config().challenger(); vk.vk.observe_into(&mut reconstruct_challenger); @@ -460,14 +457,17 @@ impl SP1Prover { // Restore the prover parameters. env::set_var(RECONSTRUCT_COMMITMENTS_ENV_VAR, rc); - SP1ReduceProof { + Ok(SP1ReduceProof { proof: reduce_proof.0, - } + }) } /// Wrap a reduce proof into a STARK proven over a SNARK-friendly field. #[instrument(name = "shrink", level = "info", skip_all)] - pub fn shrink(&self, reduced_proof: SP1ReduceProof) -> SP1ReduceProof { + pub fn shrink( + &self, + reduced_proof: SP1ReduceProof, + ) -> Result, SP1RecursionProverError> { // Setup the prover parameters. let rc = env::var(RECONSTRUCT_COMMITMENTS_ENV_VAR).unwrap_or_default(); env::set_var(RECONSTRUCT_COMMITMENTS_ENV_VAR, "false"); @@ -504,14 +504,17 @@ impl SP1Prover { // Restore the prover parameters. env::set_var(RECONSTRUCT_COMMITMENTS_ENV_VAR, rc); - SP1ReduceProof { + Ok(SP1ReduceProof { proof: compress_proof.shard_proofs.pop().unwrap(), - } + }) } /// Wrap a reduce proof into a STARK proven over a SNARK-friendly field. #[instrument(name = "wrap_bn254", level = "info", skip_all)] - pub fn wrap_bn254(&self, compressed_proof: SP1ReduceProof) -> SP1ReduceProof { + pub fn wrap_bn254( + &self, + compressed_proof: SP1ReduceProof, + ) -> Result, SP1RecursionProverError> { // Setup the prover parameters. let rc = env::var(RECONSTRUCT_COMMITMENTS_ENV_VAR).unwrap_or_default(); env::set_var(RECONSTRUCT_COMMITMENTS_ENV_VAR, "false"); @@ -562,9 +565,9 @@ impl SP1Prover { // Restore the prover parameters. env::set_var(RECONSTRUCT_COMMITMENTS_ENV_VAR, rc); - SP1ReduceProof { + Ok(SP1ReduceProof { proof: wrap_proof.shard_proofs.pop().unwrap(), - } + }) } /// Wrap the STARK proven over a SNARK-friendly field into a Groth16 proof. @@ -624,9 +627,10 @@ mod tests { use std::fs::File; use std::io::{Read, Write}; + use super::*; use crate::build::{build_groth16_artifacts, get_groth16_artifacts_dir}; - use super::*; + use anyhow::Result; use p3_field::PrimeField32; use serial_test::serial; use sp1_core::io::SP1Stdin; @@ -636,7 +640,7 @@ mod tests { /// pipeline. #[test] #[serial] - fn test_e2e() { + fn test_e2e() -> Result<()> { setup_logger(); let elf = include_bytes!("../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); @@ -648,25 +652,25 @@ mod tests { tracing::info!("prove core"); let stdin = SP1Stdin::new(); - let core_proof = prover.prove_core(&pk, &stdin); + let core_proof = prover.prove_core(&pk, &stdin)?; tracing::info!("verify core"); - prover.verify(&core_proof.proof, &vk).unwrap(); + prover.verify(&core_proof.proof, &vk)?; tracing::info!("compress"); - let compressed_proof = prover.compress(&vk, core_proof, vec![]); + let compressed_proof = prover.compress(&vk, core_proof, vec![])?; tracing::info!("verify compressed"); - prover.verify_compressed(&compressed_proof, &vk).unwrap(); + prover.verify_compressed(&compressed_proof, &vk)?; tracing::info!("shrink"); - let shrink_proof = prover.shrink(compressed_proof); + let shrink_proof = prover.shrink(compressed_proof)?; tracing::info!("verify shrink"); - prover.verify_shrink(&shrink_proof, &vk).unwrap(); + prover.verify_shrink(&shrink_proof, &vk)?; tracing::info!("wrap bn254"); - let wrapped_bn254_proof = prover.wrap_bn254(shrink_proof); + let wrapped_bn254_proof = prover.wrap_bn254(shrink_proof)?; let bytes = bincode::serialize(&wrapped_bn254_proof).unwrap(); // Save the proof. @@ -696,13 +700,15 @@ mod tests { build_groth16_artifacts(&prover.wrap_vk, &wrapped_bn254_proof.proof, &artifacts_dir); let groth16_proof = prover.wrap_groth16(wrapped_bn254_proof, artifacts_dir); println!("{:?}", groth16_proof); + + Ok(()) } /// Tests an end-to-end workflow of proving a program across the entire proof generation /// pipeline in addition to verifying deferred proofs. #[test] #[serial] - fn test_e2e_with_deferred_proofs() { + fn test_e2e_with_deferred_proofs() -> Result<()> { setup_logger(); // Test program which proves the Keccak-256 hash of various inputs. @@ -724,7 +730,7 @@ mod tests { let mut stdin = SP1Stdin::new(); stdin.write(&1usize); stdin.write(&vec![0u8, 0, 0]); - let deferred_proof_1 = prover.prove_core(&keccak_pk, &stdin); + let deferred_proof_1 = prover.prove_core(&keccak_pk, &stdin)?; let pv_1 = deferred_proof_1.public_values.as_slice().to_vec().clone(); // Generate a second proof of keccak of various inputs. @@ -734,16 +740,16 @@ mod tests { stdin.write(&vec![0u8, 1, 2]); stdin.write(&vec![2, 3, 4]); stdin.write(&vec![5, 6, 7]); - let deferred_proof_2 = prover.prove_core(&keccak_pk, &stdin); + let deferred_proof_2 = prover.prove_core(&keccak_pk, &stdin)?; let pv_2 = deferred_proof_2.public_values.as_slice().to_vec().clone(); // Generate recursive proof of first subproof. tracing::info!("compress subproof 1"); - let deferred_reduce_1 = prover.compress(&keccak_vk, deferred_proof_1, vec![]); + let deferred_reduce_1 = prover.compress(&keccak_vk, deferred_proof_1, vec![])?; // Generate recursive proof of second subproof. tracing::info!("compress subproof 2"); - let deferred_reduce_2 = prover.compress(&keccak_vk, deferred_proof_2, vec![]); + let deferred_reduce_2 = prover.compress(&keccak_vk, deferred_proof_2, vec![])?; // Run verify program with keccak vkey, subproofs, and their committed values. let mut stdin = SP1Stdin::new(); @@ -761,7 +767,7 @@ mod tests { stdin.write_proof(deferred_reduce_2.proof.clone(), keccak_vk.vk.clone()); tracing::info!("proving verify program (core)"); - let verify_proof = prover.prove_core(&verify_pk, &stdin); + let verify_proof = prover.prove_core(&verify_pk, &stdin)?; // Generate recursive proof of verify program tracing::info!("compress verify program"); @@ -773,15 +779,15 @@ mod tests { deferred_reduce_2.proof.clone(), deferred_reduce_2.proof, ], - ); + )?; let reduce_pv: &RecursionPublicValues<_> = verify_reduce.proof.public_values.as_slice().borrow(); println!("deferred_hash: {:?}", reduce_pv.deferred_proofs_digest); println!("complete: {:?}", reduce_pv.is_complete); tracing::info!("verify verify program"); - prover - .verify_compressed(&verify_reduce, &verify_vk) - .unwrap(); + prover.verify_compressed(&verify_reduce, &verify_vk)?; + + Ok(()) } } diff --git a/prover/src/types.rs b/prover/src/types.rs index 547eac770..94ffcc3ce 100644 --- a/prover/src/types.rs +++ b/prover/src/types.rs @@ -16,6 +16,7 @@ use sp1_core::{ use sp1_primitives::poseidon2_hash; use sp1_recursion_core::{air::RecursionPublicValues, stark::config::BabyBearPoseidon2Outer}; use sp1_recursion_gnark_ffi::{plonk_bn254::PlonkBn254Proof, Groth16Proof}; +use thiserror::Error; use crate::utils::words_to_bytes_be; use crate::{utils::babybear_bytes_to_bn254, words_to_bytes}; @@ -194,3 +195,6 @@ pub enum SP1ReduceProofWrapper { Core(SP1ReduceProof), Recursive(SP1ReduceProof), } + +#[derive(Error, Debug)] +pub enum SP1RecursionProverError {} diff --git a/recursion/program/src/constraints.rs b/recursion/program/src/constraints.rs index c7ab21108..01ec47718 100644 --- a/recursion/program/src/constraints.rs +++ b/recursion/program/src/constraints.rs @@ -284,7 +284,7 @@ mod tests { let (_, vk) = machine.setup(&Program::from(elf)); let mut challenger = machine.config().challenger(); let (proof, _) = - sp1_core::utils::run_and_prove(Program::from(elf), &SP1Stdin::new(), SC::default()); + sp1_core::utils::prove(Program::from(elf), &SP1Stdin::new(), SC::default()).unwrap(); machine.verify(&vk, &proof, &mut challenger).unwrap(); println!("Proof generated and verified successfully"); diff --git a/recursion/program/src/machine/mod.rs b/recursion/program/src/machine/mod.rs index 2d262332a..a298427d4 100644 --- a/recursion/program/src/machine/mod.rs +++ b/recursion/program/src/machine/mod.rs @@ -82,7 +82,7 @@ mod tests { let mut challenger = machine.config().challenger(); let time = std::time::Instant::now(); - let (proof, _) = sp1_core::utils::run_and_prove(program, &SP1Stdin::new(), SC::default()); + let (proof, _) = sp1_core::utils::prove(program, &SP1Stdin::new(), SC::default()).unwrap(); machine.verify(&vk, &proof, &mut challenger).unwrap(); tracing::info!("Proof generated successfully"); let elapsed = time.elapsed(); diff --git a/recursion/program/src/stark.rs b/recursion/program/src/stark.rs index cd59a8804..9f43af62f 100644 --- a/recursion/program/src/stark.rs +++ b/recursion/program/src/stark.rs @@ -447,7 +447,7 @@ pub(crate) mod tests { let (_, vk) = machine.setup(&Program::from(elf)); let mut challenger_val = machine.config().challenger(); let (proof, _) = - sp1_core::utils::run_and_prove(Program::from(elf), &SP1Stdin::new(), SC::default()); + sp1_core::utils::prove(Program::from(elf), &SP1Stdin::new(), SC::default()).unwrap(); let proofs = proof.shard_proofs; println!("Proof generated successfully"); diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 7d4e47cc0..7a53636ec 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -173,7 +173,7 @@ impl ProverClient { /// let public_values = client.execute(elf, stdin).unwrap(); /// ``` pub fn execute(&self, elf: &[u8], stdin: SP1Stdin) -> Result { - Ok(SP1Prover::execute(elf, &stdin)) + Ok(SP1Prover::execute(elf, &stdin)?) } /// Setup a program to be proven and verified by the SP1 RISC-V zkVM by computing the proving @@ -473,7 +473,18 @@ mod tests { include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); - let _ = client.execute(elf, stdin).unwrap(); + client.execute(elf, stdin).unwrap(); + } + + #[test] + #[should_panic] + fn test_execute_panic() { + utils::setup_logger(); + let client = ProverClient::local(); + let elf = include_bytes!("../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); + let mut stdin = SP1Stdin::new(); + stdin.write(&10usize); + client.execute(elf, stdin).unwrap(); } #[test] diff --git a/sdk/src/provers/local.rs b/sdk/src/provers/local.rs index 3c062bdee..5136de43b 100644 --- a/sdk/src/provers/local.rs +++ b/sdk/src/provers/local.rs @@ -33,7 +33,7 @@ impl Prover for LocalProver { } fn prove(&self, pk: &SP1ProvingKey, stdin: SP1Stdin) -> Result { - let proof = self.prover.prove_core(pk, &stdin); + let proof = self.prover.prove_core(pk, &stdin)?; Ok(SP1ProofWithPublicValues { proof: proof.proof.0, stdin: proof.stdin, @@ -42,10 +42,10 @@ impl Prover for LocalProver { } fn prove_compressed(&self, pk: &SP1ProvingKey, stdin: SP1Stdin) -> Result { - let proof = self.prover.prove_core(pk, &stdin); + let proof = self.prover.prove_core(pk, &stdin)?; let deferred_proofs = stdin.proofs.iter().map(|p| p.0.clone()).collect(); let public_values = proof.public_values.clone(); - let reduce_proof = self.prover.compress(&pk.vk, proof, deferred_proofs); + let reduce_proof = self.prover.compress(&pk.vk, proof, deferred_proofs)?; Ok(SP1CompressedProof { proof: reduce_proof.proof, stdin, @@ -56,12 +56,12 @@ impl Prover for LocalProver { fn prove_groth16(&self, pk: &SP1ProvingKey, stdin: SP1Stdin) -> Result { sp1_prover::build::get_groth16_artifacts_dir(); - let proof = self.prover.prove_core(pk, &stdin); + let proof = self.prover.prove_core(pk, &stdin)?; let deferred_proofs = stdin.proofs.iter().map(|p| p.0.clone()).collect(); let public_values = proof.public_values.clone(); - let reduce_proof = self.prover.compress(&pk.vk, proof, deferred_proofs); - let compress_proof = self.prover.shrink(reduce_proof); - let outer_proof = self.prover.wrap_bn254(compress_proof); + let reduce_proof = self.prover.compress(&pk.vk, proof, deferred_proofs)?; + let compress_proof = self.prover.shrink(reduce_proof)?; + let outer_proof = self.prover.wrap_bn254(compress_proof)?; let artifacts_dir = sp1_prover::build::get_groth16_artifacts_dir(); let proof = self.prover.wrap_groth16(outer_proof, artifacts_dir); Ok(SP1ProofWithPublicValues { diff --git a/sdk/src/provers/mock.rs b/sdk/src/provers/mock.rs index addb91b25..9f25eafd3 100644 --- a/sdk/src/provers/mock.rs +++ b/sdk/src/provers/mock.rs @@ -33,7 +33,7 @@ impl Prover for MockProver { } fn prove(&self, pk: &SP1ProvingKey, stdin: SP1Stdin) -> Result { - let public_values = SP1Prover::execute(&pk.elf, &stdin); + let public_values = SP1Prover::execute(&pk.elf, &stdin)?; Ok(SP1ProofWithPublicValues { proof: vec![], stdin, diff --git a/tests/panic/Cargo.lock b/tests/panic/Cargo.lock new file mode 100644 index 000000000..9a09c235c --- /dev/null +++ b/tests/panic/Cargo.lock @@ -0,0 +1,748 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "tap", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "panic-test" +version = "0.1.0" +dependencies = [ + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.201" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.201" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.63", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "sp1-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-precompiles" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "getrandom", + "hex", + "k256", + "num", + "rand", + "serde", + "snowbridge-amcl", +] + +[[package]] +name = "sp1-zkvm" +version = "0.1.0" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "k256", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-precompiles", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/tests/panic/Cargo.toml b/tests/panic/Cargo.toml new file mode 100644 index 000000000..c81641abb --- /dev/null +++ b/tests/panic/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] +[package] +name = "panic-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } diff --git a/tests/panic/elf/riscv32im-succinct-zkvm-elf b/tests/panic/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 000000000..8f81cde6d Binary files /dev/null and b/tests/panic/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/panic/src/main.rs b/tests/panic/src/main.rs new file mode 100644 index 000000000..cae572d07 --- /dev/null +++ b/tests/panic/src/main.rs @@ -0,0 +1,6 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +pub fn main() { + assert_eq!(0, 1); +}