diff --git a/core/src/errors.rs b/core/src/errors.rs index 1a1e98ceb0..2cba5a4178 100644 --- a/core/src/errors.rs +++ b/core/src/errors.rs @@ -33,6 +33,7 @@ pub enum OutputError { InvalidOverflowAddress(u64), InvalidOverflowAddressLength(usize, usize), InvalidStackElement(u64), + OutputSizeTooBig(usize), } impl fmt::Display for OutputError { @@ -48,6 +49,9 @@ impl fmt::Display for OutputError { InvalidStackElement(element) => { write!(f, "stack contains {element} that is not a valid field element") } + OutputSizeTooBig(size) => { + write!(f, "too many elements for output stack, {size} elements") + } } } } diff --git a/core/src/stack/outputs.rs b/core/src/stack/outputs.rs index 70625eb332..433c91b146 100644 --- a/core/src/stack/outputs.rs +++ b/core/src/stack/outputs.rs @@ -33,6 +33,8 @@ pub struct StackOutputs { overflow_addrs: Vec, } +pub const MAX_STACK_OUTPUTS_SIZE: usize = u16::MAX as usize; + impl StackOutputs { // CONSTRUCTOR // -------------------------------------------------------------------------------------------- @@ -45,6 +47,10 @@ impl StackOutputs { /// - If the number of stack elements is greater than `STACK_TOP_SIZE` (16) and `overflow_addrs` /// does not contain exactly `stack.len() + 1 - STACK_TOP_SIZE` elements. pub fn new(mut stack: Vec, overflow_addrs: Vec) -> Result { + if stack.len() > MAX_STACK_OUTPUTS_SIZE { + return Err(OutputError::OutputSizeTooBig(stack.len())); + } + // Validate stack elements if let Some(element) = find_invalid_elements(&stack) { return Err(OutputError::InvalidStackElement(element)); @@ -212,16 +218,6 @@ impl ToElements for StackOutputs { impl Serializable for StackOutputs { 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. - - // stack - debug_assert!(self.stack.len() <= u32::MAX as usize); - target.write_u32(self.stack.len() as u32); - self.stack.write_into(target); - - // overflow addrs debug_assert!(self.overflow_addrs.len() <= u32::MAX as usize); target.write_u32(self.overflow_addrs.len() as u32); self.overflow_addrs.write_into(target); @@ -230,14 +226,14 @@ impl Serializable for StackOutputs { impl Deserializable for StackOutputs { fn read_from(source: &mut R) -> Result { - let count = source.read_u32()?; - let mut stack = Vec::with_capacity(count as usize); + let count = source.read_u32()?.try_into().expect("u32 must fit in a usize"); + let mut stack = Vec::with_capacity(count); for _ in 0..count { stack.push(source.read_u64()?); } - let count = source.read_u32()?; - let mut overflow_addrs = Vec::with_capacity(count as usize); + let count = source.read_u32()?.try_into().expect("u32 must fit in a usize"); + let mut overflow_addrs = Vec::with_capacity(count); for _ in 0..count { overflow_addrs.push(source.read_u64()?); }