Skip to content

Commit

Permalink
stackinputs: add validation for size and deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
hackaugusto committed Dec 1, 2023
1 parent 24352ba commit 498943f
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 20 deletions.
10 changes: 6 additions & 4 deletions core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}
}
Expand Down
41 changes: 28 additions & 13 deletions core/src/stack/inputs.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -18,9 +22,13 @@ impl StackInputs {
// --------------------------------------------------------------------------------------------

/// Returns `[StackInputs]` from a list of values, reversing them into a stack.
pub fn new(mut values: Vec<Felt>) -> Self {
values.reverse();
Self { values }
pub fn new(mut values: Vec<Felt>) -> Result<Self, InputError> {
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
Expand All @@ -30,7 +38,7 @@ impl StackInputs {
I: IntoIterator<Item = u64>,
{
let values: Vec<Felt> = iter.into_iter().map(Felt::from).collect();
Ok(Self::new(values))
Self::new(values)
}

// PUBLIC ACCESSORS
Expand Down Expand Up @@ -60,20 +68,27 @@ impl IntoIterator for StackInputs {
}
}

impl ToElements<Felt> for StackInputs {
fn to_elements(&self) -> Vec<Felt> {
self.values.to_vec()
}
}

// SERIALIZATION
// ================================================================================================

impl Serializable for StackInputs {
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.

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<Felt> for StackInputs {
fn to_elements(&self) -> Vec<Felt> {
self.values.to_vec()
impl Deserializable for StackInputs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
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 })
}
}
4 changes: 2 additions & 2 deletions processor/src/operations/ext2_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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());
}
Expand Down
2 changes: 1 addition & 1 deletion processor/src/operations/fri_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down

0 comments on commit 498943f

Please sign in to comment.