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 /// Note: this operation doesn't consume the map element so it can be called multiple times
143 /// for the same key.
144 ///
145 /// # Example
146 /// Given an advice stack `[a, b, c, ...]`, and a map `x |-> [d, e, f]`:
147 ///
148 /// A call `push_stack(AdviceSource::Map { key: x, include_len: false })` will result in
149 /// advice stack: `[d, e, f, a, b, c, ...]`.
150 ///
151 /// A call `push_stack(AdviceSource::Map { key: x, include_len: true })` will result in
152 /// advice stack: `[3, d, e, f, a, b, c, ...]`.
153 ///
154 /// # Errors
155 /// Returns an error if the key was not found in the key-value map.
156 pub fn push_from_map(&mut self, key: Word, include_len: bool) -> Result<(), AdviceError> {
157 let values = self.map.get(&key).ok_or(AdviceError::MapKeyNotFound { key })?;
158
159 self.stack.extend(values.iter().rev());
160 if include_len {
161 self.stack
162 .push(Felt::try_from(values.len() as u64).expect("value length too big"));
163 }
164 Ok(())
165 }
166
167 /// Returns the current stack.
168 ///
169 /// The element at the top of the stack is in last position of the returned slice.
170 pub fn stack(&self) -> &[Felt] {
171 &self.stack
172 }
173
174 /// Extends the stack with the given elements.
175 ///
176 /// Elements are added to the top of the stack i.e. last element of this iterator is the first
177 /// element popped.
178 pub fn extend_stack<I>(&mut self, iter: I)
179 where
180 I: IntoIterator<Item = Felt>,
181 {
182 self.stack.extend(iter);
183 }
184
185 // ADVICE MAP
186 // --------------------------------------------------------------------------------------------
187
188 /// Returns true if the key has a corresponding value in the map.
189 pub fn contains_map_key(&self, key: &Word) -> bool {
190 self.map.contains_key(key)
191 }
192
193 /// Returns a reference to the value(s) associated with the specified key in the advice map.
194 pub fn get_mapped_values(&self, key: &Word) -> Option<&[Felt]> {
195 self.map.get(key).map(|value| value.as_ref())
196 }
197
198 /// Inserts the provided value into the advice map under the specified key.
199 ///
200 /// The values in the advice map can be moved onto the advice stack by invoking
201 /// the [AdviceProvider::push_from_map()] method.
202 ///
203 /// Returns an error if the specified key is already present in the advice map.
204 pub fn insert_into_map(&mut self, key: Word, values: Vec<Felt>) -> Result<(), AdviceError> {
205 match self.map.entry(key) {
206 Entry::Vacant(entry) => {
207 entry.insert(values.into());
208 },
209 Entry::Occupied(entry) => {
210 let existing_values = entry.get().as_ref();
211 if existing_values != values {
212 return Err(AdviceError::MapKeyAlreadyPresent {
213 key,
214 prev_values: existing_values.to_vec(),
215 new_values: values,
216 });
217 }
218 },
219 }
220 Ok(())
221 }
222
223 /// Merges all entries from the given [`AdviceMap`] into the current advice map.
224 ///
225 /// Returns an error if any new entry already exists with the same key but a different value
226 /// than the one currently stored. The current map remains unchanged.
227 pub fn extend_map(&mut self, other: &AdviceMap) -> Result<(), AdviceError> {
228 self.map.merge(other).map_err(|((key, prev_values), new_values)| {
229 AdviceError::MapKeyAlreadyPresent {
230 key,
231 prev_values: prev_values.to_vec(),
232 new_values: new_values.to_vec(),
233 }
234 })
235 }
236
237 // MERKLE STORE
238 // --------------------------------------------------------------------------------------------
239
240 /// Returns a node at the specified depth and index in a Merkle tree with the given root.
241 ///
242 /// # Errors
243 /// Returns an error if:
244 /// - A Merkle tree for the specified root cannot be found in this advice provider.
245 /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
246 /// by the specified root.
247 /// - Value of the node at the specified depth and index is not known to this advice provider.
248 pub fn get_tree_node(&self, root: Word, depth: Felt, index: Felt) -> Result<Word, AdviceError> {
249 let index = NodeIndex::from_elements(&depth, &index)
250 .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
251 self.store.get_node(root, index).map_err(AdviceError::MerkleStoreLookupFailed)
252 }
253
254 /// Returns true if a path to a node at the specified depth and index in a Merkle tree with the
255 /// specified root exists in this Merkle store.
256 ///
257 /// # Errors
258 /// Returns an error if accessing the Merkle store fails.
259 pub fn has_merkle_path(
260 &self,
261 root: Word,
262 depth: Felt,
263 index: Felt,
264 ) -> Result<bool, AdviceError> {
265 let index = NodeIndex::from_elements(&depth, &index)
266 .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
267
268 // TODO: switch to `MerkleStore::has_path()` once this method is implemented
269 match self.store.get_path(root, index) {
270 Ok(_) => Ok(true),
271 Err(MerkleError::RootNotInStore(..)) => Ok(false),
272 Err(MerkleError::NodeIndexNotFoundInStore(..)) => Ok(false),
273 Err(err) => Err(AdviceError::MerkleStoreLookupFailed(err)),
274 }
275 }
276
277 /// Returns a path to a node at the specified depth and index in a Merkle tree with the
278 /// specified root.
279 ///
280 /// # Errors
281 /// Returns an error if:
282 /// - A Merkle tree for the specified root cannot be found in this advice provider.
283 /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
284 /// by the specified root.
285 /// - Path to the node at the specified depth and index is not known to this advice provider.
286 pub fn get_merkle_path(
287 &self,
288 root: Word,
289 depth: Felt,
290 index: Felt,
291 ) -> Result<MerklePath, AdviceError> {
292 let index = NodeIndex::from_elements(&depth, &index)
293 .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
294 self.store
295 .get_path(root, index)
296 .map(|value| value.path)
297 .map_err(AdviceError::MerkleStoreLookupFailed)
298 }
299
300 /// Updates a node at the specified depth and index in a Merkle tree with the specified root;
301 /// returns the Merkle path from the updated node to the new root, together with the new root.
302 ///
303 /// The tree is cloned prior to the update. Thus, the advice provider retains the original and
304 /// the updated tree.
305 ///
306 /// # Errors
307 /// Returns an error if:
308 /// - A Merkle tree for the specified root cannot be found in this advice provider.
309 /// - The specified depth is either zero or greater than the depth of the Merkle tree identified
310 /// by the specified root.
311 /// - Path to the leaf at the specified index in the specified Merkle tree is not known to this
312 /// advice provider.
313 pub fn update_merkle_node(
314 &mut self,
315 root: Word,
316 depth: Felt,
317 index: Felt,
318 value: Word,
319 ) -> Result<(MerklePath, Word), AdviceError> {
320 let node_index = NodeIndex::from_elements(&depth, &index)
321 .map_err(|_| AdviceError::InvalidMerkleTreeNodeIndex { depth, index })?;
322 self.store
323 .set_node(root, node_index, value)
324 .map(|root| (root.path, root.root))
325 .map_err(AdviceError::MerkleStoreUpdateFailed)
326 }
327
328 /// Creates a new Merkle tree in the advice provider by combining Merkle trees with the
329 /// specified roots. The root of the new tree is defined as `hash(left_root, right_root)`.
330 ///
331 /// After the operation, both the original trees and the new tree remains in the advice
332 /// provider (i.e., the input trees are not removed).
333 ///
334 /// It is not checked whether a Merkle tree for either of the specified roots can be found in
335 /// this advice provider.
336 pub fn merge_roots(&mut self, lhs: Word, rhs: Word) -> Result<Word, AdviceError> {
337 self.store.merge_roots(lhs, rhs).map_err(AdviceError::MerkleStoreMergeFailed)
338 }
339
340 /// Returns true if the Merkle root exists for the advice provider Merkle store.
341 pub fn has_merkle_root(&self, root: Word) -> bool {
342 self.store.get_node(root, NodeIndex::root()).is_ok()
343 }
344
345 /// Extends the [MerkleStore] with the given nodes.
346 pub fn extend_merkle_store<I>(&mut self, iter: I)
347 where
348 I: IntoIterator<Item = InnerNodeInfo>,
349 {
350 self.store.extend(iter);
351 }
352
353 // PRECOMPILE REQUESTS
354 // --------------------------------------------------------------------------------------------
355
356 /// Returns a reference to the precompile requests.
357 ///
358 /// Ordering is the same as the order in which requests are issued during execution. This
359 /// ordering is relied upon when recomputing the precompile sponge during verification.
360 pub fn precompile_requests(&self) -> &[PrecompileRequest] {
361 &self.pc_requests
362 }
363
364 /// Extends the precompile requests with the given entries.
365 pub fn extend_precompile_requests<I>(&mut self, iter: I)
366 where
367 I: IntoIterator<Item = PrecompileRequest>,
368 {
369 self.pc_requests.extend(iter);
370 }
371
372 /// Moves all accumulated precompile requests out of this provider, leaving it empty.
373 ///
374 /// Intended for proof packaging, where requests are serialized into the proof and no longer
375 /// needed in the provider after consumption.
376 pub fn take_precompile_requests(&mut self) -> Vec<PrecompileRequest> {
377 core::mem::take(&mut self.pc_requests)
378 }
379
380 // MUTATORS
381 // --------------------------------------------------------------------------------------------
382
383 /// Extends the contents of this instance with the contents of an `AdviceInputs`.
384 pub fn extend_from_inputs(&mut self, inputs: &AdviceInputs) -> Result<(), AdviceError> {
385 self.extend_stack(inputs.stack.iter().cloned().rev());
386 self.extend_merkle_store(inputs.store.inner_nodes());
387 self.extend_map(&inputs.map)
388 }
389
390 /// Consumes `self` and return its parts (stack, map, store, precompile_requests).
391 ///
392 /// Note that the order of the stack is such that the element at the top of the stack is at the
393 /// end of the returned vector.
394 pub fn into_parts(self) -> (Vec<Felt>, AdviceMap, MerkleStore, Vec<PrecompileRequest>) {
395 (self.stack, self.map, self.store, self.pc_requests)
396 }
397}
398
399impl From<AdviceInputs> for AdviceProvider {
400 fn from(inputs: AdviceInputs) -> Self {
401 let AdviceInputs { mut stack, map, store } = inputs;
402 stack.reverse();
403 Self {
404 stack,
405 map,
406 store,
407 pc_requests: Vec::new(),
408 }
409 }
410}
411
412impl AdviceProviderInterface for AdviceProvider {
413 #[inline(always)]
414 fn pop_stack(&mut self) -> Result<Felt, AdviceError> {
415 self.pop_stack()
416 }
417
418 #[inline(always)]
419 fn pop_stack_word(&mut self) -> Result<Word, AdviceError> {
420 self.pop_stack_word()
421 }
422
423 #[inline(always)]
424 fn pop_stack_dword(&mut self) -> Result<[Word; 2], AdviceError> {
425 self.pop_stack_dword()
426 }
427
428 #[inline(always)]
429 fn get_merkle_path(
430 &self,
431 root: Word,
432 depth: Felt,
433 index: Felt,
434 ) -> Result<Option<MerklePath>, AdviceError> {
435 self.get_merkle_path(root, depth, index).map(Some)
436 }
437
438 #[inline(always)]
439 fn update_merkle_node(
440 &mut self,
441 root: Word,
442 depth: Felt,
443 index: Felt,
444 value: Word,
445 ) -> Result<Option<MerklePath>, AdviceError> {
446 self.update_merkle_node(root, depth, index, value).map(|(path, _)| Some(path))
447 }
448}