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}