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}