diff --git a/stwo_cairo_prover/crates/prover/src/input/builtins_segments.rs b/stwo_cairo_prover/crates/prover/src/input/builtins_segments.rs new file mode 100644 index 00000000..61eac464 --- /dev/null +++ b/stwo_cairo_prover/crates/prover/src/input/builtins_segments.rs @@ -0,0 +1,145 @@ +use std::collections::HashMap; + +use cairo_vm::air_public_input::MemorySegmentAddresses; + +// TODO(STAV): Understand if the adapter should pass builtins that won't be supported by stwo. +/// This struct holds the builtins used in a Cairo program. +/// Most of them are not implemented yet by Stwo. +#[derive(Debug)] +pub struct BuiltinsSegments { + pub range_check_bits_128_builtin: MemorySegmentAddresses, + pub range_check_bits_96_builtin: MemorySegmentAddresses, + pub bitwise_builtin: MemorySegmentAddresses, + pub add_mod_builtin: MemorySegmentAddresses, + pub ec_op_builtin: MemorySegmentAddresses, + pub ecdsa_builtin: MemorySegmentAddresses, + pub keccak_builtin: MemorySegmentAddresses, + pub mul_mod_builtin: MemorySegmentAddresses, + pub pedersen_builtin: MemorySegmentAddresses, + pub poseidon_builtin: MemorySegmentAddresses, +} + +impl Default for BuiltinsSegments { + fn default() -> Self { + Self { + range_check_bits_128_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + range_check_bits_96_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + bitwise_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + add_mod_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + ec_op_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + ecdsa_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + keccak_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + mul_mod_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + pedersen_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + poseidon_builtin: MemorySegmentAddresses { + begin_addr: 0, + stop_ptr: 0, + }, + } + } +} +impl BuiltinsSegments { + /// Create a new `BuiltinsSegments` struct from a map of memory MemorySegmentAddressess. + pub fn from_memory_segments( + memory_segments: &HashMap<&str, cairo_vm::air_public_input::MemorySegmentAddresses>, + ) -> Self { + let mut res = Self::default(); + for (name, value) in memory_segments.iter() { + match *name { + "range_check" => { + res.range_check_bits_128_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "range_check96" => { + res.range_check_bits_96_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "bitwise" => { + res.bitwise_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "add_mod" => { + res.add_mod_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "ec_op" => { + res.ec_op_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "ecdsa" => { + res.ecdsa_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "keccak" => { + res.keccak_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "mul_mod" => { + res.mul_mod_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "pedersen" => { + res.pedersen_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + "poseidon" => { + res.poseidon_builtin = MemorySegmentAddresses { + begin_addr: value.begin_addr, + stop_ptr: value.stop_ptr, + } + } + // Output, executaion and program segments are not builtins. + "output" => {} + "execution" => {} + "program" => {} + _ => panic!("Unknown memory segment: {name}"), + } + } + res + } +} diff --git a/stwo_cairo_prover/crates/prover/src/input/mod.rs b/stwo_cairo_prover/crates/prover/src/input/mod.rs index be6994cf..36a35567 100644 --- a/stwo_cairo_prover/crates/prover/src/input/mod.rs +++ b/stwo_cairo_prover/crates/prover/src/input/mod.rs @@ -1,7 +1,8 @@ -use cairo_vm::air_public_input::MemorySegmentAddresses; +use builtins_segments::BuiltinsSegments; use mem::Memory; use state_transitions::StateTransitions; +pub mod builtins_segments; mod decode; pub mod mem; pub mod plain; @@ -19,5 +20,5 @@ pub struct CairoInput { pub public_mem_addresses: Vec, // Builtins. - pub range_check_builtin: MemorySegmentAddresses, + pub builtins_segments: BuiltinsSegments, } diff --git a/stwo_cairo_prover/crates/prover/src/input/plain.rs b/stwo_cairo_prover/crates/prover/src/input/plain.rs index 7f9b3d6e..ff6817b0 100644 --- a/stwo_cairo_prover/crates/prover/src/input/plain.rs +++ b/stwo_cairo_prover/crates/prover/src/input/plain.rs @@ -9,8 +9,7 @@ use itertools::Itertools; use super::mem::{MemConfig, MemoryBuilder}; use super::state_transitions::StateTransitions; use super::vm_import::MemEntry; -use super::CairoInput; -use crate::input::MemorySegmentAddresses; +use super::{BuiltinsSegments, CairoInput}; // TODO(Ohad): remove dev_mode after adding the rest of the opcodes. /// Translates a plain casm into a CairoInput by running the program and extracting the memory and @@ -71,22 +70,25 @@ pub fn input_from_finished_runner(runner: CairoRunner, dev_mode: bool) -> CairoI val: bytemuck::cast(v.to_bytes_le()), }) }); - let trace = runner.relocated_trace.unwrap(); + let trace = runner.relocated_trace.clone().unwrap(); let trace = trace.iter().map(|t| t.clone().into()); let mem_config = MemConfig::default(); let mut mem = MemoryBuilder::from_iter(mem_config, mem); let state_transitions = StateTransitions::from_iter(trace, &mut mem, dev_mode); + let public_input = runner + .get_air_public_input() + .expect("Unable to get public input from the runner"); + + let builtins_segments = BuiltinsSegments::from_memory_segments(&public_input.memory_segments); + // TODO(spapini): Add output builtin to public memory. let public_mem_addresses = (0..(program_len as u32)).collect_vec(); CairoInput { state_transitions, mem: mem.build(), public_mem_addresses, - range_check_builtin: MemorySegmentAddresses { - begin_addr: 24, - stop_ptr: 64, - }, + builtins_segments, } } diff --git a/stwo_cairo_prover/crates/prover/src/input/vm_import/mod.rs b/stwo_cairo_prover/crates/prover/src/input/vm_import/mod.rs index 6d038455..1b0b0c23 100644 --- a/stwo_cairo_prover/crates/prover/src/input/vm_import/mod.rs +++ b/stwo_cairo_prover/crates/prover/src/input/vm_import/mod.rs @@ -4,6 +4,8 @@ use std::io::Read; use std::path::Path; use bytemuck::{bytes_of_mut, Pod, Zeroable}; +#[cfg(test)] +use cairo_vm::air_public_input::MemorySegmentAddresses; use cairo_vm::air_public_input::PublicInput; use cairo_vm::vm::trace::trace_entry::RelocatedTraceEntry; use json::PrivateInput; @@ -14,7 +16,7 @@ use super::mem::MemConfig; use super::state_transitions::StateTransitions; use super::CairoInput; use crate::input::mem::MemoryBuilder; -use crate::input::MemorySegmentAddresses; +use crate::input::BuiltinsSegments; #[derive(Debug, Error)] pub enum VmImportError { @@ -58,14 +60,13 @@ pub fn import_from_vm_output( .map(|entry| entry.address as u32) .collect(); + let builtins_segments = BuiltinsSegments::from_memory_segments(&pub_data.memory_segments); + Ok(CairoInput { state_transitions, mem: mem.build(), public_mem_addresses, - range_check_builtin: MemorySegmentAddresses { - begin_addr: pub_data.memory_segments["range_check"].begin_addr as usize, - stop_ptr: pub_data.memory_segments["range_check"].stop_ptr as usize, - }, + builtins_segments, }) } @@ -152,11 +153,12 @@ pub mod tests { // TODO (Stav): Once all the components are in, verify the proof to ensure the sort was correct. // TODO (Ohad): remove the following doc after deleting dev_mod. - /// When not ignored, the test passes only with dev_mod = false. #[ignore] #[test] fn test_read_from_large_files() { let input = large_cairo_input(); + + // Check opcode components. let components = input.state_transitions.casm_states_by_opcode; assert_eq!(components.generic_opcode.len(), 0); assert_eq!(components.add_ap_opcode_is_imm_f_op1_base_fp_f.len(), 0); @@ -209,18 +211,93 @@ pub mod tests { .len(), 0 ); - assert_eq!(components.mul_opcode_is_small_t_is_imm_t.len(), 8996); - assert_eq!(components.mul_opcode_is_small_t_is_imm_f.len(), 6563); - assert_eq!(components.mul_opcode_is_small_f_is_imm_f.len(), 4583); - assert_eq!(components.mul_opcode_is_small_f_is_imm_t.len(), 9047); + // TODO(Ohad): update counts after adding mull small. + assert_eq!(components.mul_opcode_is_small_t_is_imm_t.len(), 0); + assert_eq!(components.mul_opcode_is_small_t_is_imm_f.len(), 0); + assert_eq!(components.mul_opcode_is_small_f_is_imm_f.len(), 11146); + assert_eq!(components.mul_opcode_is_small_f_is_imm_t.len(), 18043); assert_eq!(components.ret_opcode.len(), 49472); + + // Check builtins + let builtins = input.builtins_segments; + assert_eq!( + builtins.range_check_bits_128_builtin, + MemorySegmentAddresses { + begin_addr: 1715768, + stop_ptr: 1757348 + } + ); + assert_eq!( + builtins.range_check_bits_96_builtin, + MemorySegmentAddresses { + begin_addr: 17706552, + stop_ptr: 17706552 + } + ); + assert_eq!( + builtins.bitwise_builtin, + MemorySegmentAddresses { + begin_addr: 5942840, + stop_ptr: 5942840 + } + ); + assert_eq!( + builtins.add_mod_builtin, + MemorySegmentAddresses { + begin_addr: 21900856, + stop_ptr: 21900856 + } + ); + assert_eq!( + builtins.ec_op_builtin, + MemorySegmentAddresses { + begin_addr: 16428600, + stop_ptr: 16428747 + } + ); + assert_eq!( + builtins.ecdsa_builtin, + MemorySegmentAddresses { + begin_addr: 5910072, + stop_ptr: 5910072 + } + ); + assert_eq!( + builtins.keccak_builtin, + MemorySegmentAddresses { + begin_addr: 16657976, + stop_ptr: 16657976 + } + ); + assert_eq!( + builtins.mul_mod_builtin, + MemorySegmentAddresses { + begin_addr: 23735864, + stop_ptr: 23735864 + } + ); + assert_eq!( + builtins.pedersen_builtin, + MemorySegmentAddresses { + begin_addr: 1322552, + stop_ptr: 1337489 + } + ); + assert_eq!( + builtins.poseidon_builtin, + MemorySegmentAddresses { + begin_addr: 16920120, + stop_ptr: 17444532 + } + ); } - // When not ignored, the test passes only with dev_mod = false. #[ignore] #[test] fn test_read_from_small_files() { let input = small_cairo_input(); + + // Check opcode components. let components = input.state_transitions.casm_states_by_opcode; assert_eq!(components.generic_opcode.len(), 0); assert_eq!(components.add_ap_opcode_is_imm_f_op1_base_fp_f.len(), 0); @@ -278,5 +355,78 @@ pub mod tests { assert_eq!(components.mul_opcode_is_small_f_is_imm_f.len(), 0); assert_eq!(components.mul_opcode_is_small_f_is_imm_t.len(), 0); assert_eq!(components.ret_opcode.len(), 462); + + // Check builtins + let builtins = input.builtins_segments; + assert_eq!( + builtins.range_check_bits_128_builtin, + MemorySegmentAddresses { + begin_addr: 6000, + stop_ptr: 6050 + } + ); + assert_eq!( + builtins.range_check_bits_96_builtin, + MemorySegmentAddresses { + begin_addr: 68464, + stop_ptr: 68514 + } + ); + assert_eq!( + builtins.bitwise_builtin, + MemorySegmentAddresses { + begin_addr: 22512, + stop_ptr: 22762 + } + ); + assert_eq!( + builtins.add_mod_builtin, + MemorySegmentAddresses { + begin_addr: 84848, + stop_ptr: 84848 + } + ); + assert_eq!( + builtins.ec_op_builtin, + MemorySegmentAddresses { + begin_addr: 63472, + stop_ptr: 63822 + } + ); + assert_eq!( + builtins.ecdsa_builtin, + MemorySegmentAddresses { + begin_addr: 22384, + stop_ptr: 22484 + } + ); + assert_eq!( + builtins.keccak_builtin, + MemorySegmentAddresses { + begin_addr: 64368, + stop_ptr: 65168 + } + ); + assert_eq!( + builtins.mul_mod_builtin, + MemorySegmentAddresses { + begin_addr: 92016, + stop_ptr: 92016 + } + ); + assert_eq!( + builtins.pedersen_builtin, + MemorySegmentAddresses { + begin_addr: 4464, + stop_ptr: 4614 + } + ); + assert_eq!( + builtins.poseidon_builtin, + MemorySegmentAddresses { + begin_addr: 65392, + stop_ptr: 65692 + } + ); } }