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
18mod continuation_stack;
19mod errors;
20mod execution;
21mod execution_options;
22mod fast;
23mod host;
24mod processor;
25mod tracer;
26
27use crate::{
28 advice::{AdviceInputs, AdviceProvider},
29 continuation_stack::ContinuationStack,
30 errors::{MapExecErr, MapExecErrNoCtx},
31 processor::{Processor, SystemInterface},
32 trace::RowIndex,
33};
34
35#[cfg(any(test, feature = "testing"))]
36mod test_utils;
37#[cfg(any(test, feature = "testing"))]
38pub use test_utils::{ProcessorStateSnapshot, TestHost, TraceCollector};
39
40#[cfg(test)]
41mod tests;
42
43pub use continuation_stack::Continuation;
47pub use errors::{AceError, ExecutionError, HostError, MemoryError};
48pub use execution_options::{ExecutionOptions, ExecutionOptionsError};
49pub use fast::{BreakReason, ExecutionOutput, FastProcessor, ResumeContext};
50pub use host::{
51 BaseHost, FutureMaybeSend, Host, MastForestStore, MemMastForestStore, SyncHost,
52 debug::DefaultDebugHandler,
53 default::{DefaultHost, HostLibrary},
54 handlers::{DebugError, DebugHandler, TraceError},
55};
56pub use miden_core::{
57 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO, crypto, field, mast, precompile,
58 program::{
59 InputError, Kernel, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs,
60 },
61 serde, utils,
62};
63pub use trace::{TraceBuildInputs, TraceGenerationContext};
64
65pub mod advice {
66 pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStackBuilder};
67
68 pub use super::host::{
69 AdviceMutation,
70 advice::{AdviceError, AdviceProvider},
71 };
72}
73
74pub mod event {
75 pub use miden_core::events::*;
76
77 pub use crate::host::handlers::{
78 EventError, EventHandler, EventHandlerRegistry, NoopEventHandler,
79 };
80}
81
82pub mod operation {
83 pub use miden_core::operations::*;
84
85 pub use crate::errors::OperationError;
86}
87
88pub mod trace;
89
90#[tracing::instrument("execute_program", skip_all)]
102pub async fn execute(
103 program: &Program,
104 stack_inputs: StackInputs,
105 advice_inputs: AdviceInputs,
106 host: &mut impl Host,
107 options: ExecutionOptions,
108) -> Result<ExecutionOutput, ExecutionError> {
109 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options)
110 .map_exec_err_no_ctx()?;
111 processor.execute(program, host).await
112}
113
114#[cfg(not(target_family = "wasm"))]
123#[tracing::instrument("execute_program_sync", skip_all)]
124pub fn execute_sync(
125 program: &Program,
126 stack_inputs: StackInputs,
127 advice_inputs: AdviceInputs,
128 host: &mut impl SyncHost,
129 options: ExecutionOptions,
130) -> Result<ExecutionOutput, ExecutionError> {
131 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options)
132 .map_exec_err_no_ctx()?;
133 processor.execute_sync(program, host)
134}
135
136#[derive(Debug)]
144pub struct ProcessorState<'a> {
145 processor: &'a FastProcessor,
146}
147
148impl<'a> ProcessorState<'a> {
149 #[inline(always)]
151 pub fn advice_provider(&self) -> &AdviceProvider {
152 self.processor.advice_provider()
153 }
154
155 #[inline(always)]
157 pub fn execution_options(&self) -> &ExecutionOptions {
158 self.processor.execution_options()
159 }
160
161 #[inline(always)]
163 pub fn clock(&self) -> RowIndex {
164 self.processor.clock()
165 }
166
167 #[inline(always)]
169 pub fn ctx(&self) -> ContextId {
170 self.processor.ctx()
171 }
172
173 #[inline(always)]
177 pub fn get_stack_item(&self, pos: usize) -> Felt {
178 self.processor.stack_get_safe(pos)
179 }
180
181 #[inline(always)]
193 pub fn get_stack_word(&self, start_idx: usize) -> Word {
194 self.processor.stack_get_word_safe(start_idx)
195 }
196
197 #[inline(always)]
200 pub fn get_stack_state(&self) -> Vec<Felt> {
201 self.processor.stack().iter().rev().copied().collect()
202 }
203
204 #[inline(always)]
207 pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option<Felt> {
208 self.processor.memory().read_element_impl(ctx, addr)
209 }
210
211 #[inline(always)]
216 pub fn get_mem_word(&self, ctx: ContextId, addr: u32) -> Result<Option<Word>, MemoryError> {
217 self.processor.memory().read_word_impl(ctx, addr)
218 }
219
220 pub fn get_mem_addr_range(
223 &self,
224 start_idx: usize,
225 end_idx: usize,
226 ) -> Result<core::ops::Range<u32>, MemoryError> {
227 let start_addr = self.get_stack_item(start_idx).as_canonical_u64();
228 let end_addr = self.get_stack_item(end_idx).as_canonical_u64();
229
230 if start_addr > u32::MAX as u64 {
231 return Err(MemoryError::AddressOutOfBounds { addr: start_addr });
232 }
233 if end_addr > u32::MAX as u64 {
234 return Err(MemoryError::AddressOutOfBounds { addr: end_addr });
235 }
236
237 if start_addr > end_addr {
238 return Err(MemoryError::InvalidMemoryRange { start_addr, end_addr });
239 }
240
241 Ok(start_addr as u32..end_addr as u32)
242 }
243
244 #[inline(always)]
250 pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(MemoryAddress, Felt)> {
251 self.processor.memory().get_memory_state(ctx)
252 }
253}
254
255pub trait Stopper {
265 type Processor;
266
267 fn should_stop(
282 &self,
283 processor: &Self::Processor,
284 continuation_stack: &ContinuationStack,
285 continuation_after_stop: impl FnOnce() -> Option<Continuation>,
286 ) -> ControlFlow<BreakReason>;
287}
288
289#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
294pub struct ContextId(u32);
295
296impl ContextId {
297 pub fn root() -> Self {
299 Self(0)
300 }
301
302 pub fn is_root(&self) -> bool {
304 self.0 == 0
305 }
306}
307
308impl From<RowIndex> for ContextId {
309 fn from(value: RowIndex) -> Self {
310 Self(value.as_u32())
311 }
312}
313
314impl From<u32> for ContextId {
315 fn from(value: u32) -> Self {
316 Self(value)
317 }
318}
319
320impl From<ContextId> for u32 {
321 fn from(context_id: ContextId) -> Self {
322 context_id.0
323 }
324}
325
326impl From<ContextId> for u64 {
327 fn from(context_id: ContextId) -> Self {
328 context_id.0.into()
329 }
330}
331
332impl From<ContextId> for Felt {
333 fn from(context_id: ContextId) -> Self {
334 Felt::from_u32(context_id.0)
335 }
336}
337
338impl Display for ContextId {
339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340 write!(f, "{}", self.0)
341 }
342}
343
344#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
348pub struct MemoryAddress(u32);
349
350impl From<u32> for MemoryAddress {
351 fn from(addr: u32) -> Self {
352 MemoryAddress(addr)
353 }
354}
355
356impl From<MemoryAddress> for u32 {
357 fn from(value: MemoryAddress) -> Self {
358 value.0
359 }
360}
361
362impl Display for MemoryAddress {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 Display::fmt(&self.0, f)
365 }
366}
367
368impl LowerHex for MemoryAddress {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 LowerHex::fmt(&self.0, f)
371 }
372}
373
374impl core::ops::Add<MemoryAddress> for MemoryAddress {
375 type Output = Self;
376
377 fn add(self, rhs: MemoryAddress) -> Self::Output {
378 MemoryAddress(self.0 + rhs.0)
379 }
380}
381
382impl core::ops::Add<u32> for MemoryAddress {
383 type Output = Self;
384
385 fn add(self, rhs: u32) -> Self::Output {
386 MemoryAddress(self.0 + rhs)
387 }
388}