From 1a46c9fb20c33148315d316be344fe410a06af73 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:30:13 -0300 Subject: [PATCH] Implement `extend_additional_data` for `BuiltinRunner` (#1726) * Implement extend_additional_data for hash * Handle check * Simplify * Simplify * Implement extend_additional_data for ecdsa * Add test * Implement extend_additional_data for output * Implement extend_additional_data for enum * Add changelog entry * Add doc comments to get_additional_data & extend_additional_data --- CHANGELOG.md | 2 + vm/src/vm/errors/runner_errors.rs | 2 + vm/src/vm/runners/builtin_runner/hash.rs | 36 +++++++++++- vm/src/vm/runners/builtin_runner/mod.rs | 15 +++++ vm/src/vm/runners/builtin_runner/output.rs | 37 +++++++++++- vm/src/vm/runners/builtin_runner/signature.rs | 56 ++++++++++++++++++- 6 files changed, 145 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06ca7c5b0d..6c15aaa681 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ #### Upcoming Changes +* feat: Implement `extend_additional_data` for `BuiltinRunner`[#1726](https://github.com/lambdaclass/cairo-vm/pull/1726) + * BREAKING: Set dynamic params as null by default on air public input [#1716](https://github.com/lambdaclass/cairo-vm/pull/1716) * `PublicInput` field `layout_params` renamed to `dynamic_params` & type changed from`&'a CairoLayout` to `()`. diff --git a/vm/src/vm/errors/runner_errors.rs b/vm/src/vm/errors/runner_errors.rs index a1ad55bcc4..91392f4f06 100644 --- a/vm/src/vm/errors/runner_errors.rs +++ b/vm/src/vm/errors/runner_errors.rs @@ -126,6 +126,8 @@ pub enum RunnerError { MissingBuiltin(BuiltinName), #[error("The stop pointer of the missing builtin {0} must be 0")] MissingBuiltinStopPtrNotZero(BuiltinName), + #[error("{0}: Invalid additional data")] + InvalidAdditionalData(BuiltinName), } #[cfg(test)] diff --git a/vm/src/vm/runners/builtin_runner/hash.rs b/vm/src/vm/runners/builtin_runner/hash.rs index 225b779d82..2ed138ec4d 100644 --- a/vm/src/vm/runners/builtin_runner/hash.rs +++ b/vm/src/vm/runners/builtin_runner/hash.rs @@ -1,5 +1,6 @@ use crate::air_private_input::{PrivateInput, PrivateInputPair}; use crate::stdlib::{cell::RefCell, prelude::*}; +use crate::types::builtin_name::BuiltinName; use crate::types::instance_definitions::pedersen_instance_def::CELLS_PER_HASH; use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::errors::memory_errors::MemoryError; @@ -118,6 +119,28 @@ impl HashBuiltinRunner { BuiltinAdditionalData::Hash(verified_addresses) } + pub fn extend_additional_data( + &mut self, + additional_data: &BuiltinAdditionalData, + ) -> Result<(), RunnerError> { + let additional_data = match additional_data { + BuiltinAdditionalData::Hash(d) => d, + _ => return Err(RunnerError::InvalidAdditionalData(BuiltinName::pedersen)), + }; + let mut verified_addresses = self.verified_addresses.borrow_mut(); + for addr in additional_data { + if addr.segment_index != self.base as isize { + return Err(RunnerError::InvalidAdditionalData(BuiltinName::pedersen)); + } + // Mark offset as verified + if addr.offset > verified_addresses.len() { + verified_addresses.resize(addr.offset, false); + } + verified_addresses.insert(addr.offset, true) + } + Ok(()) + } + pub fn air_private_input(&self, memory: &Memory) -> Vec { let mut private_inputs = vec![]; if let Some(segment) = memory.data.get(self.base) { @@ -442,7 +465,7 @@ mod tests { } #[test] - fn get_additional_info() { + fn get_additional_data() { let mut builtin = HashBuiltinRunner::new(Some(1), true); let verified_addresses = vec![Relocatable::from((0, 3)), Relocatable::from((0, 6))]; builtin.verified_addresses = @@ -453,6 +476,17 @@ mod tests { ) } + #[test] + fn get_and_extend_additional_data() { + let mut builtin_a = HashBuiltinRunner::new(Some(1), true); + builtin_a.verified_addresses = + RefCell::new(vec![false, false, false, true, false, false, true]); + let additional_data = builtin_a.get_additional_data(); + let mut builtin_b = HashBuiltinRunner::new(Some(1), true); + builtin_b.extend_additional_data(&additional_data).unwrap(); + assert_eq!(builtin_a.verified_addresses, builtin_b.verified_addresses); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_air_private_input() { diff --git a/vm/src/vm/runners/builtin_runner/mod.rs b/vm/src/vm/runners/builtin_runner/mod.rs index 1d1f21c07e..886ed00578 100644 --- a/vm/src/vm/runners/builtin_runner/mod.rs +++ b/vm/src/vm/runners/builtin_runner/mod.rs @@ -499,6 +499,7 @@ impl BuiltinRunner { } } + /// Returns data stored internally by builtins needed to re-execute from a cairo pie pub fn get_additional_data(&self) -> BuiltinAdditionalData { match self { BuiltinRunner::Hash(builtin) => builtin.get_additional_data(), @@ -508,6 +509,20 @@ impl BuiltinRunner { } } + /// Extends the builtin's internal data with the internal data obtained from a previous cairo execution + /// Used solely when running from a cairo pie + pub fn extend_additional_data( + &mut self, + additional_data: &BuiltinAdditionalData, + ) -> Result<(), RunnerError> { + match self { + BuiltinRunner::Hash(builtin) => builtin.extend_additional_data(additional_data), + BuiltinRunner::Output(builtin) => builtin.extend_additional_data(additional_data), + BuiltinRunner::Signature(builtin) => builtin.extend_additional_data(additional_data), + _ => Ok(()), + } + } + // Returns information about the builtin that should be added to the AIR private input. pub fn air_private_input(&self, segments: &MemorySegmentManager) -> Vec { match self { diff --git a/vm/src/vm/runners/builtin_runner/output.rs b/vm/src/vm/runners/builtin_runner/output.rs index f0015761f6..a8486fe2d9 100644 --- a/vm/src/vm/runners/builtin_runner/output.rs +++ b/vm/src/vm/runners/builtin_runner/output.rs @@ -124,6 +124,19 @@ impl OutputBuiltinRunner { }) } + pub fn extend_additional_data( + &mut self, + additional_data: &BuiltinAdditionalData, + ) -> Result<(), RunnerError> { + let additional_data = match additional_data { + BuiltinAdditionalData::Output(d) => d, + _ => return Err(RunnerError::InvalidAdditionalData(BuiltinName::output)), + }; + self.pages.extend(additional_data.pages.clone()); + self.attributes.extend(additional_data.attributes.clone()); + Ok(()) + } + pub(crate) fn set_stop_ptr_offset(&mut self, offset: usize) { self.stop_ptr = Some(offset) } @@ -456,7 +469,7 @@ mod tests { } #[test] - fn get_additional_info_no_pages_no_attributes() { + fn get_additional_data_no_pages_no_attributes() { let builtin = OutputBuiltinRunner::new(true); assert_eq!( builtin.get_additional_data(), @@ -599,4 +612,26 @@ mod tests { vec![(0, 0), (1, 0), (2, 1), (3, 1), (4, 2), (5, 2), (6, 2)] ); } + + #[test] + fn get_and_extend_additional_data() { + let builtin_a = OutputBuiltinRunner { + base: 0, + pages: HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), + attributes: HashMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), + stop_ptr: None, + included: true, + }; + let additional_data = builtin_a.get_additional_data(); + let mut builtin_b = OutputBuiltinRunner { + base: 0, + pages: Default::default(), + attributes: Default::default(), + stop_ptr: None, + included: true, + }; + builtin_b.extend_additional_data(&additional_data).unwrap(); + assert_eq!(builtin_a.attributes, builtin_b.attributes); + assert_eq!(builtin_a.pages, builtin_b.pages); + } } diff --git a/vm/src/vm/runners/builtin_runner/signature.rs b/vm/src/vm/runners/builtin_runner/signature.rs index a95ad508a4..762e46f639 100644 --- a/vm/src/vm/runners/builtin_runner/signature.rs +++ b/vm/src/vm/runners/builtin_runner/signature.rs @@ -2,8 +2,10 @@ use crate::air_private_input::{PrivateInput, PrivateInputSignature, SignatureInp use crate::math_utils::div_mod; use crate::stdlib::{cell::RefCell, collections::HashMap, prelude::*, rc::Rc}; +use crate::types::builtin_name::BuiltinName; use crate::types::errors::math_errors::MathError; use crate::types::instance_definitions::ecdsa_instance_def::CELLS_PER_SIGNATURE; +use crate::vm::errors::runner_errors::RunnerError; use crate::vm::runners::cairo_pie::BuiltinAdditionalData; use crate::Felt252; use crate::{ @@ -180,6 +182,31 @@ impl SignatureBuiltinRunner { BuiltinAdditionalData::Signature(signatures) } + pub fn extend_additional_data( + &mut self, + additional_data: &BuiltinAdditionalData, + ) -> Result<(), RunnerError> { + let additional_data = match additional_data { + BuiltinAdditionalData::Signature(d) => d, + _ => return Err(RunnerError::InvalidAdditionalData(BuiltinName::ecdsa)), + }; + for (addr, (r, s)) in additional_data { + if addr.segment_index != self.base as isize { + return Err(RunnerError::InvalidAdditionalData(BuiltinName::ecdsa)); + } + self.signatures.borrow_mut().insert( + *addr, + Signature { + r: FieldElement::from_bytes_be(&r.to_bytes_be()) + .map_err(|_| MathError::ByteConversionError)?, + s: FieldElement::from_bytes_be(&s.to_bytes_be()) + .map_err(|_| MathError::ByteConversionError)?, + }, + ); + } + Ok(()) + } + pub fn air_private_input(&self, memory: &Memory) -> Vec { let mut private_inputs = vec![]; for (addr, signature) in self.signatures.borrow().iter() { @@ -482,7 +509,7 @@ mod tests { } #[test] - fn get_additional_info() { + fn get_additional_data() { let mut builtin = SignatureBuiltinRunner::new(Some(512), true); let signatures = HashMap::from([( Relocatable::from((4, 0)), @@ -501,4 +528,31 @@ mod tests { BuiltinAdditionalData::Signature(signatures) ) } + + #[test] + fn get_and_extend_additional_data() { + let mut builtin_a = SignatureBuiltinRunner::new(Some(512), true); + let signatures = HashMap::from([( + Relocatable::from((0, 0)), + Signature { + r: FieldElement::from_dec_str("45678").unwrap(), + s: FieldElement::from_dec_str("1239").unwrap(), + }, + )]); + builtin_a.signatures = Rc::new(RefCell::new(signatures)); + let additional_data = builtin_a.get_additional_data(); + let mut builtin_b = SignatureBuiltinRunner::new(Some(512), true); + builtin_b.extend_additional_data(&additional_data).unwrap(); + // Signature doesn't implement PartialEq so we can't comapre the list of signatures directly + let signatures_a = builtin_a.signatures.borrow(); + let signatures_b = builtin_b.signatures.borrow(); + assert_eq!(signatures_a.len(), signatures_b.len()); + for ((addr_a, signature_a), (addr_b, signature_b)) in + signatures_a.iter().zip(signatures_b.iter()) + { + assert_eq!(addr_a, addr_b); + assert_eq!(signature_a.r, signature_b.r); + assert_eq!(signature_a.s, signature_b.s); + } + } }