miden_core/stack/
outputs.rs

1use alloc::vec::Vec;
2use core::ops::Deref;
3
4use miden_crypto::{Word, ZERO};
5
6use super::{ByteWriter, Felt, MIN_STACK_DEPTH, OutputError, Serializable, get_num_stack_values};
7use crate::utils::{ByteReader, Deserializable, DeserializationError, range};
8
9// STACK OUTPUTS
10// ================================================================================================
11
12/// Output container for Miden VM programs.
13///
14/// Miden program outputs contain the full state of the stack at the end of execution.
15///
16/// `stack` is expected to be ordered as if the elements were popped off the stack one by one.
17/// Thus, the value at the top of the stack is expected to be in the first position, and the order
18/// of the rest of the output elements will also match the order on the stack.
19#[derive(Debug, Clone, Default, PartialEq, Eq)]
20pub struct StackOutputs {
21    elements: [Felt; MIN_STACK_DEPTH],
22}
23
24impl StackOutputs {
25    // CONSTRUCTORS
26    // --------------------------------------------------------------------------------------------
27
28    /// Constructs a new [StackOutputs] struct from the provided stack elements.
29    ///
30    /// # Errors
31    ///  Returns an error if the number of stack elements is greater than `MIN_STACK_DEPTH` (16).
32    pub fn new(mut stack: Vec<Felt>) -> Result<Self, OutputError> {
33        // validate stack length
34        if stack.len() > MIN_STACK_DEPTH {
35            return Err(OutputError::OutputSizeTooBig(stack.len()));
36        }
37        stack.resize(MIN_STACK_DEPTH, ZERO);
38
39        Ok(Self { elements: stack.try_into().unwrap() })
40    }
41
42    /// Attempts to create [StackOutputs] struct from the provided stack elements represented as
43    /// vector of `u64` values.
44    ///
45    /// # Errors
46    /// Returns an error if:
47    /// - Any of the provided stack elements are invalid field elements.
48    pub fn try_from_ints<I>(iter: I) -> Result<Self, OutputError>
49    where
50        I: IntoIterator<Item = u64>,
51    {
52        // Validate stack elements
53        let stack = iter
54            .into_iter()
55            .map(Felt::try_from)
56            .collect::<Result<Vec<Felt>, _>>()
57            .map_err(OutputError::InvalidStackElement)?;
58
59        Self::new(stack)
60    }
61
62    // PUBLIC ACCESSORS
63    // --------------------------------------------------------------------------------------------
64
65    /// Returns the element located at the specified position on the stack or `None` if out of
66    /// bounds.
67    pub fn get_stack_item(&self, idx: usize) -> Option<Felt> {
68        self.elements.get(idx).cloned()
69    }
70
71    /// Returns the word located starting at the specified Felt position on the stack or `None` if
72    /// out of bounds. For example, passing in `0` returns the word at the top of the stack, and
73    /// passing in `4` returns the word starting at element index `4`.
74    pub fn get_stack_word(&self, idx: usize) -> Option<Word> {
75        let word_elements: Word = {
76            let word_elements: Vec<Felt> = range(idx, 4)
77                .map(|idx| self.get_stack_item(idx))
78                // Elements need to be reversed, since a word `[a, b, c, d]` will be stored on the
79                // stack as `[d, c, b, a]`
80                .rev()
81                .collect::<Option<_>>()?;
82
83            word_elements.try_into().expect("a Word contains 4 elements")
84        };
85
86        Some(word_elements)
87    }
88
89    /// Returns the number of requested stack outputs or returns the full stack if fewer than the
90    /// requested number of stack values exist.
91    pub fn stack_truncated(&self, num_outputs: usize) -> &[Felt] {
92        let len = self.elements.len().min(num_outputs);
93        &self.elements[..len]
94    }
95
96    // PUBLIC MUTATORS
97    // --------------------------------------------------------------------------------------------
98
99    /// Returns mutable access to the stack outputs, to be used for testing or running examples.
100    pub fn stack_mut(&mut self) -> &mut [Felt] {
101        &mut self.elements
102    }
103
104    /// Converts the [`StackOutputs`] into the vector of `u64` values.
105    pub fn as_int_vec(&self) -> Vec<u64> {
106        self.elements.iter().map(|e| (*e).as_int()).collect()
107    }
108}
109
110impl Deref for StackOutputs {
111    type Target = [Felt; 16];
112
113    fn deref(&self) -> &Self::Target {
114        &self.elements
115    }
116}
117
118impl From<[Felt; MIN_STACK_DEPTH]> for StackOutputs {
119    fn from(value: [Felt; MIN_STACK_DEPTH]) -> Self {
120        Self { elements: value }
121    }
122}
123
124// SERIALIZATION
125// ================================================================================================
126
127impl Serializable for StackOutputs {
128    fn write_into<W: ByteWriter>(&self, target: &mut W) {
129        let num_stack_values = get_num_stack_values(self);
130        target.write_u8(num_stack_values);
131        target.write_many(&self.elements[..num_stack_values as usize]);
132    }
133}
134
135impl Deserializable for StackOutputs {
136    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
137        let num_elements = source.read_u8()?;
138
139        let elements = source.read_many::<Felt>(num_elements.into())?;
140
141        StackOutputs::new(elements).map_err(|_| {
142            DeserializationError::InvalidValue(format!(
143                "number of stack elements should not be greater than {}, but {} was found",
144                MIN_STACK_DEPTH, num_elements
145            ))
146        })
147    }
148}