miden_processor/host/advice/
mod.rs

1use alloc::{collections::BTreeMap, vec::Vec};
2
3use miden_core::{
4    AdviceMap, Felt, Word,
5    crypto::merkle::{MerklePath, MerkleStore, NodeIndex, StoreNode},
6};
7
8mod inputs;
9pub use inputs::AdviceInputs;
10
11mod errors;
12pub use errors::AdviceError;
13
14// TYPE ALIASES
15// ================================================================================================
16
17type SimpleMerkleMap = BTreeMap<Word, StoreNode>;
18
19// ADVICE PROVIDER
20// ================================================================================================
21
22/// An advice provider is a component through which the host can interact with the advice provider.
23/// The host can request nondeterministic inputs from the advice provider (i.e., result of a
24/// computation performed outside of the VM), as well as insert new data into the advice provider.
25///
26/// An advice provider consists of the following components:
27/// 1. Advice stack, which is a LIFO data structure. The processor can move the elements from the
28///    advice stack onto the operand stack, as well as push new elements onto the advice stack.
29/// 2. Advice map, which is a key-value map where keys are words (4 field elements) and values are
30///    vectors of field elements. The processor can push the values from the map onto the advice
31///    stack, as well as insert new values into the map.
32/// 3. Merkle store, which contains structured data reducible to Merkle paths. The VM can request
33///    Merkle paths from the store, as well as mutate it by updating or merging nodes contained in
34///    the store.
35///
36/// Advice data is store in-memory using [BTreeMap]s as its backing storage.
37#[derive(Debug, Clone, Default)]
38pub struct AdviceProvider {
39    pub stack: Vec<Felt>,
40    pub map: AdviceMap,
41    pub store: MerkleStore<SimpleMerkleMap>,
42}
43
44impl AdviceProvider {
45    // ADVICE STACK
46    // --------------------------------------------------------------------------------------------
47
48    /// Pops an element from the advice stack and returns it.
49    ///
50    /// # Errors
51    /// Returns an error if the advice stack is empty.
52    pub fn pop_stack(&mut self) -> Result<Felt, AdviceError> {
53        self.stack.pop().ok_or(AdviceError::StackReadFailed)
54    }
55
56    /// Pops a word (4 elements) from the advice stack and returns it.
57    ///
58    /// Note: a word is popped off the stack element-by-element. For example, a `[d, c, b, a, ...]`
59    /// stack (i.e., `d` is at the top of the stack) will yield `[d, c, b, a]`.
60    ///
61    /// # Errors
62    /// Returns an error if the advice stack does not contain a full word.
63    pub fn pop_stack_word(&mut self) -> Result<Word, AdviceError> {
64        if self.stack.len() < 4 {
65            return Err(AdviceError::StackReadFailed);
66        }
67
68        let idx = self.stack.len() - 4;
69        let result =
70            [self.stack[idx + 3], self.stack[idx + 2], self.stack[idx + 1], self.stack[idx]];
71
72        self.stack.truncate(idx);
73
74        Ok(result.into())
75    }
76
77    /// Pops a double word (8 elements) from the advice stack and returns them.
78    ///
79    /// Note: words are popped off the stack element-by-element. For example, a
80    /// `[h, g, f, e, d, c, b, a, ...]` stack (i.e., `h` is at the top of the stack) will yield
81    /// two words: `[h, g, f,e ], [d, c, b, a]`.
82    ///
83    /// # Errors
84    /// Returns an error if the advice stack does not contain two words.
85    pub fn pop_stack_dword(&mut self) -> Result<[Word; 2], AdviceError> {
86        let word0 = self.pop_stack_word()?;
87        let word1 = self.pop_stack_word()?;
88
89        Ok([word0, word1])
90    }
91
92    /// Pushes a single value onto the advice stack.
93    pub fn push_stack(&mut self, value: Felt) {
94        self.stack.push(value)
95    }
96
97    /// Pushes a word (4 elements) onto the stack.
98    pub fn push_stack_word(&mut self, word: &Word) {
99        self.stack.extend(word.iter().rev())
100    }
101
102    /// Fetches a list of elements under the specified key from the advice map and pushes them onto
103    /// the advice stack.
104    ///
105    /// If `include_len` is set to true, this also pushes the number of elements onto the advice
106    /// stack.
107    ///
108    /// Note: this operation doesn't consume the map element so it can be called multiple times
109    /// for the same key.
110    ///
111    /// # Example
112    /// Given an advice stack `[a, b, c, ...]`, and a map `x |-> [d, e, f]`:
113    ///
114    /// A call `push_stack(AdviceSource::Map { key: x, include_len: false })` will result in
115    /// advice stack: `[d, e, f, a, b, c, ...]`.
116    ///
117    /// A call `push_stack(AdviceSource::Map { key: x, include_len: true })` will result in
118    /// advice stack: `[3, d, e, f, a, b, c, ...]`.
119    ///
120    /// # Errors
121    /// Returns an error if the key was not found in the key-value map.
122    pub fn push_from_map(&mut self, key: Word, include_len: bool) -> Result<(), AdviceError> {
123        let values = self.map.get(&key).ok_or(AdviceError::MapKeyNotFound { key })?;
124
125        self.stack.extend(values.iter().rev());
126        if include_len {
127            self.stack
128                .push(Felt::try_from(values.len() as u64).expect("value length too big"));
129        }
130        Ok(())
131    }
132
133    /// Returns the current stack.
134    pub fn stack(&self) -> &[Felt] {
135        &self.stack
136    }
137
138    // ADVICE MAP
139    // --------------------------------------------------------------------------------------------
140
141    /// Returns a reference to the value(s) associated with the specified key in the advice map.
142    pub fn get_mapped_values(&self, key: &Word) -> Result<&[Felt], AdviceError> {
143        self.map.get(key).ok_or(AdviceError::MapKeyNotFound { key: *key })
144    }
145
146    /// Inserts the provided value into the advice map under the specified key.
147    ///
148    /// The values in the advice map can be moved onto the advice stack by invoking
149    /// the [AdviceProvider::push_stack()] method.
150    ///
151    /// Returns an error if the specified key is already present in the advice map.
152    pub fn insert_into_map(&mut self, key: Word, values: Vec<Felt>) {
153        self.map.insert(key, values);
154    }
155
156    /// Merges all entries from the given [`AdviceMap`] into the current advice map.
157    ///
158    /// Returns an error if any new entry already exists with the same key but a different value
159    /// than the one currently stored. The current map remains unchanged.
160    pub fn merge_advice_map(&mut self, other: &AdviceMap) -> Result<(), AdviceError> {
161        self.map.merge_advice_map(other).map_err(|((key, prev_values), new_values)| {
162            AdviceError::MapKeyAlreadyPresent { key, prev_values, new_values }
163        })
164    }
165
166    // MERKLE STORE
167    // --------------------------------------------------------------------------------------------
168
169    /// Returns a node at the specified depth and index in a Merkle tree with the given root.
170    ///
171    /// # Errors
172    /// Returns an error if:
173    /// - A Merkle tree for the specified root cannot be found in this advice provider.
174    /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
175    ///   by the specified root.
176    /// - Value of the node at the specified depth and index is not known to this advice provider.
177    pub fn get_tree_node(
178        &self,
179        root: Word,
180        depth: &Felt,
181        index: &Felt,
182    ) -> Result<Word, AdviceError> {
183        let index = NodeIndex::from_elements(depth, index).map_err(|_| {
184            AdviceError::InvalidMerkleTreeNodeIndex { depth: *depth, index: *index }
185        })?;
186        self.store.get_node(root, index).map_err(AdviceError::MerkleStoreLookupFailed)
187    }
188
189    /// Returns a path to a node at the specified depth and index in a Merkle tree with the
190    /// specified root.
191    ///
192    /// # Errors
193    /// Returns an error if:
194    /// - A Merkle tree for the specified root cannot be found in this advice provider.
195    /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
196    ///   by the specified root.
197    /// - Path to the node at the specified depth and index is not known to this advice provider.
198    pub fn get_merkle_path(
199        &self,
200        root: Word,
201        depth: &Felt,
202        index: &Felt,
203    ) -> Result<MerklePath, AdviceError> {
204        let index = NodeIndex::from_elements(depth, index).map_err(|_| {
205            AdviceError::InvalidMerkleTreeNodeIndex { depth: *depth, index: *index }
206        })?;
207        self.store
208            .get_path(root, index)
209            .map(|value| value.path)
210            .map_err(AdviceError::MerkleStoreLookupFailed)
211    }
212
213    /// Updates a node at the specified depth and index in a Merkle tree with the specified root;
214    /// returns the Merkle path from the updated node to the new root, together with the new root.
215    ///
216    /// The tree is cloned prior to the update. Thus, the advice provider retains the original and
217    /// the updated tree.
218    ///
219    /// # Errors
220    /// Returns an error if:
221    /// - A Merkle tree for the specified root cannot be found in this advice provider.
222    /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
223    ///   by the specified root.
224    /// - Path to the leaf at the specified index in the specified Merkle tree is not known to this
225    ///   advice provider.
226    pub fn update_merkle_node(
227        &mut self,
228        root: Word,
229        depth: &Felt,
230        index: &Felt,
231        value: Word,
232    ) -> Result<(MerklePath, Word), AdviceError> {
233        let node_index = NodeIndex::from_elements(depth, index).map_err(|_| {
234            AdviceError::InvalidMerkleTreeNodeIndex { depth: *depth, index: *index }
235        })?;
236        self.store
237            .set_node(root, node_index, value)
238            .map(|root| (root.path, root.root))
239            .map_err(AdviceError::MerkleStoreUpdateFailed)
240    }
241
242    /// Creates a new Merkle tree in the advice provider by combining Merkle trees with the
243    /// specified roots. The root of the new tree is defined as `hash(left_root, right_root)`.
244    ///
245    /// After the operation, both the original trees and the new tree remains in the advice
246    /// provider (i.e., the input trees are not removed).
247    ///
248    /// It is not checked whether a Merkle tree for either of the specified roots can be found in
249    /// this advice provider.
250    pub fn merge_roots(&mut self, lhs: Word, rhs: Word) -> Result<Word, AdviceError> {
251        self.store.merge_roots(lhs, rhs).map_err(AdviceError::MerkleStoreMergeFailed)
252    }
253
254    /// Returns true if the Merkle root exists for the advice provider Merkle store.
255    pub fn has_merkle_root(&self, root: Word) -> bool {
256        self.store.get_node(root, NodeIndex::root()).is_ok()
257    }
258}
259
260impl From<AdviceInputs> for AdviceProvider {
261    fn from(inputs: AdviceInputs) -> Self {
262        let (mut stack, map, store) = inputs.into_parts();
263        stack.reverse();
264        Self { stack, map, store }
265    }
266}