Skip to main content

miden_core/advice/
mod.rs

1use alloc::vec::Vec;
2
3use crate::{
4    Felt, Word,
5    crypto::merkle::MerkleStore,
6    field::QuotientMap,
7    program::InputError,
8    serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
9};
10
11mod map;
12pub use map::AdviceMap;
13
14mod stack;
15pub use stack::AdviceStackBuilder;
16
17// ADVICE INPUTS
18// ================================================================================================
19
20/// Inputs container to initialize advice provider for the execution of Miden VM programs.
21///
22/// The program may request nondeterministic advice inputs from the prover. These inputs are secret
23/// inputs. This means that the prover does not need to share them with the verifier.
24///
25/// There are three types of advice inputs:
26///
27/// 1. Single advice stack which can contain any number of elements.
28/// 2. Key-mapped element lists which can be pushed onto the advice stack.
29/// 3. Merkle store, which is used to provide nondeterministic inputs for instructions that operates
30///    with Merkle trees.
31#[derive(Clone, Debug, Default, PartialEq, Eq)]
32pub struct AdviceInputs {
33    pub stack: Vec<Felt>,
34    pub map: AdviceMap,
35    pub store: MerkleStore,
36}
37
38impl AdviceInputs {
39    // CONSTRUCTORS
40    // --------------------------------------------------------------------------------------------
41
42    /// Attempts to extend the stack values with the given sequence of integers, returning an error
43    /// if any of the numbers fails while converting to an element `[Felt]`.
44    pub fn with_stack_values<I>(mut self, iter: I) -> Result<Self, InputError>
45    where
46        I: IntoIterator<Item = u64>,
47    {
48        let stack = iter
49            .into_iter()
50            .map(|v| Felt::from_canonical_checked(v).ok_or(InputError::InvalidStackElement(v)))
51            .collect::<Result<Vec<_>, _>>()?;
52
53        self.stack.extend(stack.iter());
54        Ok(self)
55    }
56
57    /// Extends the stack with the given elements.
58    pub fn with_stack<I>(mut self, iter: I) -> Self
59    where
60        I: IntoIterator<Item = Felt>,
61    {
62        self.stack.extend(iter);
63        self
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.extend(other.stack);
87        self.map.extend(other.map);
88        self.store.extend(other.store.inner_nodes());
89    }
90}
91
92impl Serializable for AdviceInputs {
93    fn write_into<W: ByteWriter>(&self, target: &mut W) {
94        let Self { stack, map, store } = self;
95        stack.write_into(target);
96        map.write_into(target);
97        store.write_into(target);
98    }
99}
100
101impl Deserializable for AdviceInputs {
102    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
103        let stack = Vec::<Felt>::read_from(source)?;
104        let map = AdviceMap::read_from(source)?;
105        let store = MerkleStore::read_from(source)?;
106        Ok(Self { stack, map, store })
107    }
108}
109
110// TESTS
111// ================================================================================================
112
113#[cfg(test)]
114mod tests {
115    use alloc::vec::Vec;
116
117    use super::{AdviceInputs, AdviceStackBuilder};
118    use crate::{
119        Felt, Word,
120        serde::{Deserializable, Serializable},
121    };
122
123    #[test]
124    fn test_advice_inputs_eq() {
125        let advice1 = AdviceInputs::default();
126        let advice2 = AdviceInputs::default();
127
128        assert_eq!(advice1, advice2);
129
130        let advice1 = AdviceInputs::default().with_stack_values([1, 2, 3].iter().copied()).unwrap();
131        let advice2 = AdviceInputs::default().with_stack_values([1, 2, 3].iter().copied()).unwrap();
132
133        assert_eq!(advice1, advice2);
134    }
135
136    #[test]
137    fn test_advice_inputs_serialization() {
138        let advice1 = AdviceInputs::default().with_stack_values([1, 2, 3].iter().copied()).unwrap();
139        let bytes = advice1.to_bytes();
140        let advice2 = AdviceInputs::read_from_bytes(&bytes).unwrap();
141
142        assert_eq!(advice1, advice2);
143    }
144
145    // ADVICE STACK BUILDER TESTS
146    // --------------------------------------------------------------------------------------------
147
148    #[test]
149    fn test_builder_push_for_adv_push() {
150        // push_for_adv_push reverses the slice
151        // Input: [a, b, c] -> Builder stack: [c, b, a] (c on top)
152        let a = Felt::new(1);
153        let b = Felt::new(2);
154        let c = Felt::new(3);
155
156        let mut builder = AdviceStackBuilder::new();
157        builder.push_for_adv_push(&[a, b, c]);
158        let advice = builder.build();
159
160        // Builder stack is [c, b, a] with c on top (index 0)
161        // This becomes AdviceInputs.stack = [c, b, a]
162        assert_eq!(advice.stack, vec![c, b, a]);
163    }
164
165    #[test]
166    fn test_builder_push_for_adv_loadw() {
167        let word: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into();
168
169        let mut builder = AdviceStackBuilder::new();
170        builder.push_for_adv_loadw(word);
171        let advice = builder.build();
172
173        // Builder stack is [w0, w1, w2, w3] with w0 on top
174        assert_eq!(advice.stack, vec![Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]);
175    }
176
177    #[test]
178    fn test_builder_push_for_adv_pipe() {
179        let slice: Vec<Felt> = (1..=8).map(Felt::new).collect();
180
181        let mut builder = AdviceStackBuilder::new();
182        builder.push_for_adv_pipe(&slice);
183        let advice = builder.build();
184
185        assert_eq!(advice.stack, slice);
186    }
187
188    #[test]
189    #[should_panic(expected = "push_for_adv_pipe requires slice length to be a multiple of 8")]
190    fn test_builder_push_for_adv_pipe_panics_on_misalignment() {
191        let slice: Vec<Felt> = (1..=7).map(Felt::new).collect();
192
193        let mut builder = AdviceStackBuilder::new();
194        builder.push_for_adv_pipe(&slice);
195        builder.build();
196    }
197
198    #[test]
199    fn test_builder_push_u64_slice() {
200        // push_u64_slice converts u64 to Felt without reversal
201        let mut builder = AdviceStackBuilder::new();
202        builder.push_u64_slice(&[1, 2, 3, 4]);
203        let advice = builder.build();
204
205        assert_eq!(advice.stack, vec![Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]);
206    }
207
208    #[test]
209    fn test_builder_chaining_top_first() {
210        // First call adds elements consumed first (on top)
211        // Second call adds elements consumed second (below)
212        let a = Felt::new(1);
213        let b = Felt::new(2);
214        let c = Felt::new(3);
215        let word: Word = [Felt::new(10), Felt::new(20), Felt::new(30), Felt::new(40)].into();
216
217        let mut builder = AdviceStackBuilder::new();
218        builder.push_for_adv_push(&[a, b, c]); // Consumed first
219        builder.push_for_adv_loadw(word); // Consumed second
220        let advice = builder.build();
221
222        // Builder stack: [c, b, a, w0, w1, w2, w3]
223        // (c on top from reversed [a,b,c], then word below)
224        assert_eq!(
225            advice.stack,
226            vec![c, b, a, Felt::new(10), Felt::new(20), Felt::new(30), Felt::new(40)]
227        );
228    }
229
230    #[test]
231    fn test_builder_multiple_push_for_adv_push() {
232        // Multiple calls should maintain top-first ordering
233        let first = [Felt::new(1), Felt::new(2)];
234        let second = [Felt::new(3), Felt::new(4)];
235
236        let mut builder = AdviceStackBuilder::new();
237        builder.push_for_adv_push(&first); // Consumed first
238        builder.push_for_adv_push(&second); // Consumed second
239        let advice = builder.build();
240
241        // First call: [2, 1] (reversed)
242        // Second call prepends: [4, 3, 2, 1] -> but wait, second is consumed AFTER first
243        // So second should go BELOW first in the stack
244        // Builder stack after first: [2, 1]
245        // Builder stack after second: [2, 1, 4, 3]
246        assert_eq!(advice.stack, vec![Felt::new(2), Felt::new(1), Felt::new(4), Felt::new(3)]);
247    }
248}