miden_processor/
utils.rs

1use alloc::{sync::Arc, vec::Vec};
2
3use miden_air::RowIndex;
4use miden_core::mast::{ExternalNode, MastForest, MastNodeId};
5// RE-EXPORTS
6// ================================================================================================
7pub use miden_core::utils::*;
8
9use super::{AdviceProvider, Felt};
10use crate::{AsyncHost, ExecutionError, SyncHost};
11
12// HELPER FUNCTIONS
13// ================================================================================================
14
15/// Returns the number of rows in the provided execution trace assumed to be in column-major form
16/// and contain at least one column.
17pub(crate) fn get_trace_len(trace: &[Vec<Felt>]) -> usize {
18    trace[0].len()
19}
20
21/// Splits an element into two field elements containing 32-bit integer values
22#[inline(always)]
23pub(crate) fn split_element(value: Felt) -> (Felt, Felt) {
24    let value = value.as_int();
25    let lo = (value as u32) as u64;
26    let hi = value >> 32;
27    (Felt::new(hi), Felt::new(lo))
28}
29
30/// Splits an element into two 16 bit integer limbs. It assumes that the field element contains a
31/// valid 32-bit integer value.
32pub(crate) fn split_element_u32_into_u16(value: Felt) -> (Felt, Felt) {
33    let (hi, lo) = split_u32_into_u16(value.as_int());
34    (Felt::new(hi as u64), Felt::new(lo as u64))
35}
36
37/// Splits a u64 integer assumed to contain a 32-bit value into two u16 integers.
38///
39/// # Errors
40/// Fails in debug mode if the provided value is not a 32-bit value.
41pub(crate) fn split_u32_into_u16(value: u64) -> (u16, u16) {
42    const U32MAX: u64 = u32::MAX as u64;
43    debug_assert!(value <= U32MAX, "not a 32-bit value");
44
45    let lo = value as u16;
46    let hi = (value >> 16) as u16;
47
48    (hi, lo)
49}
50
51/// Resolves an external node reference to a procedure root using the `MastForest` store in the
52/// provided host.
53///
54/// This helper function is extracted to ensure that [`crate::Process`] and
55/// [`crate::fast::FastProcessor`] resolve external nodes in the same way.
56pub(crate) fn resolve_external_node(
57    external_node: &ExternalNode,
58    advice_provider: &mut AdviceProvider,
59    host: &impl SyncHost,
60) -> Result<(MastNodeId, Arc<MastForest>), ExecutionError> {
61    let node_digest = external_node.digest();
62    let mast_forest = host
63        .get_mast_forest(&node_digest)
64        .ok_or(ExecutionError::no_mast_forest_with_procedure(node_digest, &()))?;
65
66    // We limit the parts of the program that can be called externally to procedure
67    // roots, even though MAST doesn't have that restriction.
68    let root_id = mast_forest
69        .find_procedure_root(node_digest)
70        .ok_or(ExecutionError::malfored_mast_forest_in_host(node_digest, &()))?;
71
72    // if the node that we got by looking up an external reference is also an External
73    // node, we are about to enter into an infinite loop - so, return an error
74    if mast_forest[root_id].is_external() {
75        return Err(ExecutionError::CircularExternalNode(node_digest));
76    }
77
78    // TODO(#1949):
79    //  We should keep track which MastForest AdviceMaps were inserted to avoid
80    //  the duplicate check over the looked up forest.
81    advice_provider
82        .merge_advice_map(mast_forest.advice_map())
83        .map_err(|err| ExecutionError::advice_error(err, RowIndex::from(0), &()))?;
84
85    Ok((root_id, mast_forest))
86}
87
88/// Analogous to [`resolve_external_node`], but for asynchronous execution.
89pub(crate) async fn resolve_external_node_async(
90    external_node: &ExternalNode,
91    advice_provider: &mut AdviceProvider,
92    host: &mut impl AsyncHost,
93) -> Result<(MastNodeId, Arc<MastForest>), ExecutionError> {
94    let node_digest = external_node.digest();
95    let mast_forest = host
96        .get_mast_forest(&node_digest)
97        .await
98        .ok_or(ExecutionError::no_mast_forest_with_procedure(node_digest, &()))?;
99
100    // We limit the parts of the program that can be called externally to procedure
101    // roots, even though MAST doesn't have that restriction.
102    let root_id = mast_forest
103        .find_procedure_root(node_digest)
104        .ok_or(ExecutionError::malfored_mast_forest_in_host(node_digest, &()))?;
105
106    // if the node that we got by looking up an external reference is also an External
107    // node, we are about to enter into an infinite loop - so, return an error
108    if mast_forest[root_id].is_external() {
109        return Err(ExecutionError::CircularExternalNode(node_digest));
110    }
111
112    // TODO(#1949):
113    //  We should keep track which MastForest AdviceMaps were inserted to avoid
114    //  the duplicate check over the looked up forest.
115    advice_provider
116        .merge_advice_map(mast_forest.advice_map())
117        .map_err(|err| ExecutionError::advice_error(err, RowIndex::from(0), &()))?;
118
119    Ok((root_id, mast_forest))
120}