1use alloc::vec::Vec;
2
3use crate::{
4 Felt, Word,
5 crypto::merkle::MerkleStore,
6 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8
9mod map;
10pub use map::AdviceMap;
11
12mod stack;
13pub use stack::AdviceStack;
14
15#[derive(Clone, Debug, Default, PartialEq, Eq)]
33#[cfg_attr(
34 all(feature = "arbitrary", test),
35 miden_test_serialization_macros::serialization_test
36)]
37pub struct AdviceInputs {
38 stack: AdviceStack,
39 map: AdviceMap,
40 store: MerkleStore,
41}
42
43impl AdviceInputs {
44 pub fn new(stack: AdviceStack, map: AdviceMap, store: MerkleStore) -> Self {
49 Self { stack, map, store }
50 }
51
52 pub fn with_stack(mut self, stack: AdviceStack) -> Self {
54 self.stack = stack;
55 self
56 }
57
58 pub fn stack(&self) -> AdviceStack {
60 self.stack.clone()
61 }
62
63 pub fn map(&self) -> &AdviceMap {
65 &self.map
66 }
67
68 pub fn store(&self) -> &MerkleStore {
70 &self.store
71 }
72
73 pub fn with_map<I>(mut self, iter: I) -> Self
75 where
76 I: IntoIterator<Item = (Word, Vec<Felt>)>,
77 {
78 self.map.extend(iter);
79 self
80 }
81
82 pub fn with_merkle_store(mut self, store: MerkleStore) -> Self {
84 self.store = store;
85 self
86 }
87
88 pub fn extend(&mut self, other: Self) {
93 self.stack.append_elements(other.stack.into_elements());
94 self.map.extend(other.map);
95 self.store.extend(other.store.inner_nodes());
96 }
97
98 pub fn into_parts(self) -> (AdviceStack, AdviceMap, MerkleStore) {
100 (self.stack, self.map, self.store)
101 }
102}
103
104impl From<AdviceMap> for AdviceInputs {
105 fn from(map: AdviceMap) -> Self {
106 Self {
107 stack: AdviceStack::default(),
108 map,
109 store: MerkleStore::default(),
110 }
111 }
112}
113
114impl Serializable for AdviceInputs {
115 fn write_into<W: ByteWriter>(&self, target: &mut W) {
116 let Self { stack, map, store } = self;
117 let stack: Vec<Felt> = stack.iter().copied().collect();
118 stack.write_into(target);
119 map.write_into(target);
120 store.write_into(target);
121 }
122}
123
124impl Deserializable for AdviceInputs {
125 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
126 let stack = Vec::<Felt>::read_from(source)?;
127 let map = AdviceMap::read_from(source)?;
128 let store = MerkleStore::read_from(source)?;
129 Ok(Self { stack: stack.into(), map, store })
130 }
131}
132
133#[cfg(test)]
137mod tests {
138 use alloc::vec::Vec;
139
140 use super::{AdviceInputs, AdviceMap, AdviceStack};
141 use crate::{
142 Felt, Word,
143 crypto::merkle::MerkleStore,
144 serde::{Deserializable, DeserializationError, Serializable},
145 };
146
147 #[test]
148 fn test_advice_inputs_eq() {
149 let advice1 = AdviceInputs::default();
150 let advice2 = AdviceInputs::default();
151
152 assert_eq!(advice1, advice2);
153
154 let advice1 =
155 AdviceInputs::default().with_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
156 let advice2 =
157 AdviceInputs::default().with_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
158
159 assert_eq!(advice1, advice2);
160 }
161
162 #[test]
163 fn test_advice_inputs_serialization() {
164 let advice1 =
165 AdviceInputs::default().with_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
166 let bytes = advice1.to_bytes();
167 let advice2 = AdviceInputs::read_from_bytes(&bytes).unwrap();
168
169 assert_eq!(advice1, advice2);
170 }
171
172 #[test]
173 fn advice_inputs_reject_unversioned_merkle_store() {
174 let mut bytes = Vec::<Felt>::new().to_bytes();
175 AdviceMap::default().write_into(&mut bytes);
176 0u64.write_into(&mut bytes);
178 assert!(matches!(
179 AdviceInputs::read_from_bytes(&bytes),
180 Err(DeserializationError::InvalidValue(message))
181 if message == "unsupported MerkleStore format: expected a versioned encoding"
182 ));
183 }
184
185 #[test]
186 fn advice_inputs_new_assembles_parts() {
187 let stack = AdviceStack::try_from_values([1, 2, 3]).unwrap();
188 let map = AdviceMap::from_iter([(Word::default(), vec![Felt::new_unchecked(7)])]);
189 let store = MerkleStore::default();
190
191 let advice = AdviceInputs::new(stack.clone(), map.clone(), store.clone());
192
193 assert_eq!(advice.stack(), stack);
194 assert_eq!(advice.map, map);
195 assert_eq!(advice.store, store);
196 }
197
198 #[test]
199 fn advice_inputs_from_advice_map_defaults_other_parts() {
200 let map = AdviceMap::from_iter([(Word::default(), vec![Felt::new_unchecked(7)])]);
201
202 let advice = AdviceInputs::from(map.clone());
203
204 assert_eq!(advice.stack(), AdviceStack::default());
205 assert_eq!(advice.map, map);
206 assert_eq!(advice.store, MerkleStore::default());
207 }
208
209 #[test]
210 fn advice_inputs_accept_typed_advice_stack() {
211 let mut stack = AdviceStack::new();
212 stack.append_element(Felt::new_unchecked(1));
213 stack.append_word(
214 [
215 Felt::new_unchecked(2),
216 Felt::new_unchecked(3),
217 Felt::new_unchecked(4),
218 Felt::new_unchecked(5),
219 ]
220 .into(),
221 );
222
223 let advice = AdviceInputs::default().with_stack(stack.clone());
224
225 assert_eq!(advice.stack(), stack);
226 }
227
228 #[test]
229 fn advice_stack_consumes_word_sized_groups_top_first() {
230 let word0: Word = [
231 Felt::new_unchecked(1),
232 Felt::new_unchecked(2),
233 Felt::new_unchecked(3),
234 Felt::new_unchecked(4),
235 ]
236 .into();
237 let word1: Word = [
238 Felt::new_unchecked(5),
239 Felt::new_unchecked(6),
240 Felt::new_unchecked(7),
241 Felt::new_unchecked(8),
242 ]
243 .into();
244 let mut stack = AdviceStack::new();
245
246 stack.append_element(Felt::new_unchecked(0));
247 stack.append_word(word0);
248 stack.append_dword([word1, word0]);
249
250 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(0)));
251 assert_eq!(stack.consume_word(), Some(word0));
252 assert_eq!(stack.consume_dword(), Some([word1, word0]));
253 assert!(stack.is_empty());
254 }
255
256 #[test]
257 fn advice_stack_rejects_partial_dword_without_consuming() {
258 let word: Word = [
259 Felt::new_unchecked(1),
260 Felt::new_unchecked(2),
261 Felt::new_unchecked(3),
262 Felt::new_unchecked(4),
263 ]
264 .into();
265 let mut stack = AdviceStack::new();
266 stack.append_word(word);
267
268 assert_eq!(stack.consume_dword(), None);
269 assert_eq!(stack.consume_word(), Some(word));
270 }
271
272 #[test]
273 fn advice_stack_append_for_adv_push_matches_repeated_consumption() {
274 let values = [Felt::new_unchecked(1), Felt::new_unchecked(2), Felt::new_unchecked(3)];
275 let mut stack = AdviceStack::new();
276 stack.append_for_adv_push(&values);
277
278 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(3)));
279 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(2)));
280 assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(1)));
281 assert!(stack.is_empty());
282 }
283
284 #[test]
285 fn advice_stack_append_for_adv_pipe_requires_dword_alignment() {
286 let values: Vec<Felt> = (1..=16).map(Felt::new_unchecked).collect();
287 let mut stack = AdviceStack::new();
288 stack.append_for_adv_pipe(&values);
289
290 assert_eq!(stack.into_elements(), values);
291 }
292
293 #[test]
294 #[should_panic(expected = "append_for_adv_pipe requires slice length to be a multiple of 8")]
295 fn advice_stack_append_for_adv_pipe_panics_on_misalignment() {
296 let values: Vec<Felt> = (1..=7).map(Felt::new_unchecked).collect();
297 let mut stack = AdviceStack::new();
298 stack.append_for_adv_pipe(&values);
299 }
300
301 #[test]
302 fn advice_stack_prepends_new_top_elements() {
303 let mut stack = AdviceStack::from(vec![Felt::new_unchecked(3), Felt::new_unchecked(4)]);
304
305 stack.push_element(Felt::new_unchecked(2));
306 stack.prepend_elements([Felt::new_unchecked(0), Felt::new_unchecked(1)]);
307
308 assert_eq!(
309 stack.into_elements(),
310 vec![
311 Felt::new_unchecked(0),
312 Felt::new_unchecked(1),
313 Felt::new_unchecked(2),
314 Felt::new_unchecked(3),
315 Felt::new_unchecked(4),
316 ]
317 );
318 }
319
320 #[test]
324 fn advice_stack_try_from_values_keeps_top_first_order() {
325 let stack = AdviceStack::try_from_values([1, 2, 3, 4]).unwrap();
326
327 assert_eq!(
328 stack.into_elements(),
329 vec![
330 Felt::new_unchecked(1),
331 Felt::new_unchecked(2),
332 Felt::new_unchecked(3),
333 Felt::new_unchecked(4)
334 ]
335 );
336 }
337}