1#![no_std]
2
3extern crate alloc;
4
5#[cfg(feature = "std")]
6extern crate std;
7
8use alloc::{
9 format,
10 string::{String, ToString},
11 sync::Arc,
12 vec,
13 vec::Vec,
14};
15
16use miden_assembly::{KernelLibrary, Library, Parse, diagnostics::reporting::PrintDiagnostic};
17pub use miden_assembly::{
18 Path,
19 debuginfo::{DefaultSourceManager, SourceFile, SourceLanguage, SourceManager},
20 diagnostics::Report,
21};
22pub use miden_core::{
23 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO,
24 chiplets::hasher::{STATE_WIDTH, hash_elements},
25 field::{Field, PrimeCharacteristicRing, PrimeField64, QuadFelt},
26 program::{MIN_STACK_DEPTH, StackInputs, StackOutputs},
27 utils::{IntoBytes, ToElements, group_slice_elements},
28};
29use miden_core::{
30 chiplets::hasher::apply_permutation,
31 events::{EventName, SystemEvent},
32 program::ProgramInfo,
33};
34pub use miden_processor::{
35 ContextId, ExecutionError, ProcessorState,
36 advice::{AdviceInputs, AdviceProvider, AdviceStackBuilder},
37 trace::ExecutionTrace,
38};
39use miden_processor::{
40 DefaultDebugHandler, DefaultHost, ExecutionOutput, FastProcessor, Program, TraceBuildInputs,
41 event::EventHandler, trace::build_trace,
42};
43#[cfg(not(target_arch = "wasm32"))]
44pub use miden_prover::prove_sync;
45pub use miden_prover::{ProvingOptions, prove};
46pub use miden_verifier::verify;
47pub use pretty_assertions::{assert_eq, assert_ne, assert_str_eq};
48#[cfg(not(target_family = "wasm"))]
49use proptest::prelude::{Arbitrary, Strategy};
50pub use test_case::test_case;
51
52pub mod math {
53 pub use miden_core::{
54 field::{ExtensionField, Field, PrimeField64, QuadFelt},
55 utils::ToElements,
56 };
57}
58
59pub use miden_core::serde;
60
61pub mod crypto;
62
63#[cfg(not(target_family = "wasm"))]
64pub mod rand;
65
66mod test_builders;
67
68#[cfg(not(target_family = "wasm"))]
69pub use proptest;
70pub const U32_BOUND: u64 = u32::MAX as u64 + 1;
75
76pub const TRUNCATE_STACK_PROC: &str = "
78@locals(4)
79proc truncate_stack
80 loc_storew_be.0 dropw movupw.3
81 sdepth neq.16
82 while.true
83 dropw movupw.3
84 sdepth neq.16
85 end
86 loc_loadw_be.0
87end
88";
89
90#[cfg(all(feature = "std", not(target_family = "wasm")))]
95#[macro_export]
96macro_rules! expect_assembly_error {
97 ($test:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
98 let error = $test.compile().expect_err("expected assembly to fail");
99 match error.downcast::<::miden_assembly::AssemblyError>() {
100 Ok(error) => {
101 ::miden_core::assert_matches!(error, $( $pattern )|+ $( if $guard )?);
102 }
103 Err(report) => {
104 panic!(r#"
105assertion failed (expected assembly error, but got a different type):
106 left: `{:?}`,
107 right: `{}`"#, report, stringify!($($pattern)|+ $(if $guard)?));
108 }
109 }
110 };
111}
112
113#[cfg(all(feature = "std", not(target_family = "wasm")))]
115#[macro_export]
116macro_rules! expect_exec_error_matches {
117 ($test:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
118 match $test.execute() {
119 Ok(_) => panic!("expected execution to fail @ {}:{}", file!(), line!()),
120 Err(error) => ::miden_core::assert_matches!(error, $( $pattern )|+ $( if $guard )?),
121 }
122 };
123}
124
125#[cfg(not(target_family = "wasm"))]
132#[macro_export]
133macro_rules! assert_diagnostic_lines {
134 ($diagnostic:expr, $($expected:expr),+) => {{
135 use miden_assembly::testing::Pattern;
136 let actual = format!("{}", miden_assembly::diagnostics::reporting::PrintDiagnostic::new_without_color($diagnostic));
137 let lines = actual.lines().filter(|l| !l.trim().is_empty()).zip([$(Pattern::from($expected)),*].into_iter());
138 for (actual_line, expected) in lines {
139 expected.assert_match_with_context(actual_line, &actual);
140 }
141 }};
142}
143
144#[cfg(not(target_family = "wasm"))]
145#[macro_export]
146macro_rules! assert_assembler_diagnostic {
147 ($test:ident, $($expected:literal),+) => {{
148 let error = $test
149 .compile()
150 .expect_err("expected diagnostic to be raised, but compilation succeeded");
151 assert_diagnostic_lines!(error, $($expected),*);
152 }};
153
154 ($test:ident, $($expected:expr),+) => {{
155 let error = $test
156 .compile()
157 .expect_err("expected diagnostic to be raised, but compilation succeeded");
158 assert_diagnostic_lines!(error, $($expected),*);
159 }};
160}
161
162pub struct Test {
176 pub source_manager: Arc<DefaultSourceManager>,
177 pub source: Arc<SourceFile>,
178 pub kernel_source: Option<Arc<SourceFile>>,
179 pub stack_inputs: StackInputs,
180 pub advice_inputs: AdviceInputs,
181 pub in_debug_mode: bool,
182 pub libraries: Vec<Library>,
183 pub handlers: Vec<(EventName, Arc<dyn EventHandler>)>,
184 pub add_modules: Vec<(Arc<Path>, String)>,
185}
186
187#[derive(Default)]
192pub struct BufferWriter {
193 pub buffer: String,
194}
195
196impl core::fmt::Write for BufferWriter {
197 fn write_str(&mut self, s: &str) -> core::fmt::Result {
198 self.buffer.push_str(s);
199 Ok(())
200 }
201}
202
203impl Test {
204 pub fn new(name: &str, source: &str, in_debug_mode: bool) -> Self {
209 let source_manager = Arc::new(DefaultSourceManager::default());
210 let source = source_manager.load(SourceLanguage::Masm, name.into(), source.to_string());
211 Self {
212 source_manager,
213 source,
214 kernel_source: None,
215 stack_inputs: StackInputs::default(),
216 advice_inputs: AdviceInputs::default(),
217 in_debug_mode,
218 libraries: Vec::default(),
219 handlers: Vec::new(),
220 add_modules: Vec::default(),
221 }
222 }
223
224 #[track_caller]
226 pub fn with_kernel(self, kernel_source: impl ToString) -> Self {
227 self.with_kernel_source(
228 format!("kernel{}", core::panic::Location::caller().line()),
229 kernel_source,
230 )
231 }
232
233 pub fn with_kernel_source(
235 mut self,
236 kernel_name: impl Into<String>,
237 kernel_source: impl ToString,
238 ) -> Self {
239 self.kernel_source = Some(self.source_manager.load(
240 SourceLanguage::Masm,
241 kernel_name.into().into(),
242 kernel_source.to_string(),
243 ));
244 self
245 }
246
247 pub fn add_module(&mut self, path: impl AsRef<Path>, source: impl ToString) {
249 self.add_modules.push((path.as_ref().into(), source.to_string()));
250 }
251
252 pub fn add_event_handler(&mut self, event: EventName, handler: impl EventHandler) {
254 self.add_event_handlers(vec![(event, Arc::new(handler))]);
255 }
256
257 pub fn add_event_handlers(&mut self, handlers: Vec<(EventName, Arc<dyn EventHandler>)>) {
259 for (event, handler) in handlers {
260 let event_name = event.as_str();
261 if SystemEvent::from_name(event_name).is_some() {
262 panic!("tried to register handler for reserved system event: {event_name}")
263 }
264 let event_id = event.to_event_id();
265 if self.handlers.iter().any(|(e, _)| e.to_event_id() == event_id) {
266 panic!("handler for event '{event_name}' was already added")
267 }
268 self.handlers.push((event, handler));
269 }
270 }
271
272 #[cfg(not(target_arch = "wasm32"))]
278 #[track_caller]
279 pub fn expect_stack(&self, final_stack: &[u64]) {
280 let result = self.get_last_stack_state().as_int_vec();
281 let expected = resize_to_min_stack_depth(final_stack);
282 assert_eq!(expected, result, "Expected stack to be {:?}, found {:?}", expected, result);
283 }
284
285 #[cfg(not(target_arch = "wasm32"))]
289 #[track_caller]
290 pub fn expect_stack_and_memory(
291 &self,
292 final_stack: &[u64],
293 mem_start_addr: u32,
294 expected_mem: &[u64],
295 ) {
296 let (program, host) = self.get_program_and_host();
298 let mut host = host.with_source_manager(self.source_manager.clone());
299
300 let processor = FastProcessor::new(self.stack_inputs)
302 .with_advice(self.advice_inputs.clone())
303 .with_debugging(self.in_debug_mode)
304 .with_tracing(self.in_debug_mode);
305 let execution_output = processor.execute_sync(&program, &mut host).unwrap();
306
307 for (addr, mem_value) in ((mem_start_addr as usize)
309 ..(mem_start_addr as usize + expected_mem.len()))
310 .zip(expected_mem.iter())
311 {
312 let mem_state = execution_output
313 .memory
314 .read_element(ContextId::root(), Felt::from_u32(addr as u32))
315 .unwrap();
316 assert_eq!(
317 *mem_value,
318 mem_state.as_canonical_u64(),
319 "Expected memory [{}] => {:?}, found {:?}",
320 addr,
321 mem_value,
322 mem_state
323 );
324 }
325
326 self.expect_stack(final_stack);
328 }
329
330 #[cfg(not(target_family = "wasm"))]
334 pub fn prop_expect_stack(
335 &self,
336 final_stack: &[u64],
337 ) -> Result<(), proptest::prelude::TestCaseError> {
338 let result = self.get_last_stack_state().as_int_vec();
339 proptest::prop_assert_eq!(resize_to_min_stack_depth(final_stack), result);
340
341 Ok(())
342 }
343
344 pub fn compile(&self) -> Result<(Program, Option<KernelLibrary>), Report> {
353 use miden_assembly::{Assembler, ParseOptions, ast::ModuleKind};
354
355 #[cfg(not(target_family = "wasm"))]
357 {
358 let _ = env_logger::Builder::from_env("MIDEN_LOG").format_timestamp(None).try_init();
359 }
360
361 let (assembler, kernel_lib) = if let Some(kernel) = self.kernel_source.clone() {
362 let kernel_lib =
363 Assembler::new(self.source_manager.clone()).assemble_kernel(kernel).unwrap();
364
365 (
366 Assembler::with_kernel(self.source_manager.clone(), kernel_lib.clone()),
367 Some(kernel_lib),
368 )
369 } else {
370 (Assembler::new(self.source_manager.clone()), None)
371 };
372
373 let mut assembler =
374 self.add_modules.iter().fold(assembler, |mut assembler, (path, source)| {
375 let module = source
376 .parse_with_options(
377 self.source_manager.clone(),
378 ParseOptions::new(ModuleKind::Library, path.clone()),
379 )
380 .expect("invalid masm source code");
381 assembler.compile_and_statically_link(module).expect("failed to link module");
382 assembler
383 });
384 for library in &self.libraries {
386 assembler.link_dynamic_library(library).unwrap();
387 }
388
389 Ok((assembler.assemble_program(self.source.clone())?, kernel_lib))
390 }
391
392 #[cfg(not(target_arch = "wasm32"))]
398 #[track_caller]
399 pub fn execute(&self) -> Result<ExecutionTrace, ExecutionError> {
400 const FRAGMENT_SIZE: usize = 1 << 16;
404
405 let (program, host) = self.get_program_and_host();
406 let mut host = host.with_source_manager(self.source_manager.clone());
407
408 let fast_stack_result = {
409 let fast_processor = FastProcessor::new_with_options(
410 self.stack_inputs,
411 self.advice_inputs.clone(),
412 miden_processor::ExecutionOptions::default()
413 .with_debugging(self.in_debug_mode)
414 .with_core_trace_fragment_size(FRAGMENT_SIZE)
415 .unwrap(),
416 );
417 fast_processor.execute_trace_inputs_sync(&program, &mut host)
418 };
419
420 self.assert_result_with_step_execution(&fast_stack_result);
422
423 fast_stack_result.and_then(|trace_inputs| {
424 let trace = build_trace(trace_inputs)?;
425
426 assert_eq!(&program.hash(), trace.program_hash(), "inconsistent program hash");
427 Ok(trace)
428 })
429 }
430
431 #[cfg(not(target_arch = "wasm32"))]
435 pub fn execute_for_output(&self) -> Result<(ExecutionOutput, DefaultHost), ExecutionError> {
436 let (program, host) = self.get_program_and_host();
437 let mut host = host.with_source_manager(self.source_manager.clone());
438
439 let processor = FastProcessor::new(self.stack_inputs)
440 .with_advice(self.advice_inputs.clone())
441 .with_debugging(true)
442 .with_tracing(true);
443
444 processor.execute_sync(&program, &mut host).map(|output| (output, host))
445 }
446
447 #[cfg(not(target_arch = "wasm32"))]
452 pub fn execute_with_debug_buffer(&self) -> Result<(StackOutputs, String), ExecutionError> {
453 let debug_handler = DefaultDebugHandler::new(BufferWriter::default());
454
455 let (program, host) = self.get_program_and_host();
456 let mut host = host
457 .with_source_manager(self.source_manager.clone())
458 .with_debug_handler(debug_handler);
459
460 let processor = FastProcessor::new(self.stack_inputs)
461 .with_advice(self.advice_inputs.clone())
462 .with_debugging(true)
463 .with_tracing(true);
464
465 let stack_result = processor.execute_sync(&program, &mut host);
466
467 let debug_output = host.debug_handler().writer().buffer.clone();
468
469 match stack_result {
470 Ok(exec_output) => Ok((exec_output.stack, debug_output)),
471 Err(err) => {
472 #[cfg(feature = "std")]
474 std::eprintln!("{}", debug_output);
475 Err(err)
476 },
477 }
478 }
479
480 #[cfg(not(target_arch = "wasm32"))]
488 pub fn prove_and_verify(&self, pub_inputs: Vec<u64>, test_fail: bool) {
489 let (program, mut host) = self.get_program_and_host();
490 let stack_inputs = StackInputs::try_from_ints(pub_inputs).unwrap();
491 let (mut stack_outputs, proof) = miden_prover::prove_sync(
492 &program,
493 stack_inputs,
494 self.advice_inputs.clone(),
495 &mut host,
496 miden_processor::ExecutionOptions::default(),
497 ProvingOptions::default(),
498 )
499 .unwrap();
500
501 let program_info = ProgramInfo::from(program);
502 if test_fail {
503 stack_outputs.as_mut()[0] += ONE;
504 assert!(
505 miden_verifier::verify(program_info, stack_inputs, stack_outputs, proof).is_err()
506 );
507 } else {
508 let result = miden_verifier::verify(program_info, stack_inputs, stack_outputs, proof);
509 assert!(result.is_ok(), "error: {result:?}");
510 }
511 }
512
513 #[cfg(not(target_arch = "wasm32"))]
525 #[track_caller]
526 pub fn check_constraints(&self) {
527 let trace = self
528 .execute()
529 .inspect_err(|_err| {
530 #[cfg(feature = "std")]
531 std::eprintln!("{}", PrintDiagnostic::new_without_color(_err))
532 })
533 .expect("failed to execute");
534 trace.check_constraints();
535 }
536
537 #[cfg(not(target_arch = "wasm32"))]
539 #[track_caller]
540 pub fn get_last_stack_state(&self) -> StackOutputs {
541 let trace = self
542 .execute()
543 .inspect_err(|_err| {
544 #[cfg(feature = "std")]
545 std::eprintln!("{}", PrintDiagnostic::new_without_color(_err))
546 })
547 .expect("failed to execute");
548
549 trace.last_stack_state()
550 }
551
552 fn get_program_and_host(&self) -> (Program, DefaultHost) {
560 let (program, kernel) = self.compile().expect("Failed to compile test source.");
561 let mut host = DefaultHost::default();
562 if let Some(kernel) = kernel {
563 host.load_library(kernel.mast_forest()).unwrap();
564 }
565 for library in &self.libraries {
566 host.load_library(library.mast_forest()).unwrap();
567 }
568 for (event, handler) in &self.handlers {
569 host.register_handler(event.clone(), handler.clone()).unwrap();
570 }
571
572 (program, host)
573 }
574
575 fn assert_result_with_step_execution(
576 &self,
577 fast_result: &Result<TraceBuildInputs, ExecutionError>,
578 ) {
579 fn compare_results(
580 left_result: Result<StackOutputs, &ExecutionError>,
581 right_result: &Result<StackOutputs, ExecutionError>,
582 left_name: &str,
583 right_name: &str,
584 ) {
585 match (left_result, right_result) {
586 (Ok(left_stack_outputs), Ok(right_stack_outputs)) => {
587 assert_eq!(
588 left_stack_outputs, *right_stack_outputs,
589 "stack outputs do not match between {left_name} and {right_name}"
590 );
591 },
592 (Err(left_err), Err(right_err)) => {
593 let right_diagnostic =
595 format!("{}", PrintDiagnostic::new_without_color(right_err));
596 let left_diagnostic =
597 format!("{}", PrintDiagnostic::new_without_color(left_err));
598
599 assert_eq!(
600 left_diagnostic, right_diagnostic,
601 "diagnostics do not match between {left_name} and {right_name}:\n{left_name}: {}\n{right_name}: {}",
602 left_diagnostic, right_diagnostic
603 );
604 },
605 (Ok(_), Err(right_err)) => {
606 let right_diagnostic =
607 format!("{}", PrintDiagnostic::new_without_color(right_err));
608 panic!(
609 "expected error, but {left_name} succeeded. {right_name} error:\n{right_diagnostic}"
610 );
611 },
612 (Err(left_err), Ok(_)) => {
613 panic!(
614 "expected success, but {left_name} failed. {left_name} error:\n{left_err}"
615 );
616 },
617 }
618 }
619
620 let (program, host) = self.get_program_and_host();
621 let mut host = host.with_source_manager(self.source_manager.clone());
622
623 let fast_result_by_step = {
624 let fast_process = FastProcessor::new(self.stack_inputs)
625 .with_advice(self.advice_inputs.clone())
626 .with_debugging(self.in_debug_mode)
627 .with_tracing(self.in_debug_mode);
628 fast_process.execute_by_step_sync(&program, &mut host)
629 };
630
631 compare_results(
632 fast_result.as_ref().map(|trace_inputs| *trace_inputs.stack_outputs()),
633 &fast_result_by_step,
634 "fast processor",
635 "fast processor by step",
636 );
637 }
638}
639
640pub fn append_word_to_vec(target: &mut Vec<u64>, word: Word) {
645 target.extend(word.iter().map(Felt::as_canonical_u64));
646}
647
648pub fn felt_slice_to_ints(values: &[Felt]) -> Vec<u64> {
650 values.iter().map(|e| (*e).as_canonical_u64()).collect()
651}
652
653pub fn resize_to_min_stack_depth(values: &[u64]) -> Vec<u64> {
654 let mut result: Vec<u64> = values.to_vec();
655 result.resize(MIN_STACK_DEPTH, 0);
656 result
657}
658
659#[cfg(not(target_family = "wasm"))]
661pub fn prop_randw<T: Arbitrary>() -> impl Strategy<Value = Vec<T>> {
662 use proptest::prelude::{any, prop};
663 prop::collection::vec(any::<T>(), 4)
664}
665
666pub fn build_expected_perm(values: &[u64]) -> [Felt; STATE_WIDTH] {
671 assert!(values.len() >= STATE_WIDTH, "expected at least 12 values for hperm test");
672
673 let mut state = [ZERO; STATE_WIDTH];
677 for i in 0..STATE_WIDTH {
678 state[i] = Felt::new(values[i]);
679 }
680
681 apply_permutation(&mut state);
683
684 let mut out = [ZERO; STATE_WIDTH];
686 out[..STATE_WIDTH].copy_from_slice(&state[..STATE_WIDTH]);
687
688 out
689}
690
691pub fn build_expected_hash(values: &[u64]) -> [Felt; 4] {
692 let digest = hash_elements(&values.iter().map(|&v| Felt::new(v)).collect::<Vec<_>>());
693 digest.into()
694}
695
696#[cfg(all(feature = "std", not(target_family = "wasm")))]
698pub fn push_inputs(inputs: &[u64]) -> String {
699 let mut result = String::new();
700
701 inputs.iter().for_each(|v| result.push_str(&format!("push.{v}\n")));
702 result
703}
704
705pub fn get_column_name(col_idx: usize) -> String {
707 use miden_air::trace::{
708 CLK_COL_IDX, CTX_COL_IDX, DECODER_TRACE_OFFSET, FN_HASH_OFFSET, RANGE_CHECK_TRACE_OFFSET,
709 STACK_TRACE_OFFSET,
710 decoder::{
711 ADDR_COL_IDX, GROUP_COUNT_COL_IDX, HASHER_STATE_OFFSET, IN_SPAN_COL_IDX,
712 NUM_HASHER_COLUMNS, NUM_OP_BATCH_FLAGS, NUM_OP_BITS, NUM_OP_BITS_EXTRA_COLS,
713 OP_BATCH_FLAGS_OFFSET, OP_BITS_EXTRA_COLS_OFFSET, OP_BITS_OFFSET, OP_INDEX_COL_IDX,
714 },
715 stack::{B0_COL_IDX, B1_COL_IDX, H0_COL_IDX, STACK_TOP_OFFSET},
716 };
717
718 match col_idx {
719 CLK_COL_IDX => "clk".to_string(),
721 CTX_COL_IDX => "ctx".to_string(),
722 i if (FN_HASH_OFFSET..FN_HASH_OFFSET + 4).contains(&i) => {
723 format!("fn_hash[{}]", i - FN_HASH_OFFSET)
724 },
725
726 i if i == DECODER_TRACE_OFFSET + ADDR_COL_IDX => "decoder_addr".to_string(),
728 i if (DECODER_TRACE_OFFSET + OP_BITS_OFFSET
729 ..DECODER_TRACE_OFFSET + OP_BITS_OFFSET + NUM_OP_BITS)
730 .contains(&i) =>
731 {
732 format!("op_bits[{}]", i - (DECODER_TRACE_OFFSET + OP_BITS_OFFSET))
733 },
734 i if (DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET
735 ..DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + NUM_HASHER_COLUMNS)
736 .contains(&i) =>
737 {
738 format!("hasher_state[{}]", i - (DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET))
739 },
740 i if i == DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX => "in_span".to_string(),
741 i if i == DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX => "group_count".to_string(),
742 i if i == DECODER_TRACE_OFFSET + OP_INDEX_COL_IDX => "op_index".to_string(),
743 i if (DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET
744 ..DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + NUM_OP_BATCH_FLAGS)
745 .contains(&i) =>
746 {
747 format!("op_batch_flag[{}]", i - (DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET))
748 },
749 i if (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET
750 ..DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + NUM_OP_BITS_EXTRA_COLS)
751 .contains(&i) =>
752 {
753 format!("op_bits_extra[{}]", i - (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET))
754 },
755 i if (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET
756 ..DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + NUM_OP_BITS_EXTRA_COLS)
757 .contains(&i) =>
758 {
759 format!("op_bits_extra[{}]", i - (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET))
760 },
761
762 i if (STACK_TRACE_OFFSET + STACK_TOP_OFFSET
764 ..STACK_TRACE_OFFSET + STACK_TOP_OFFSET + MIN_STACK_DEPTH)
765 .contains(&i) =>
766 {
767 format!("stack[{}]", i - (STACK_TRACE_OFFSET + STACK_TOP_OFFSET))
768 },
769 i if i == STACK_TRACE_OFFSET + B0_COL_IDX => "stack_b0".to_string(),
770 i if i == STACK_TRACE_OFFSET + B1_COL_IDX => "stack_b1".to_string(),
771 i if i == STACK_TRACE_OFFSET + H0_COL_IDX => "stack_h0".to_string(),
772
773 i if i >= RANGE_CHECK_TRACE_OFFSET => {
775 format!("range_check[{}]", i - RANGE_CHECK_TRACE_OFFSET)
776 },
777
778 _ => format!("unknown_col[{}]", col_idx),
780 }
781}