From 974e62185f359050d142ab2c3c95963385975f89 Mon Sep 17 00:00:00 2001 From: Ohad Nir <141617878+ohad-nir-starkware@users.noreply.github.com> Date: Tue, 11 Feb 2025 20:35:59 +0200 Subject: [PATCH] add get_u32_range to impl VirtualMachine add get_u32 and get_u32_range to impl Memory (#1936) --- CHANGELOG.md | 2 ++ vm/src/vm/vm_core.rs | 39 +++++++++++++++++++++ vm/src/vm/vm_memory/memory.rs | 66 +++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95cfd2d722..c8b21c95a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ #### Upcoming Changes +* feat: add `get_u32_range` to `impl VirtualMachine` add `get_u32` and `get_u32_range` to `impl Memory` [#1936](https://github.com/lambdaclass/cairo-vm/pull/1936) + * feat: add the field `opcode_extension` to the structure of `Instruction` [#1933](https://github.com/lambdaclass/cairo-vm/pull/1933) * fix(BREAKING): Fix no trace padding flow in proof mode [#1909](https://github.com/lambdaclass/cairo-vm/pull/1909) diff --git a/vm/src/vm/vm_core.rs b/vm/src/vm/vm_core.rs index 0a87ef026f..38fb82d29b 100644 --- a/vm/src/vm/vm_core.rs +++ b/vm/src/vm/vm_core.rs @@ -929,6 +929,12 @@ impl VirtualMachine { self.segments.memory.get_integer_range(addr, size) } + /// Gets n u32 values from memory starting from addr (n being size). + /// Returns an error if any of the values inside the range is missing (memory gap) or is not a u32. + pub fn get_u32_range(&self, addr: Relocatable, size: usize) -> Result, MemoryError> { + self.segments.memory.get_u32_range(addr, size) + } + pub fn get_range_check_builtin( &self, ) -> Result<&RangeCheckBuiltinRunner, VirtualMachineError> { @@ -4373,6 +4379,39 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_ok() { + let mut vm = vm!(); + vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967295), ((0, 3), 3)]; + let expected_vector = vec![1, 4294967295]; + assert_eq!(vm.get_u32_range((0, 1).into(), 2), Ok(expected_vector)); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_relocatable() { + let mut vm = vm!(); + vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), (0, 0)), ((0, 3), 3)]; + assert_matches!(vm.get_u32_range((0, 1).into(), 2), Err(MemoryError::ExpectedInteger(bx)) if *bx == (0, 2).into()); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_over_32_bits() { + let mut vm = vm!(); + vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967296), ((0, 3), 3)]; + assert_matches!(vm.get_u32_range((0, 1).into(), 2), Err(MemoryError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(4294967296_u64)); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_memory_gap() { + let mut vm = vm!(); + vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 3), 3)]; + assert_matches!(vm.get_u32_range((0, 1).into(), 3), Err(MemoryError::UnknownMemoryCell(bx)) if *bx == (0, 2).into()); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_traceback_entries_bad_usort() { diff --git a/vm/src/vm/vm_memory/memory.rs b/vm/src/vm/vm_memory/memory.rs index affd0a06d4..9a20b60d05 100644 --- a/vm/src/vm/vm_memory/memory.rs +++ b/vm/src/vm/vm_memory/memory.rs @@ -414,6 +414,14 @@ impl Memory { } } + /// Gets a u32 value from memory address. + /// Returns an Error if the value at the memory address is missing or not a u32. + pub fn get_u32(&self, key: Relocatable) -> Result { + let felt = self.get_integer(key)?.into_owned(); + felt.to_u32() + .ok_or_else(|| MemoryError::Math(MathError::Felt252ToU32Conversion(Box::new(felt)))) + } + /// Gets the value from memory address as a usize. /// Returns an Error if the value at the memory address is missing not a Felt252, or can't be converted to usize. pub fn get_usize(&self, key: Relocatable) -> Result { @@ -623,6 +631,18 @@ impl Memory { Ok(values) } + /// Gets a range of u32 memory values from addr to addr + size + /// Fails if any of the values inside the range is missing (memory gap) or is not a u32 + pub fn get_u32_range(&self, addr: Relocatable, size: usize) -> Result, MemoryError> { + let mut values = Vec::new(); + + for i in 0..size { + values.push(self.get_u32((addr + i)?)?); + } + + Ok(values) + } + pub fn mark_as_accessed(&mut self, addr: Relocatable) { let (i, j) = from_relocatable_to_indexes(addr); let data = if addr.segment_index < 0 { @@ -1135,6 +1155,23 @@ mod memory_tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_too_big() { + let mut segments = MemorySegmentManager::new(); + segments.add(); + segments + .memory + .insert(Relocatable::from((0, 0)), &Felt252::from(1_u64 << 32)) + .unwrap(); + assert_matches!( + segments.memory.get_u32(Relocatable::from((0, 0))), + Err(MemoryError::Math(MathError::Felt252ToU32Conversion( + bx + ))) if *bx == Felt252::from(1_u64 << 32) + ); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn default_memory() { @@ -1350,6 +1387,35 @@ mod memory_tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_ok() { + let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967295), ((0, 3), 3)]; + let expected_vector = vec![1, 4294967295]; + assert_eq!(memory.get_u32_range((0, 1).into(), 2), Ok(expected_vector)); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_relocatable() { + let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), (0, 0)), ((0, 3), 3)]; + assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::ExpectedInteger(bx)) if *bx == (0, 2).into()); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_over_32_bits() { + let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967296), ((0, 3), 3)]; + assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(4294967296_u64)); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_u32_range_memory_gap() { + let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 3), 3)]; + assert_matches!(memory.get_u32_range((0, 1).into(), 3), Err(MemoryError::UnknownMemoryCell(bx)) if *bx == (0, 2).into()); + } + /// Test that relocate_memory() works when there are no relocation rules. #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]