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