miden_processor/host/advice/
mod.rs

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