Skip to main content

miden_processor/host/advice/
mod.rs

1use alloc::{
2    collections::{VecDeque, btree_map::Entry},
3    vec::Vec,
4};
5
6use miden_core::{
7    Felt, Word,
8    advice::{AdviceInputs, AdviceMap},
9    crypto::merkle::{InnerNodeInfo, MerkleError, MerklePath, MerkleStore, NodeIndex},
10    precompile::PrecompileRequest,
11};
12
13mod errors;
14pub use errors::AdviceError;
15
16use crate::{host::AdviceMutation, processor::AdviceProviderInterface};
17
18// ADVICE PROVIDER
19// ================================================================================================
20
21/// An advice provider is a component through which the VM can request nondeterministic inputs from
22/// the host (i.e., result of a computation performed outside of the VM), as well as insert new data
23/// into the advice provider to be recovered by the host after the program has finished executing.
24///
25/// An advice provider consists of the following components:
26/// 1. Advice stack, which is a LIFO data structure. The processor can move the elements from the
27///    advice stack onto the operand stack, as well as push new elements onto the advice stack.
28/// 2. Advice map, which is a key-value map where keys are words (4 field elements) and values are
29///    vectors of field elements. The processor can push the values from the map onto the advice
30///    stack, as well as insert new values into the map.
31/// 3. Merkle store, which contains structured data reducible to Merkle paths. The VM can request
32///    Merkle paths from the store, as well as mutate it by updating or merging nodes contained in
33///    the store.
34/// 4. Deferred precompile requests containing the calldata of any precompile requests made by the
35///    VM. The VM computes a commitment to the calldata of all the precompiles it requests. When
36///    verifying each call, this commitment must be recomputed and should match the one computed by
37///    the VM. After executing a program, the data in these requests can either
38///    - be included in the proof of the VM execution and verified natively alongside the VM proof,
39///      or,
40///    - used to produce a STARK proof using a precompile VM, which can be verified in the epilog of
41///      the program.
42#[derive(Debug, Clone, Default)]
43pub struct AdviceProvider {
44    stack: VecDeque<Felt>,
45    map: AdviceMap,
46    store: MerkleStore,
47    pc_requests: Vec<PrecompileRequest>,
48}
49
50impl AdviceProvider {
51    /// Applies the mutations given in order to the `AdviceProvider`.
52    pub fn apply_mutations(
53        &mut self,
54        mutations: impl IntoIterator<Item = AdviceMutation>,
55    ) -> Result<(), AdviceError> {
56        mutations.into_iter().try_for_each(|mutation| self.apply_mutation(mutation))
57    }
58
59    fn apply_mutation(&mut self, mutation: AdviceMutation) -> Result<(), AdviceError> {
60        match mutation {
61            AdviceMutation::ExtendStack { values } => {
62                self.extend_stack(values);
63            },
64            AdviceMutation::ExtendMap { other } => {
65                self.extend_map(&other)?;
66            },
67            AdviceMutation::ExtendMerkleStore { infos } => {
68                self.extend_merkle_store(infos);
69            },
70            AdviceMutation::ExtendPrecompileRequests { data } => {
71                self.extend_precompile_requests(data);
72            },
73        }
74        Ok(())
75    }
76
77    // ADVICE STACK
78    // --------------------------------------------------------------------------------------------
79
80    /// Pops an element from the advice stack and returns it.
81    ///
82    /// # Errors
83    /// Returns an error if the advice stack is empty.
84    fn pop_stack(&mut self) -> Result<Felt, AdviceError> {
85        self.stack.pop_front().ok_or(AdviceError::StackReadFailed)
86    }
87
88    /// Pops a word (4 elements) from the advice stack and returns it.
89    ///
90    /// Note: a word is popped off the stack element-by-element. For example, a `[d, c, b, a, ...]`
91    /// stack (i.e., `d` is at the top of the stack) will yield `[d, c, b, a]`.
92    ///
93    /// # Errors
94    /// Returns an error if the advice stack does not contain a full word.
95    fn pop_stack_word(&mut self) -> Result<Word, AdviceError> {
96        if self.stack.len() < 4 {
97            return Err(AdviceError::StackReadFailed);
98        }
99
100        let w0 = self.stack.pop_front().expect("checked len");
101        let w1 = self.stack.pop_front().expect("checked len");
102        let w2 = self.stack.pop_front().expect("checked len");
103        let w3 = self.stack.pop_front().expect("checked len");
104
105        Ok(Word::new([w0, w1, w2, w3]))
106    }
107
108    /// Pops a double word (8 elements) from the advice stack and returns them.
109    ///
110    /// Note: words are popped off the stack element-by-element. For example, a
111    /// `[h, g, f, e, d, c, b, a, ...]` stack (i.e., `h` is at the top of the stack) will yield
112    /// two words: `[h, g, f,e ], [d, c, b, a]`.
113    ///
114    /// # Errors
115    /// Returns an error if the advice stack does not contain two words.
116    fn pop_stack_dword(&mut self) -> Result<[Word; 2], AdviceError> {
117        let word0 = self.pop_stack_word()?;
118        let word1 = self.pop_stack_word()?;
119
120        Ok([word0, word1])
121    }
122
123    /// Pushes a single value onto the advice stack.
124    pub fn push_stack(&mut self, value: Felt) {
125        self.stack.push_front(value)
126    }
127
128    /// Pushes a word (4 elements) onto the stack.
129    pub fn push_stack_word(&mut self, word: &Word) {
130        for &value in word.iter().rev() {
131            self.stack.push_front(value);
132        }
133    }
134
135    /// Fetches a list of elements under the specified key from the advice map and pushes them onto
136    /// the advice stack.
137    ///
138    /// If `include_len` is set to true, this also pushes the number of elements onto the advice
139    /// stack.
140    ///
141    /// If `pad_to` is not equal to 0, the elements list obtained from the advice map will be padded
142    /// with zeros, increasing its length to the next multiple of `pad_to`.
143    ///
144    /// Note: this operation doesn't consume the map element so it can be called multiple times
145    /// for the same key.
146    ///
147    /// # Example
148    /// Given an advice stack `[a, b, c, ...]`, and a map `x |-> [d, e, f]`:
149    ///
150    /// A call `push_stack(AdviceSource::Map { key: x, include_len: false, pad_to: 0 })` will result
151    /// in advice stack: `[d, e, f, a, b, c, ...]`.
152    ///
153    /// A call `push_stack(AdviceSource::Map { key: x, include_len: true, pad_to: 0 })` will result
154    /// in advice stack: `[3, d, e, f, a, b, c, ...]`.
155    ///
156    /// A call `push_stack(AdviceSource::Map { key: x, include_len: true, pad_to: 4 })` will result
157    /// in advice stack: `[3, d, e, f, 0, a, b, c, ...]`.
158    ///
159    /// # Errors
160    /// Returns an error if the key was not found in the key-value map.
161    pub fn push_from_map(
162        &mut self,
163        key: Word,
164        include_len: bool,
165        pad_to: u8,
166    ) -> Result<(), AdviceError> {
167        let values = self.map.get(&key).ok_or(AdviceError::MapKeyNotFound { key })?;
168
169        // if pad_to was provided (not equal 0), push some zeros to the advice stack so that the
170        // final (padded) elements list length will be the next multiple of pad_to
171        if pad_to != 0 {
172            let num_pad_elements = values.len().next_multiple_of(pad_to as usize) - values.len();
173            for _ in 0..num_pad_elements {
174                self.stack.push_front(Felt::default());
175            }
176        }
177
178        // Treat map values as already canonical sequences of FELTs.
179        // The advice stack is LIFO; extend in reverse so that the first element of `values`
180        // becomes the first element returned by a subsequent `adv_push.*`.
181        for &value in values.iter().rev() {
182            self.stack.push_front(value);
183        }
184        if include_len {
185            self.stack.push_front(Felt::new(values.len() as u64));
186        }
187        Ok(())
188    }
189
190    /// Returns the current stack as a vector ordered from top (index 0) to bottom.
191    pub fn stack(&self) -> Vec<Felt> {
192        self.stack.iter().copied().collect()
193    }
194
195    /// Extends the stack with the given elements.
196    pub fn extend_stack<I>(&mut self, iter: I)
197    where
198        I: IntoIterator<Item = Felt>,
199    {
200        let values: Vec<Felt> = iter.into_iter().collect();
201        for value in values.into_iter().rev() {
202            self.stack.push_front(value);
203        }
204    }
205
206    // ADVICE MAP
207    // --------------------------------------------------------------------------------------------
208
209    /// Returns true if the key has a corresponding value in the map.
210    pub fn contains_map_key(&self, key: &Word) -> bool {
211        self.map.contains_key(key)
212    }
213
214    /// Returns a reference to the value(s) associated with the specified key in the advice map.
215    pub fn get_mapped_values(&self, key: &Word) -> Option<&[Felt]> {
216        self.map.get(key).map(|value| value.as_ref())
217    }
218
219    /// Inserts the provided value into the advice map under the specified key.
220    ///
221    /// The values in the advice map can be moved onto the advice stack by invoking
222    /// the [AdviceProvider::push_from_map()] method.
223    ///
224    /// Returns an error if the specified key is already present in the advice map.
225    pub fn insert_into_map(&mut self, key: Word, values: Vec<Felt>) -> Result<(), AdviceError> {
226        match self.map.entry(key) {
227            Entry::Vacant(entry) => {
228                entry.insert(values.into());
229            },
230            Entry::Occupied(entry) => {
231                let existing_values = entry.get().as_ref();
232                if existing_values != values {
233                    return Err(AdviceError::MapKeyAlreadyPresent {
234                        key,
235                        prev_values: existing_values.to_vec(),
236                        new_values: values,
237                    });
238                }
239            },
240        }
241        Ok(())
242    }
243
244    /// Merges all entries from the given [`AdviceMap`] into the current advice map.
245    ///
246    /// Returns an error if any new entry already exists with the same key but a different value
247    /// than the one currently stored. The current map remains unchanged.
248    pub fn extend_map(&mut self, other: &AdviceMap) -> Result<(), AdviceError> {
249        self.map.merge(other).map_err(|((key, prev_values), new_values)| {
250            AdviceError::MapKeyAlreadyPresent {
251                key,
252                prev_values: prev_values.to_vec(),
253                new_values: new_values.to_vec(),
254            }
255        })
256    }
257
258    // MERKLE STORE
259    // --------------------------------------------------------------------------------------------
260
261    /// Returns a node at the specified depth and index in a Merkle tree with the given root.
262    ///
263    /// # Errors
264    /// Returns an error if:
265    /// - A Merkle tree for the specified root cannot be found in this advice provider.
266    /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
267    ///   by the specified root.
268    /// - Value of the node at the specified depth and index is not known to this advice provider.
269    pub fn get_tree_node(&self, root: Word, depth: Felt, index: Felt) -> Result<Word, AdviceError> {
270        let index = NodeIndex::from_elements(&depth, &index)
271            .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
272        self.store.get_node(root, index).map_err(AdviceError::MerkleStoreLookupFailed)
273    }
274
275    /// Returns true if a path to a node at the specified depth and index in a Merkle tree with the
276    /// specified root exists in this Merkle store.
277    ///
278    /// # Errors
279    /// Returns an error if accessing the Merkle store fails.
280    pub fn has_merkle_path(
281        &self,
282        root: Word,
283        depth: Felt,
284        index: Felt,
285    ) -> Result<bool, AdviceError> {
286        let index = NodeIndex::from_elements(&depth, &index)
287            .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
288
289        // TODO: switch to `MerkleStore::has_path()` once this method is implemented
290        match self.store.get_path(root, index) {
291            Ok(_) => Ok(true),
292            Err(MerkleError::RootNotInStore(..)) => Ok(false),
293            Err(MerkleError::NodeIndexNotFoundInStore(..)) => Ok(false),
294            Err(err) => Err(AdviceError::MerkleStoreLookupFailed(err)),
295        }
296    }
297
298    /// Returns a path to a node at the specified depth and index in a Merkle tree with the
299    /// specified root.
300    ///
301    /// # Errors
302    /// Returns an error if:
303    /// - A Merkle tree for the specified root cannot be found in this advice provider.
304    /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
305    ///   by the specified root.
306    /// - Path to the node at the specified depth and index is not known to this advice provider.
307    pub fn get_merkle_path(
308        &self,
309        root: Word,
310        depth: Felt,
311        index: Felt,
312    ) -> Result<MerklePath, AdviceError> {
313        let index = NodeIndex::from_elements(&depth, &index)
314            .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
315        self.store
316            .get_path(root, index)
317            .map(|value| value.path)
318            .map_err(AdviceError::MerkleStoreLookupFailed)
319    }
320
321    /// Updates a node at the specified depth and index in a Merkle tree with the specified root;
322    /// returns the Merkle path from the updated node to the new root, together with the new root.
323    ///
324    /// The tree is cloned prior to the update. Thus, the advice provider retains the original and
325    /// the updated tree.
326    ///
327    /// # Errors
328    /// Returns an error if:
329    /// - A Merkle tree for the specified root cannot be found in this advice provider.
330    /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
331    ///   by the specified root.
332    /// - Path to the leaf at the specified index in the specified Merkle tree is not known to this
333    ///   advice provider.
334    pub fn update_merkle_node(
335        &mut self,
336        root: Word,
337        depth: Felt,
338        index: Felt,
339        value: Word,
340    ) -> Result<(MerklePath, Word), AdviceError> {
341        let node_index = NodeIndex::from_elements(&depth, &index)
342            .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
343        self.store
344            .set_node(root, node_index, value)
345            .map(|root| (root.path, root.root))
346            .map_err(AdviceError::MerkleStoreUpdateFailed)
347    }
348
349    /// Creates a new Merkle tree in the advice provider by combining Merkle trees with the
350    /// specified roots. The root of the new tree is defined as `hash(left_root, right_root)`.
351    ///
352    /// After the operation, both the original trees and the new tree remains in the advice
353    /// provider (i.e., the input trees are not removed).
354    ///
355    /// It is not checked whether a Merkle tree for either of the specified roots can be found in
356    /// this advice provider.
357    pub fn merge_roots(&mut self, lhs: Word, rhs: Word) -> Result<Word, AdviceError> {
358        self.store.merge_roots(lhs, rhs).map_err(AdviceError::MerkleStoreMergeFailed)
359    }
360
361    /// Returns true if the Merkle root exists for the advice provider Merkle store.
362    pub fn has_merkle_root(&self, root: Word) -> bool {
363        self.store.get_node(root, NodeIndex::root()).is_ok()
364    }
365
366    /// Extends the [MerkleStore] with the given nodes.
367    pub fn extend_merkle_store<I>(&mut self, iter: I)
368    where
369        I: IntoIterator<Item = InnerNodeInfo>,
370    {
371        self.store.extend(iter);
372    }
373
374    // PRECOMPILE REQUESTS
375    // --------------------------------------------------------------------------------------------
376
377    /// Returns a reference to the precompile requests.
378    ///
379    /// Ordering is the same as the order in which requests are issued during execution. This
380    /// ordering is relied upon when recomputing the precompile sponge during verification.
381    pub fn precompile_requests(&self) -> &[PrecompileRequest] {
382        &self.pc_requests
383    }
384
385    /// Extends the precompile requests with the given entries.
386    pub fn extend_precompile_requests<I>(&mut self, iter: I)
387    where
388        I: IntoIterator<Item = PrecompileRequest>,
389    {
390        self.pc_requests.extend(iter);
391    }
392
393    /// Moves all accumulated precompile requests out of this provider, leaving it empty.
394    ///
395    /// Intended for proof packaging, where requests are serialized into the proof and no longer
396    /// needed in the provider after consumption.
397    pub fn take_precompile_requests(&mut self) -> Vec<PrecompileRequest> {
398        core::mem::take(&mut self.pc_requests)
399    }
400
401    // MUTATORS
402    // --------------------------------------------------------------------------------------------
403
404    /// Extends the contents of this instance with the contents of an `AdviceInputs`.
405    pub fn extend_from_inputs(&mut self, inputs: &AdviceInputs) -> Result<(), AdviceError> {
406        self.extend_stack(inputs.stack.iter().cloned());
407        self.extend_merkle_store(inputs.store.inner_nodes());
408        self.extend_map(&inputs.map)
409    }
410
411    /// Consumes `self` and return its parts (stack, map, store, precompile_requests).
412    ///
413    /// The returned stack vector is ordered from top (index 0) to bottom.
414    pub fn into_parts(self) -> (Vec<Felt>, AdviceMap, MerkleStore, Vec<PrecompileRequest>) {
415        (self.stack.into_iter().collect(), self.map, self.store, self.pc_requests)
416    }
417}
418
419impl From<AdviceInputs> for AdviceProvider {
420    fn from(inputs: AdviceInputs) -> Self {
421        let AdviceInputs { stack, map, store } = inputs;
422        Self {
423            stack: VecDeque::from(stack),
424            map,
425            store,
426            pc_requests: Vec::new(),
427        }
428    }
429}
430
431// ADVICE PROVIDER INTERFACE IMPLEMENTATION
432// ================================================================================================
433
434impl AdviceProviderInterface for AdviceProvider {
435    #[inline(always)]
436    fn pop_stack(&mut self) -> Result<Felt, AdviceError> {
437        self.pop_stack()
438    }
439
440    #[inline(always)]
441    fn pop_stack_word(&mut self) -> Result<Word, AdviceError> {
442        self.pop_stack_word()
443    }
444
445    #[inline(always)]
446    fn pop_stack_dword(&mut self) -> Result<[Word; 2], AdviceError> {
447        self.pop_stack_dword()
448    }
449
450    #[inline(always)]
451    fn get_merkle_path(
452        &self,
453        root: Word,
454        depth: Felt,
455        index: Felt,
456    ) -> Result<Option<MerklePath>, AdviceError> {
457        self.get_merkle_path(root, depth, index).map(Some)
458    }
459
460    #[inline(always)]
461    fn update_merkle_node(
462        &mut self,
463        root: Word,
464        depth: Felt,
465        index: Felt,
466        value: Word,
467    ) -> Result<Option<MerklePath>, AdviceError> {
468        self.update_merkle_node(root, depth, index, value).map(|(path, _)| Some(path))
469    }
470}