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::{
64 BreakReason, DebugCallFrame, DebugCallFrameResolver, DebugFrameOrigin, ExecutionOutput,
65 FastProcessor, ResumeContext,
66};
67pub use host::{
68 BaseHost, FutureMaybeSend, Host, LoadedMastForest, MastForestStore, MemMastForestStore,
69 SyncHost,
70 debug::{StdoutWriter, format_value, write_interval, write_stack},
71 default::{DefaultHost, HostLibrary},
72};
73pub use miden_core::{
74 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO, crypto, field, mast,
75 program::{
76 ExecutionClaim, InputError, KernelDescriptor, MIN_STACK_DEPTH, Program, ProgramInfo,
77 StackInputs, StackOutputs,
78 },
79 serde, utils,
80};
81pub use trace::{ExecutionWitness, PrecompileWitness, VmWitness};
82
83pub mod advice {
84 pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStack};
85
86 pub use super::host::{
87 AdviceMutation,
88 advice::{AdviceError, AdviceProvider},
89 };
90}
91
92pub mod event {
93 pub use miden_core::events::*;
94
95 pub use crate::host::handlers::{
96 EventError, EventHandler, EventHandlerRegistry, NoopEventHandler, TraceError, TraceHandler,
97 TraceHandlerRegistry,
98 };
99}
100
101pub mod operation {
102 pub use miden_core::operations::*;
103
104 pub use crate::errors::{BinaryValueErrorContext, OperationError};
105}
106
107pub mod trace;
108
109#[derive(Debug)]
117pub struct ProcessorState<'a> {
118 processor: &'a FastProcessor,
119}
120
121impl<'a> ProcessorState<'a> {
122 #[inline(always)]
124 pub fn advice_provider(&self) -> &AdviceProvider {
125 self.processor.advice_provider()
126 }
127
128 #[inline(always)]
130 pub fn execution_options(&self) -> &ExecutionOptions {
131 self.processor.execution_options()
132 }
133
134 #[inline(always)]
136 pub fn clock(&self) -> RowIndex {
137 self.processor.clock()
138 }
139
140 #[inline(always)]
142 pub fn ctx(&self) -> ContextId {
143 self.processor.ctx()
144 }
145
146 #[inline(always)]
150 pub fn get_stack_item(&self, pos: usize) -> Felt {
151 self.processor.stack_get_safe(pos)
152 }
153
154 #[inline(always)]
166 pub fn get_stack_word(&self, start_idx: usize) -> Word {
167 self.processor.stack_get_word_safe(start_idx)
168 }
169
170 #[inline(always)]
173 pub fn get_stack_state(&self) -> Vec<Felt> {
174 self.processor.stack().iter().rev().copied().collect()
175 }
176
177 #[inline(always)]
180 pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option<Felt> {
181 self.processor.memory().read_element_impl(ctx, addr)
182 }
183
184 #[inline(always)]
189 pub fn get_mem_word(&self, ctx: ContextId, addr: u32) -> Result<Option<Word>, MemoryError> {
190 self.processor.memory().read_word_impl(ctx, addr)
191 }
192
193 pub fn get_mem_addr_range(
198 &self,
199 start_idx: usize,
200 end_idx: usize,
201 ) -> Result<core::ops::Range<u32>, MemoryError> {
202 let start_addr = self.get_stack_item(start_idx).as_canonical_u64();
203 let end_addr = self.get_stack_item(end_idx).as_canonical_u64();
204
205 if start_addr > u32::MAX as u64 {
206 return Err(MemoryError::AddressOutOfBounds { addr: start_addr });
207 }
208 if end_addr > u32::MAX as u64 {
209 return Err(MemoryError::AddressOutOfBounds { addr: end_addr });
210 }
211
212 if start_addr > end_addr {
213 return Err(MemoryError::InvalidMemoryRange { start_addr, end_addr });
214 }
215
216 Ok(start_addr as u32..end_addr as u32)
217 }
218
219 #[inline(always)]
225 pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(MemoryAddress, Felt)> {
226 self.processor.memory().get_memory_state(ctx)
227 }
228
229 #[inline(always)]
234 pub fn get_canonical_deferred_digest(&self, digest: Digest) -> Option<Digest> {
235 self.processor.deferred_state().get_canonical_digest(digest)
236 }
237
238 #[inline(always)]
243 pub fn get_canonical_deferred_node(&self, digest: Digest) -> Option<(Digest, &Node)> {
244 self.processor.deferred_state().get_canonical_node(digest)
245 }
246
247 #[inline(always)]
254 pub fn require_canonical_deferred_node(
255 &self,
256 digest: Digest,
257 ) -> Result<(Digest, &Node), PrecompileError> {
258 self.processor.deferred_state().require_canonical_node(digest)
259 }
260}
261
262pub trait Stopper {
272 type Processor;
273
274 type Forest: ExecutableMastForest + Clone;
278
279 fn should_stop(
294 &self,
295 processor: &Self::Processor,
296 continuation_stack: &ContinuationStack<Self::Forest>,
297 continuation_after_stop: impl FnOnce() -> Option<(
298 Continuation<Self::Forest>,
299 Option<DebugSourceNodeId>,
300 )>,
301 ) -> ControlFlow<BreakReason<Self::Forest>>;
302}
303
304#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
309#[cfg_attr(
310 all(feature = "arbitrary", test),
311 miden_test_serialization_macros::serialization_test
312)]
313pub struct ContextId(u32);
314
315impl ContextId {
316 pub fn root() -> Self {
318 Self(0)
319 }
320
321 pub fn is_root(&self) -> bool {
323 self.0 == 0
324 }
325}
326
327impl From<RowIndex> for ContextId {
328 fn from(value: RowIndex) -> Self {
329 Self(value.as_u32())
330 }
331}
332
333impl From<u32> for ContextId {
334 fn from(value: u32) -> Self {
335 Self(value)
336 }
337}
338
339impl From<ContextId> for u32 {
340 fn from(context_id: ContextId) -> Self {
341 context_id.0
342 }
343}
344
345impl From<ContextId> for u64 {
346 fn from(context_id: ContextId) -> Self {
347 context_id.0.into()
348 }
349}
350
351impl From<ContextId> for Felt {
352 fn from(context_id: ContextId) -> Self {
353 Felt::from_u32(context_id.0)
354 }
355}
356
357#[cfg(any(test, feature = "arbitrary"))]
358mod context_id_arbitrary {
359 use proptest::prelude::*;
360
361 use super::ContextId;
362
363 impl Arbitrary for ContextId {
364 type Parameters = ();
365 type Strategy = BoxedStrategy<Self>;
366
367 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
368 prop_oneof![Just(0u32), Just(u32::MAX), any::<u32>()].prop_map(Self).boxed()
370 }
371 }
372}
373
374impl Serializable for ContextId {
375 fn write_into<W: serde::ByteWriter>(&self, target: &mut W) {
376 Serializable::write_into(&self.0, target);
377 }
378}
379
380impl Deserializable for ContextId {
381 fn read_from<R: serde::ByteReader>(
382 source: &mut R,
383 ) -> Result<Self, serde::DeserializationError> {
384 Ok(Self(<u32 as Deserializable>::read_from(source)?))
385 }
386
387 fn min_serialized_size() -> usize {
388 <u32 as Deserializable>::min_serialized_size()
389 }
390}
391
392impl Display for ContextId {
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 write!(f, "{}", self.0)
395 }
396}
397
398#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
402pub struct MemoryAddress(u32);
403
404impl From<u32> for MemoryAddress {
405 fn from(addr: u32) -> Self {
406 MemoryAddress(addr)
407 }
408}
409
410impl From<MemoryAddress> for u32 {
411 fn from(value: MemoryAddress) -> Self {
412 value.0
413 }
414}
415
416impl Display for MemoryAddress {
417 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418 Display::fmt(&self.0, f)
419 }
420}
421
422impl LowerHex for MemoryAddress {
423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424 LowerHex::fmt(&self.0, f)
425 }
426}
427
428impl core::ops::Add<MemoryAddress> for MemoryAddress {
429 type Output = Self;
430
431 fn add(self, rhs: MemoryAddress) -> Self::Output {
432 MemoryAddress(self.0 + rhs.0)
433 }
434}
435
436impl core::ops::Add<u32> for MemoryAddress {
437 type Output = Self;
438
439 fn add(self, rhs: u32) -> Self::Output {
440 MemoryAddress(self.0 + rhs)
441 }
442}
443
444#[track_caller]
456fn option_map_break_reason<F, T>(
457 opt: Option<T>,
458 err_msg: &'static str,
459) -> ControlFlow<BreakReason<F>, T> {
460 match opt {
461 Some(value) => ControlFlow::Continue(value),
462 None => ControlFlow::Break(BreakReason::Err(ExecutionError::Internal(err_msg))),
463 }
464}