1#![no_std]
2#![cfg_attr(test, allow(clippy::needless_range_loop))]
5
6#[macro_use]
7extern crate alloc;
8
9#[cfg(feature = "std")]
10extern crate std;
11
12use alloc::vec::Vec;
13use core::{
14 fmt::{self, Display, LowerHex},
15 ops::ControlFlow,
16};
17
18use miden_mast_package::debug_info::DebugSourceNodeId;
19
20mod continuation_stack;
21mod errors;
22mod execution;
23mod execution_options;
24mod executor;
25mod fast;
26mod host;
27mod processor;
28mod tracer;
29
30use miden_core::{
31 deferred::{Digest, Node, PrecompileError},
32 mast::ExecutableMastForest,
33 serde::{Deserializable, Serializable},
34};
35
36use crate::{
37 advice::{AdviceInputs, AdviceProvider},
38 continuation_stack::ContinuationStack,
39 errors::MapExecErr,
40 processor::{Processor, SystemInterface},
41 trace::RowIndex,
42};
43
44#[cfg(any(test, feature = "testing"))]
45mod test_utils;
46#[cfg(any(test, feature = "testing"))]
47pub use test_utils::{ProcessorStateSnapshot, TestHost};
48
49#[cfg(test)]
50mod tests;
51
52pub use continuation_stack::{Continuation, SourceInlineCallContext};
56pub use errors::{
57 AceError, ExecutionError, HostError, MemoryError, PackageSourceDebugContext,
58 advice_error_with_package_source_context, event_error_with_package_source_context,
59 procedure_not_found_with_package_source_context,
60};
61pub use execution_options::{ExecutionOptions, ExecutionOptionsError};
62pub use executor::ProgramExecutor;
63pub use fast::{BreakReason, ExecutionOutput, FastProcessor, ResumeContext};
64pub use host::{
65 BaseHost, FutureMaybeSend, Host, LoadedMastForest, MastForestStore, MemMastForestStore,
66 SyncHost,
67 debug::{StdoutWriter, format_value, write_interval, write_stack},
68 default::{DefaultHost, HostLibrary},
69};
70pub use miden_core::{
71 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO, crypto, field, mast,
72 program::{
73 ExecutionClaim, InputError, KernelDescriptor, MIN_STACK_DEPTH, Program, ProgramInfo,
74 StackInputs, StackOutputs,
75 },
76 serde, utils,
77};
78pub use trace::{ExecutionWitness, PrecompileWitness, VmWitness};
79
80pub mod advice {
81 pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStack};
82
83 pub use super::host::{
84 AdviceMutation,
85 advice::{AdviceError, AdviceProvider},
86 };
87}
88
89pub mod event {
90 pub use miden_core::events::*;
91
92 pub use crate::host::handlers::{
93 EventError, EventHandler, EventHandlerRegistry, NoopEventHandler, TraceError, TraceHandler,
94 TraceHandlerRegistry,
95 };
96}
97
98pub mod operation {
99 pub use miden_core::operations::*;
100
101 pub use crate::errors::{BinaryValueErrorContext, OperationError};
102}
103
104pub mod trace;
105
106#[derive(Debug)]
114pub struct ProcessorState<'a> {
115 processor: &'a FastProcessor,
116}
117
118impl<'a> ProcessorState<'a> {
119 #[inline(always)]
121 pub fn advice_provider(&self) -> &AdviceProvider {
122 self.processor.advice_provider()
123 }
124
125 #[inline(always)]
127 pub fn execution_options(&self) -> &ExecutionOptions {
128 self.processor.execution_options()
129 }
130
131 #[inline(always)]
133 pub fn clock(&self) -> RowIndex {
134 self.processor.clock()
135 }
136
137 #[inline(always)]
139 pub fn ctx(&self) -> ContextId {
140 self.processor.ctx()
141 }
142
143 #[inline(always)]
147 pub fn get_stack_item(&self, pos: usize) -> Felt {
148 self.processor.stack_get_safe(pos)
149 }
150
151 #[inline(always)]
163 pub fn get_stack_word(&self, start_idx: usize) -> Word {
164 self.processor.stack_get_word_safe(start_idx)
165 }
166
167 #[inline(always)]
170 pub fn get_stack_state(&self) -> Vec<Felt> {
171 self.processor.stack().iter().rev().copied().collect()
172 }
173
174 #[inline(always)]
177 pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option<Felt> {
178 self.processor.memory().read_element_impl(ctx, addr)
179 }
180
181 #[inline(always)]
186 pub fn get_mem_word(&self, ctx: ContextId, addr: u32) -> Result<Option<Word>, MemoryError> {
187 self.processor.memory().read_word_impl(ctx, addr)
188 }
189
190 pub fn get_mem_addr_range(
195 &self,
196 start_idx: usize,
197 end_idx: usize,
198 ) -> Result<core::ops::Range<u32>, MemoryError> {
199 let start_addr = self.get_stack_item(start_idx).as_canonical_u64();
200 let end_addr = self.get_stack_item(end_idx).as_canonical_u64();
201
202 if start_addr > u32::MAX as u64 {
203 return Err(MemoryError::AddressOutOfBounds { addr: start_addr });
204 }
205 if end_addr > u32::MAX as u64 {
206 return Err(MemoryError::AddressOutOfBounds { addr: end_addr });
207 }
208
209 if start_addr > end_addr {
210 return Err(MemoryError::InvalidMemoryRange { start_addr, end_addr });
211 }
212
213 Ok(start_addr as u32..end_addr as u32)
214 }
215
216 #[inline(always)]
222 pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(MemoryAddress, Felt)> {
223 self.processor.memory().get_memory_state(ctx)
224 }
225
226 #[inline(always)]
231 pub fn get_canonical_deferred_digest(&self, digest: Digest) -> Option<Digest> {
232 self.processor.deferred_state().get_canonical_digest(digest)
233 }
234
235 #[inline(always)]
240 pub fn get_canonical_deferred_node(&self, digest: Digest) -> Option<(Digest, &Node)> {
241 self.processor.deferred_state().get_canonical_node(digest)
242 }
243
244 #[inline(always)]
251 pub fn require_canonical_deferred_node(
252 &self,
253 digest: Digest,
254 ) -> Result<(Digest, &Node), PrecompileError> {
255 self.processor.deferred_state().require_canonical_node(digest)
256 }
257}
258
259pub trait Stopper {
269 type Processor;
270
271 type Forest: ExecutableMastForest + Clone;
275
276 fn should_stop(
291 &self,
292 processor: &Self::Processor,
293 continuation_stack: &ContinuationStack<Self::Forest>,
294 continuation_after_stop: impl FnOnce() -> Option<(
295 Continuation<Self::Forest>,
296 Option<DebugSourceNodeId>,
297 )>,
298 ) -> ControlFlow<BreakReason<Self::Forest>>;
299}
300
301#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
306pub struct ContextId(u32);
307
308impl ContextId {
309 pub fn root() -> Self {
311 Self(0)
312 }
313
314 pub fn is_root(&self) -> bool {
316 self.0 == 0
317 }
318}
319
320impl From<RowIndex> for ContextId {
321 fn from(value: RowIndex) -> Self {
322 Self(value.as_u32())
323 }
324}
325
326impl From<u32> for ContextId {
327 fn from(value: u32) -> Self {
328 Self(value)
329 }
330}
331
332impl From<ContextId> for u32 {
333 fn from(context_id: ContextId) -> Self {
334 context_id.0
335 }
336}
337
338impl From<ContextId> for u64 {
339 fn from(context_id: ContextId) -> Self {
340 context_id.0.into()
341 }
342}
343
344impl From<ContextId> for Felt {
345 fn from(context_id: ContextId) -> Self {
346 Felt::from_u32(context_id.0)
347 }
348}
349
350impl Serializable for ContextId {
351 fn write_into<W: serde::ByteWriter>(&self, target: &mut W) {
352 Serializable::write_into(&self.0, target);
353 }
354}
355
356impl Deserializable for ContextId {
357 fn read_from<R: serde::ByteReader>(
358 source: &mut R,
359 ) -> Result<Self, serde::DeserializationError> {
360 Ok(Self(<u32 as Deserializable>::read_from(source)?))
361 }
362
363 fn min_serialized_size() -> usize {
364 <u32 as Deserializable>::min_serialized_size()
365 }
366}
367
368impl Display for ContextId {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 write!(f, "{}", self.0)
371 }
372}
373
374#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
378pub struct MemoryAddress(u32);
379
380impl From<u32> for MemoryAddress {
381 fn from(addr: u32) -> Self {
382 MemoryAddress(addr)
383 }
384}
385
386impl From<MemoryAddress> for u32 {
387 fn from(value: MemoryAddress) -> Self {
388 value.0
389 }
390}
391
392impl Display for MemoryAddress {
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 Display::fmt(&self.0, f)
395 }
396}
397
398impl LowerHex for MemoryAddress {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 LowerHex::fmt(&self.0, f)
401 }
402}
403
404impl core::ops::Add<MemoryAddress> for MemoryAddress {
405 type Output = Self;
406
407 fn add(self, rhs: MemoryAddress) -> Self::Output {
408 MemoryAddress(self.0 + rhs.0)
409 }
410}
411
412impl core::ops::Add<u32> for MemoryAddress {
413 type Output = Self;
414
415 fn add(self, rhs: u32) -> Self::Output {
416 MemoryAddress(self.0 + rhs)
417 }
418}
419
420#[track_caller]
432fn option_map_break_reason<F, T>(
433 opt: Option<T>,
434 err_msg: &'static str,
435) -> ControlFlow<BreakReason<F>, T> {
436 match opt {
437 Some(value) => ControlFlow::Continue(value),
438 None => ControlFlow::Break(BreakReason::Err(ExecutionError::Internal(err_msg))),
439 }
440}