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///
30/// Serialization includes the `MerkleStore` format header and version. Encodings containing an
31/// unversioned store are rejected.
32#[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    // CONSTRUCTORS
45    // --------------------------------------------------------------------------------------------
46
47    /// Creates a new advice inputs container from the provided stack, map, and Merkle store.
48    pub fn new(stack: AdviceStack, map: AdviceMap, store: MerkleStore) -> Self {
49        Self { stack, map, store }
50    }
51
52    /// Replaces the stack with the provided typed stack.
53    pub fn with_stack(mut self, stack: AdviceStack) -> Self {
54        self.stack = stack;
55        self
56    }
57
58    /// Returns the advice stack.
59    pub fn stack(&self) -> AdviceStack {
60        self.stack.clone()
61    }
62
63    /// Returns the advice map.
64    pub fn map(&self) -> &AdviceMap {
65        &self.map
66    }
67
68    /// Returns the Merkle store.
69    pub fn store(&self) -> &MerkleStore {
70        &self.store
71    }
72
73    /// Extends the map of values with the given argument, replacing previously inserted items.
74    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    /// Replaces the [MerkleStore] with the provided argument.
83    pub fn with_merkle_store(mut self, store: MerkleStore) -> Self {
84        self.store = store;
85        self
86    }
87
88    // PUBLIC MUTATORS
89    // --------------------------------------------------------------------------------------------
90
91    /// Extends the contents of this instance with the contents of the other instance.
92    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    /// Consumes this instance and returns its parts.
99    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// TESTS
134// ================================================================================================
135
136#[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        // An unversioned empty store contains only its u64 node count.
177        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    // INTEGER INPUT TESTS
321    // --------------------------------------------------------------------------------------------
322
323    #[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}