1#![no_std]
2
3#[macro_use]
4extern crate alloc;
5
6#[cfg(feature = "std")]
7extern crate std;
8
9use alloc::vec::Vec;
10use core::{
11 fmt::{self, Display, LowerHex},
12 ops::ControlFlow,
13};
14
15mod continuation_stack;
16mod debug;
17mod errors;
18mod execution;
19mod execution_options;
20mod fast;
21mod host;
22mod processor;
23mod tracer;
24
25use crate::{
26 advice::{AdviceInputs, AdviceProvider},
27 errors::MapExecErr,
28 field::{PrimeCharacteristicRing, PrimeField64},
29 processor::{Processor, SystemInterface},
30 trace::{ExecutionTrace, RowIndex},
31};
32
33#[cfg(any(test, feature = "testing"))]
34mod test_utils;
35#[cfg(any(test, feature = "testing"))]
36pub use test_utils::{ProcessorStateSnapshot, TestHost, TraceCollector};
37
38#[cfg(test)]
39mod tests;
40
41pub use errors::{ExecutionError, MemoryError};
45pub use execution_options::{ExecutionOptions, ExecutionOptionsError};
46pub use fast::{BreakReason, ExecutionOutput, FastProcessor, ResumeContext};
47pub use host::{
48 FutureMaybeSend, Host, MastForestStore, MemMastForestStore,
49 debug::DefaultDebugHandler,
50 default::{DefaultHost, HostLibrary},
51 handlers::{DebugError, DebugHandler, TraceError},
52};
53pub use miden_core::{
54 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO, crypto, field, mast, precompile,
55 program::{
56 InputError, Kernel, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs,
57 },
58 serde, utils,
59};
60
61pub mod advice {
62 pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStackBuilder};
63
64 pub use super::host::{
65 AdviceMutation,
66 advice::{AdviceError, AdviceProvider},
67 };
68}
69
70pub mod event {
71 pub use miden_core::events::*;
72
73 pub use crate::host::handlers::{
74 EventError, EventHandler, EventHandlerRegistry, NoopEventHandler,
75 };
76}
77
78pub mod operation {
79 pub use miden_core::operations::*;
80
81 pub use crate::errors::OperationError;
82}
83
84pub mod trace;
85
86#[tracing::instrument("execute_program", skip_all)]
100pub async fn execute(
101 program: &Program,
102 stack_inputs: StackInputs,
103 advice_inputs: AdviceInputs,
104 host: &mut impl Host,
105 options: ExecutionOptions,
106) -> Result<ExecutionTrace, ExecutionError> {
107 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options);
108 let (execution_output, trace_generation_context) =
109 processor.execute_for_trace(program, host).await?;
110
111 let trace = trace::build_trace(execution_output, trace_generation_context, program.to_info());
112
113 assert_eq!(&program.hash(), trace.program_hash(), "inconsistent program hash");
114 Ok(trace)
115}
116
117#[cfg(not(target_arch = "wasm32"))]
126#[tracing::instrument("execute_program_sync", skip_all)]
127pub fn execute_sync(
128 program: &Program,
129 stack_inputs: StackInputs,
130 advice_inputs: AdviceInputs,
131 host: &mut impl Host,
132 options: ExecutionOptions,
133) -> Result<ExecutionTrace, ExecutionError> {
134 match tokio::runtime::Handle::try_current() {
135 Ok(_handle) => {
136 panic!(
139 "Cannot call execute_sync from within a Tokio runtime. \
140 Use the async execute() method instead."
141 )
142 },
143 Err(_) => {
144 let rt = tokio::runtime::Builder::new_current_thread().build().unwrap();
146 rt.block_on(execute(program, stack_inputs, advice_inputs, host, options))
147 },
148 }
149}
150
151#[derive(Debug)]
159pub struct ProcessorState<'a> {
160 processor: &'a mut FastProcessor,
161}
162
163impl<'a> ProcessorState<'a> {
164 #[inline(always)]
166 pub fn advice_provider(&self) -> &AdviceProvider {
167 self.processor.advice_provider()
168 }
169
170 #[inline(always)]
172 pub fn advice_provider_mut(&mut self) -> &mut AdviceProvider {
173 self.processor.advice_provider_mut()
174 }
175
176 #[inline(always)]
178 pub fn clock(&self) -> RowIndex {
179 self.processor.clock()
180 }
181
182 #[inline(always)]
184 pub fn ctx(&self) -> ContextId {
185 self.processor.ctx()
186 }
187
188 #[inline(always)]
192 pub fn get_stack_item(&self, pos: usize) -> Felt {
193 self.processor.stack_get(pos)
194 }
195
196 #[inline(always)]
208 pub fn get_stack_word(&self, start_idx: usize) -> Word {
209 self.processor.stack_get_word(start_idx)
210 }
211
212 #[inline(always)]
215 pub fn get_stack_state(&self) -> Vec<Felt> {
216 self.processor.stack().iter().rev().copied().collect()
217 }
218
219 #[inline(always)]
222 pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option<Felt> {
223 self.processor.memory().read_element_impl(ctx, addr)
224 }
225
226 #[inline(always)]
231 pub fn get_mem_word(&self, ctx: ContextId, addr: u32) -> Result<Option<Word>, MemoryError> {
232 self.processor.memory().read_word_impl(ctx, addr)
233 }
234
235 pub fn get_mem_addr_range(
238 &self,
239 start_idx: usize,
240 end_idx: usize,
241 ) -> Result<core::ops::Range<u32>, MemoryError> {
242 let start_addr = self.get_stack_item(start_idx).as_canonical_u64();
243 let end_addr = self.get_stack_item(end_idx).as_canonical_u64();
244
245 if start_addr > u32::MAX as u64 {
246 return Err(MemoryError::AddressOutOfBounds { addr: start_addr });
247 }
248 if end_addr > u32::MAX as u64 {
249 return Err(MemoryError::AddressOutOfBounds { addr: end_addr });
250 }
251
252 if start_addr > end_addr {
253 return Err(MemoryError::InvalidMemoryRange { start_addr, end_addr });
254 }
255
256 Ok(start_addr as u32..end_addr as u32)
257 }
258
259 #[inline(always)]
265 pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(MemoryAddress, Felt)> {
266 self.processor.memory().get_memory_state(ctx)
267 }
268}
269
270pub trait Stopper {
275 type Processor;
276
277 fn should_stop(
287 &self,
288 processor: &Self::Processor,
289 continuation_after_stop: impl FnOnce() -> Option<continuation_stack::Continuation>,
290 ) -> ControlFlow<BreakReason>;
291}
292
293#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
298pub struct ContextId(u32);
299
300impl ContextId {
301 pub fn root() -> Self {
303 Self(0)
304 }
305
306 pub fn is_root(&self) -> bool {
308 self.0 == 0
309 }
310}
311
312impl From<RowIndex> for ContextId {
313 fn from(value: RowIndex) -> Self {
314 Self(value.as_u32())
315 }
316}
317
318impl From<u32> for ContextId {
319 fn from(value: u32) -> Self {
320 Self(value)
321 }
322}
323
324impl From<ContextId> for u32 {
325 fn from(context_id: ContextId) -> Self {
326 context_id.0
327 }
328}
329
330impl From<ContextId> for u64 {
331 fn from(context_id: ContextId) -> Self {
332 context_id.0.into()
333 }
334}
335
336impl From<ContextId> for Felt {
337 fn from(context_id: ContextId) -> Self {
338 Felt::from_u32(context_id.0)
339 }
340}
341
342impl Display for ContextId {
343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344 write!(f, "{}", self.0)
345 }
346}
347
348#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
352pub struct MemoryAddress(u32);
353
354impl From<u32> for MemoryAddress {
355 fn from(addr: u32) -> Self {
356 MemoryAddress(addr)
357 }
358}
359
360impl From<MemoryAddress> for u32 {
361 fn from(value: MemoryAddress) -> Self {
362 value.0
363 }
364}
365
366impl Display for MemoryAddress {
367 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
368 Display::fmt(&self.0, f)
369 }
370}
371
372impl LowerHex for MemoryAddress {
373 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
374 LowerHex::fmt(&self.0, f)
375 }
376}
377
378impl core::ops::Add<MemoryAddress> for MemoryAddress {
379 type Output = Self;
380
381 fn add(self, rhs: MemoryAddress) -> Self::Output {
382 MemoryAddress(self.0 + rhs.0)
383 }
384}
385
386impl core::ops::Add<u32> for MemoryAddress {
387 type Output = Self;
388
389 fn add(self, rhs: u32) -> Self::Output {
390 MemoryAddress(self.0 + rhs)
391 }
392}