Skip to content

Commit

Permalink
stackoutputs: add deserializer and size validation
Browse files Browse the repository at this point in the history
  • Loading branch information
hackaugusto committed Dec 2, 2023
1 parent 4b8b03f commit 27c65ee
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 14 deletions.
4 changes: 4 additions & 0 deletions core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub enum OutputError {
InvalidOverflowAddress(u64),
InvalidOverflowAddressLength(usize, usize),
InvalidStackElement(u64),
OutputSizeTooBig(usize),
}

impl fmt::Display for OutputError {
Expand All @@ -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")
}
}
}
}
Expand Down
24 changes: 10 additions & 14 deletions core/src/stack/outputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub struct StackOutputs {
overflow_addrs: Vec<u64>,
}

pub const MAX_STACK_OUTPUTS_SIZE: usize = u16::MAX as usize;

impl StackOutputs {
// CONSTRUCTOR
// --------------------------------------------------------------------------------------------
Expand All @@ -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<u64>, overflow_addrs: Vec<u64>) -> Result<Self, OutputError> {
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));
Expand Down Expand Up @@ -212,16 +218,6 @@ impl ToElements<Felt> for StackOutputs {

impl Serializable for StackOutputs {
fn write_into<W: ByteWriter>(&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);
Expand All @@ -230,14 +226,14 @@ impl Serializable for StackOutputs {

impl Deserializable for StackOutputs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
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()?);
}
Expand Down

0 comments on commit 27c65ee

Please sign in to comment.