Skip to main content

miden_core/advice/
mod.rs

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// ADVICE INPUTS
16// ================================================================================================
17
18/// Inputs container to initialize advice provider for the execution of Miden VM programs.
19///
20/// The program may request nondeterministic advice inputs from the prover. These inputs are secret
21/// inputs. This means that the prover does not need to share them with the verifier.
22///
23/// There are three types of advice inputs:
24///
25/// 1. Single advice stack which can contain any number of elements.
26/// 2. Key-mapped element lists which can be pushed onto the advice stack.
27/// 3. Merkle store, which is used to provide nondeterministic inputs for instructions that operates
28///    with Merkle trees.
29#[derive(Clone, Debug, Default, PartialEq, Eq)]
30pub struct AdviceInputs {
31    stack: AdviceStack,
32    map: AdviceMap,
33    store: MerkleStore,
34}
35
36impl AdviceInputs {
37    // CONSTRUCTORS
38    // --------------------------------------------------------------------------------------------
39
40    /// Creates a new advice inputs container from the provided stack, map, and Merkle store.
41    pub fn new(stack: AdviceStack, map: AdviceMap, store: MerkleStore) -> Self {
42        Self { stack, map, store }
43    }
44
45    /// Replaces the stack with the provided typed stack.
46    pub fn with_stack(mut self, stack: AdviceStack) -> Self {
47        self.stack = stack;
48        self
49    }
50
51    /// Returns the advice stack.
52    pub fn stack(&self) -> AdviceStack {
53        self.stack.clone()
54    }
55
56    /// Returns the advice map.
57    pub fn map(&self) -> &AdviceMap {
58        &self.map
59    }
60
61    /// Returns the Merkle store.
62    pub fn store(&self) -> &MerkleStore {
63        &self.store
64    }
65
66    /// Extends the map of values with the given argument, replacing previously inserted items.
67    pub fn with_map<I>(mut self, iter: I) -> Self
68    where
69        I: IntoIterator<Item = (Word, Vec<Felt>)>,
70    {
71        self.map.extend(iter);
72        self
73    }
74
75    /// Replaces the [MerkleStore] with the provided argument.
76    pub fn with_merkle_store(mut self, store: MerkleStore) -> Self {
77        self.store = store;
78        self
79    }
80
81    // PUBLIC MUTATORS
82    // --------------------------------------------------------------------------------------------
83
84    /// Extends the contents of this instance with the contents of the other instance.
85    pub fn extend(&mut self, other: Self) {
86        self.stack.append_elements(other.stack.into_elements());
87        self.map.extend(other.map);
88        self.store.extend(other.store.inner_nodes());
89    }
90
91    /// Consumes this instance and returns its parts.
92    pub fn into_parts(self) -> (AdviceStack, AdviceMap, MerkleStore) {
93        (self.stack, self.map, self.store)
94    }
95}
96
97impl From<AdviceMap> for AdviceInputs {
98    fn from(map: AdviceMap) -> Self {
99        Self {
100            stack: AdviceStack::default(),
101            map,
102            store: MerkleStore::default(),
103        }
104    }
105}
106
107impl Serializable for AdviceInputs {
108    fn write_into<W: ByteWriter>(&self, target: &mut W) {
109        let Self { stack, map, store } = self;
110        let stack: Vec<Felt> = stack.iter().copied().collect();
111        stack.write_into(target);
112        map.write_into(target);
113        store.write_into(target);
114    }
115}
116
117impl Deserializable for AdviceInputs {
118    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
119        let stack = Vec::<Felt>::read_from(source)?;
120        let map = AdviceMap::read_from(source)?;
121        let store = MerkleStore::read_from(source)?;
122        Ok(Self { stack: stack.into(), map, store })
123    }
124}
125
126// TESTS
127// ================================================================================================
128
129#[cfg(test)]
130mod tests {
131    use alloc::vec::Vec;
132
133    use super::{AdviceInputs, AdviceMap, AdviceStack};
134    use crate::{
135        Felt, Word,
136        crypto::merkle::MerkleStore,
137        serde::{Deserializable, Serializable},
138    };
139
140    #[test]
141    fn test_advice_inputs_eq() {
142        let advice1 = AdviceInputs::default();
143        let advice2 = AdviceInputs::default();
144
145        assert_eq!(advice1, advice2);
146
147        let advice1 =
148            AdviceInputs::default().with_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
149        let advice2 =
150            AdviceInputs::default().with_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
151
152        assert_eq!(advice1, advice2);
153    }
154
155    #[test]
156    fn test_advice_inputs_serialization() {
157        let advice1 =
158            AdviceInputs::default().with_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
159        let bytes = advice1.to_bytes();
160        let advice2 = AdviceInputs::read_from_bytes(&bytes).unwrap();
161
162        assert_eq!(advice1, advice2);
163    }
164
165    #[test]
166    fn advice_inputs_new_assembles_parts() {
167        let stack = AdviceStack::try_from_values([1, 2, 3]).unwrap();
168        let map = AdviceMap::from_iter([(Word::default(), vec![Felt::new_unchecked(7)])]);
169        let store = MerkleStore::default();
170
171        let advice = AdviceInputs::new(stack.clone(), map.clone(), store.clone());
172
173        assert_eq!(advice.stack(), stack);
174        assert_eq!(advice.map, map);
175        assert_eq!(advice.store, store);
176    }
177
178    #[test]
179    fn advice_inputs_from_advice_map_defaults_other_parts() {
180        let map = AdviceMap::from_iter([(Word::default(), vec![Felt::new_unchecked(7)])]);
181
182        let advice = AdviceInputs::from(map.clone());
183
184        assert_eq!(advice.stack(), AdviceStack::default());
185        assert_eq!(advice.map, map);
186        assert_eq!(advice.store, MerkleStore::default());
187    }
188
189    #[test]
190    fn advice_inputs_accept_typed_advice_stack() {
191        let mut stack = AdviceStack::new();
192        stack.append_element(Felt::new_unchecked(1));
193        stack.append_word(
194            [
195                Felt::new_unchecked(2),
196                Felt::new_unchecked(3),
197                Felt::new_unchecked(4),
198                Felt::new_unchecked(5),
199            ]
200            .into(),
201        );
202
203        let advice = AdviceInputs::default().with_stack(stack.clone());
204
205        assert_eq!(advice.stack(), stack);
206    }
207
208    #[test]
209    fn advice_stack_consumes_word_sized_groups_top_first() {
210        let word0: Word = [
211            Felt::new_unchecked(1),
212            Felt::new_unchecked(2),
213            Felt::new_unchecked(3),
214            Felt::new_unchecked(4),
215        ]
216        .into();
217        let word1: Word = [
218            Felt::new_unchecked(5),
219            Felt::new_unchecked(6),
220            Felt::new_unchecked(7),
221            Felt::new_unchecked(8),
222        ]
223        .into();
224        let mut stack = AdviceStack::new();
225
226        stack.append_element(Felt::new_unchecked(0));
227        stack.append_word(word0);
228        stack.append_dword([word1, word0]);
229
230        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(0)));
231        assert_eq!(stack.consume_word(), Some(word0));
232        assert_eq!(stack.consume_dword(), Some([word1, word0]));
233        assert!(stack.is_empty());
234    }
235
236    #[test]
237    fn advice_stack_rejects_partial_dword_without_consuming() {
238        let word: Word = [
239            Felt::new_unchecked(1),
240            Felt::new_unchecked(2),
241            Felt::new_unchecked(3),
242            Felt::new_unchecked(4),
243        ]
244        .into();
245        let mut stack = AdviceStack::new();
246        stack.append_word(word);
247
248        assert_eq!(stack.consume_dword(), None);
249        assert_eq!(stack.consume_word(), Some(word));
250    }
251
252    #[test]
253    fn advice_stack_append_for_adv_push_matches_repeated_consumption() {
254        let values = [Felt::new_unchecked(1), Felt::new_unchecked(2), Felt::new_unchecked(3)];
255        let mut stack = AdviceStack::new();
256        stack.append_for_adv_push(&values);
257
258        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(3)));
259        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(2)));
260        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(1)));
261        assert!(stack.is_empty());
262    }
263
264    #[test]
265    fn advice_stack_append_for_adv_pipe_requires_dword_alignment() {
266        let values: Vec<Felt> = (1..=16).map(Felt::new_unchecked).collect();
267        let mut stack = AdviceStack::new();
268        stack.append_for_adv_pipe(&values);
269
270        assert_eq!(stack.into_elements(), values);
271    }
272
273    #[test]
274    #[should_panic(expected = "append_for_adv_pipe requires slice length to be a multiple of 8")]
275    fn advice_stack_append_for_adv_pipe_panics_on_misalignment() {
276        let values: Vec<Felt> = (1..=7).map(Felt::new_unchecked).collect();
277        let mut stack = AdviceStack::new();
278        stack.append_for_adv_pipe(&values);
279    }
280
281    #[test]
282    fn advice_stack_prepends_new_top_elements() {
283        let mut stack = AdviceStack::from(vec![Felt::new_unchecked(3), Felt::new_unchecked(4)]);
284
285        stack.push_element(Felt::new_unchecked(2));
286        stack.prepend_elements([Felt::new_unchecked(0), Felt::new_unchecked(1)]);
287
288        assert_eq!(
289            stack.into_elements(),
290            vec![
291                Felt::new_unchecked(0),
292                Felt::new_unchecked(1),
293                Felt::new_unchecked(2),
294                Felt::new_unchecked(3),
295                Felt::new_unchecked(4),
296            ]
297        );
298    }
299
300    // INTEGER INPUT TESTS
301    // --------------------------------------------------------------------------------------------
302
303    #[test]
304    fn advice_stack_try_from_values_keeps_top_first_order() {
305        let stack = AdviceStack::try_from_values([1, 2, 3, 4]).unwrap();
306
307        assert_eq!(
308            stack.into_elements(),
309            vec![
310                Felt::new_unchecked(1),
311                Felt::new_unchecked(2),
312                Felt::new_unchecked(3),
313                Felt::new_unchecked(4)
314            ]
315        );
316    }
317}