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    advice_stack: AdviceStack,
32    pub map: AdviceMap,
33    pub store: MerkleStore,
34}
35
36impl AdviceInputs {
37    // CONSTRUCTORS
38    // --------------------------------------------------------------------------------------------
39
40    /// Replaces the advice stack with the provided typed stack.
41    pub fn with_advice_stack(mut self, stack: AdviceStack) -> Self {
42        self.advice_stack = stack;
43        self
44    }
45
46    /// Returns the advice stack as a typed stack.
47    pub fn advice_stack(&self) -> AdviceStack {
48        self.advice_stack.clone()
49    }
50
51    /// Extends the map of values with the given argument, replacing previously inserted items.
52    pub fn with_map<I>(mut self, iter: I) -> Self
53    where
54        I: IntoIterator<Item = (Word, Vec<Felt>)>,
55    {
56        self.map.extend(iter);
57        self
58    }
59
60    /// Replaces the [MerkleStore] with the provided argument.
61    pub fn with_merkle_store(mut self, store: MerkleStore) -> Self {
62        self.store = store;
63        self
64    }
65
66    // PUBLIC MUTATORS
67    // --------------------------------------------------------------------------------------------
68
69    /// Extends the contents of this instance with the contents of the other instance.
70    pub fn extend(&mut self, other: Self) {
71        self.advice_stack.append_elements(other.advice_stack.into_elements());
72        self.map.extend(other.map);
73        self.store.extend(other.store.inner_nodes());
74    }
75
76    /// Consumes this instance and returns its parts.
77    pub fn into_parts(self) -> (AdviceStack, AdviceMap, MerkleStore) {
78        (self.advice_stack, self.map, self.store)
79    }
80}
81
82impl Serializable for AdviceInputs {
83    fn write_into<W: ByteWriter>(&self, target: &mut W) {
84        let Self { advice_stack, map, store } = self;
85        let stack: Vec<Felt> = advice_stack.iter().copied().collect();
86        stack.write_into(target);
87        map.write_into(target);
88        store.write_into(target);
89    }
90}
91
92impl Deserializable for AdviceInputs {
93    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
94        let stack = Vec::<Felt>::read_from(source)?;
95        let map = AdviceMap::read_from(source)?;
96        let store = MerkleStore::read_from(source)?;
97        Ok(Self { advice_stack: stack.into(), map, store })
98    }
99}
100
101// TESTS
102// ================================================================================================
103
104#[cfg(test)]
105mod tests {
106    use alloc::vec::Vec;
107
108    use super::{AdviceInputs, AdviceStack};
109    use crate::{
110        Felt, Word,
111        serde::{Deserializable, Serializable},
112    };
113
114    #[test]
115    fn test_advice_inputs_eq() {
116        let advice1 = AdviceInputs::default();
117        let advice2 = AdviceInputs::default();
118
119        assert_eq!(advice1, advice2);
120
121        let advice1 = AdviceInputs::default()
122            .with_advice_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
123        let advice2 = AdviceInputs::default()
124            .with_advice_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
125
126        assert_eq!(advice1, advice2);
127    }
128
129    #[test]
130    fn test_advice_inputs_serialization() {
131        let advice1 = AdviceInputs::default()
132            .with_advice_stack(AdviceStack::try_from_values([1, 2, 3]).unwrap());
133        let bytes = advice1.to_bytes();
134        let advice2 = AdviceInputs::read_from_bytes(&bytes).unwrap();
135
136        assert_eq!(advice1, advice2);
137    }
138
139    #[test]
140    fn advice_inputs_accept_typed_advice_stack() {
141        let mut stack = AdviceStack::new();
142        stack.append_element(Felt::new_unchecked(1));
143        stack.append_word(
144            [
145                Felt::new_unchecked(2),
146                Felt::new_unchecked(3),
147                Felt::new_unchecked(4),
148                Felt::new_unchecked(5),
149            ]
150            .into(),
151        );
152
153        let advice = AdviceInputs::default().with_advice_stack(stack.clone());
154
155        assert_eq!(advice.advice_stack(), stack);
156    }
157
158    #[test]
159    fn advice_stack_consumes_word_sized_groups_top_first() {
160        let word0: Word = [
161            Felt::new_unchecked(1),
162            Felt::new_unchecked(2),
163            Felt::new_unchecked(3),
164            Felt::new_unchecked(4),
165        ]
166        .into();
167        let word1: Word = [
168            Felt::new_unchecked(5),
169            Felt::new_unchecked(6),
170            Felt::new_unchecked(7),
171            Felt::new_unchecked(8),
172        ]
173        .into();
174        let mut stack = AdviceStack::new();
175
176        stack.append_element(Felt::new_unchecked(0));
177        stack.append_word(word0);
178        stack.append_dword([word1, word0]);
179
180        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(0)));
181        assert_eq!(stack.consume_word(), Some(word0));
182        assert_eq!(stack.consume_dword(), Some([word1, word0]));
183        assert!(stack.is_empty());
184    }
185
186    #[test]
187    fn advice_stack_rejects_partial_dword_without_consuming() {
188        let word: Word = [
189            Felt::new_unchecked(1),
190            Felt::new_unchecked(2),
191            Felt::new_unchecked(3),
192            Felt::new_unchecked(4),
193        ]
194        .into();
195        let mut stack = AdviceStack::new();
196        stack.append_word(word);
197
198        assert_eq!(stack.consume_dword(), None);
199        assert_eq!(stack.consume_word(), Some(word));
200    }
201
202    #[test]
203    fn advice_stack_append_for_adv_push_matches_repeated_consumption() {
204        let values = [Felt::new_unchecked(1), Felt::new_unchecked(2), Felt::new_unchecked(3)];
205        let mut stack = AdviceStack::new();
206        stack.append_for_adv_push(&values);
207
208        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(3)));
209        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(2)));
210        assert_eq!(stack.consume_element(), Some(Felt::new_unchecked(1)));
211        assert!(stack.is_empty());
212    }
213
214    #[test]
215    fn advice_stack_append_for_adv_pipe_requires_dword_alignment() {
216        let values: Vec<Felt> = (1..=16).map(Felt::new_unchecked).collect();
217        let mut stack = AdviceStack::new();
218        stack.append_for_adv_pipe(&values);
219
220        assert_eq!(stack.into_elements(), values);
221    }
222
223    #[test]
224    #[should_panic(expected = "append_for_adv_pipe requires slice length to be a multiple of 8")]
225    fn advice_stack_append_for_adv_pipe_panics_on_misalignment() {
226        let values: Vec<Felt> = (1..=7).map(Felt::new_unchecked).collect();
227        let mut stack = AdviceStack::new();
228        stack.append_for_adv_pipe(&values);
229    }
230
231    #[test]
232    fn advice_stack_prepends_new_top_elements() {
233        let mut stack = AdviceStack::from(vec![Felt::new_unchecked(3), Felt::new_unchecked(4)]);
234
235        stack.push_element(Felt::new_unchecked(2));
236        stack.prepend_elements([Felt::new_unchecked(0), Felt::new_unchecked(1)]);
237
238        assert_eq!(
239            stack.into_elements(),
240            vec![
241                Felt::new_unchecked(0),
242                Felt::new_unchecked(1),
243                Felt::new_unchecked(2),
244                Felt::new_unchecked(3),
245                Felt::new_unchecked(4),
246            ]
247        );
248    }
249
250    // INTEGER INPUT TESTS
251    // --------------------------------------------------------------------------------------------
252
253    #[test]
254    fn advice_stack_try_from_values_keeps_top_first_order() {
255        let stack = AdviceStack::try_from_values([1, 2, 3, 4]).unwrap();
256
257        assert_eq!(
258            stack.into_elements(),
259            vec![
260                Felt::new_unchecked(1),
261                Felt::new_unchecked(2),
262                Felt::new_unchecked(3),
263                Felt::new_unchecked(4)
264            ]
265        );
266    }
267}