diff --git a/core/src/errors.rs b/core/src/errors.rs index 1a1e98ceb0..5128d8f9cd 100644 --- a/core/src/errors.rs +++ b/core/src/errors.rs @@ -5,20 +5,22 @@ use core::fmt; #[derive(Clone, Debug)] pub enum InputError { - NotFieldElement(u64, &'static str), DuplicateAdviceRoot([u8; 32]), + NotFieldElement(u64, &'static str), + StackTooBig(usize), } impl fmt::Display for InputError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use InputError::*; match self { - NotFieldElement(num, description) => { - write!(f, "{num} is not a valid field element: {description}") - } DuplicateAdviceRoot(key) => { write!(f, "{key:02x?} is a duplicate of the current merkle set") } + NotFieldElement(num, description) => { + write!(f, "{num} is not a valid field element: {description}") + } + StackTooBig(size) => write!(f, "Stack can not have {size} elements"), } } } diff --git a/core/src/stack/inputs.rs b/core/src/stack/inputs.rs index 4e8c6520e7..b5ca987581 100644 --- a/core/src/stack/inputs.rs +++ b/core/src/stack/inputs.rs @@ -1,9 +1,13 @@ +use winter_utils::{ByteReader, Deserializable, DeserializationError}; + use super::{vec, ByteWriter, Felt, InputError, Serializable, ToElements, Vec}; use core::slice; // STACK INPUTS // ================================================================================================ +const MAX_STACK_INPUTS_SIZE: usize = u32::MAX as usize; + /// Initial state of the stack to support program execution. /// /// The program execution expects the inputs to be a stack on the VM, and it will be stored in @@ -18,9 +22,13 @@ impl StackInputs { // -------------------------------------------------------------------------------------------- /// Returns `[StackInputs]` from a list of values, reversing them into a stack. - pub fn new(mut values: Vec) -> Self { - values.reverse(); - Self { values } + pub fn new(mut values: Vec) -> Result { + if values.len() > MAX_STACK_INPUTS_SIZE { + Err(InputError::StackTooBig(values.len())) + } else { + values.reverse(); + Ok(Self { values }) + } } /// Attempts to create stack inputs from an iterator of numbers, failing if they do not @@ -30,7 +38,7 @@ impl StackInputs { I: IntoIterator, { let values: Vec = iter.into_iter().map(Felt::from).collect(); - Ok(Self::new(values)) + Self::new(values) } // PUBLIC ACCESSORS @@ -60,20 +68,27 @@ impl IntoIterator for StackInputs { } } +impl ToElements for StackInputs { + fn to_elements(&self) -> Vec { + self.values.to_vec() + } +} + +// SERIALIZATION +// ================================================================================================ + impl Serializable for StackInputs { fn write_into(&self, target: &mut W) { - // TODO the length of the stack, by design, will not be greater than `u32::MAX`. however, - // we must define a common serialization format as we might diverge from the implementation - // here and the one provided by default from winterfell. - - debug_assert!(self.values.len() <= u32::MAX as usize); + debug_assert!(self.values.len() <= MAX_STACK_INPUTS_SIZE); target.write_u32(self.values.len() as u32); - self.values.iter().copied().for_each(|v| target.write(v)); + self.values.write_into(target); } } -impl ToElements for StackInputs { - fn to_elements(&self) -> Vec { - self.values.to_vec() +impl Deserializable for StackInputs { + fn read_from(source: &mut R) -> Result { + let count: usize = source.read_u32()?.try_into().expect("u32 must fit in a usize"); + let values = Felt::read_batch_from(source, count)?; + Ok(Self { values }) } } diff --git a/processor/src/operations/ext2_ops.rs b/processor/src/operations/ext2_ops.rs index 2af25f29ec..53b0c053ee 100644 --- a/processor/src/operations/ext2_ops.rs +++ b/processor/src/operations/ext2_ops.rs @@ -49,7 +49,7 @@ mod tests { // initialize the stack with a few values let [a0, a1, b0, b1] = [rand_value(); 4]; - let stack = StackInputs::new(vec![a0, a1, b0, b1]); + let stack = StackInputs::new(vec![a0, a1, b0, b1]).unwrap(); let mut process = Process::new_dummy(stack); // multiply the top two values @@ -64,7 +64,7 @@ mod tests { assert_eq!(expected, process.stack.trace_state()); // calling ext2mul with a stack of minimum depth is ok - let stack = StackInputs::new(vec![]); + let stack = StackInputs::new(vec![]).unwrap(); let mut process = Process::new_dummy(stack); assert!(process.execute_op(Operation::Ext2Mul).is_ok()); } diff --git a/processor/src/operations/fri_ops.rs b/processor/src/operations/fri_ops.rs index c0beeafda4..653c314def 100644 --- a/processor/src/operations/fri_ops.rs +++ b/processor/src/operations/fri_ops.rs @@ -321,7 +321,7 @@ mod tests { ]; // --- execute FRIE2F4 operation -------------------------------------- - let stack_inputs = StackInputs::new(inputs.to_vec()); + let stack_inputs = StackInputs::new(inputs.to_vec()).unwrap(); let mut process = Process::new_dummy_with_decoder_helpers(stack_inputs); process.execute_op(Operation::FriE2F4).unwrap();