1use alloc::vec::Vec;
2#[cfg(any(test, feature = "testing"))]
3use core::ops::Range;
4
5#[cfg(feature = "std")]
6use miden_air::trace::PADDED_TRACE_WIDTH;
7use miden_air::{
8 AirWitness, AuxBuilder, ProcessorAir, PublicInputs, debug,
9 trace::{
10 DECODER_TRACE_OFFSET, MainTrace, STACK_TRACE_OFFSET, TRACE_WIDTH,
11 decoder::{NUM_USER_OP_HELPERS, USER_OP_HELPERS_OFFSET},
12 },
13};
14
15use crate::{
16 AdviceProvider, Felt, MIN_STACK_DEPTH, ProgramInfo, StackInputs, StackOutputs, Word, ZERO,
17 fast::ExecutionOutput,
18 field::{ExtensionField, QuadFelt},
19 precompile::{PrecompileRequest, PrecompileTranscript},
20 utils::{ColMatrix, Matrix, RowMajorMatrix},
21};
22
23pub(crate) mod utils;
24use miden_air::trace::Challenges;
25use utils::{AuxColumnBuilder, TraceFragment};
26
27pub mod chiplets;
28pub mod execution_tracer;
29
30mod decoder;
31mod parallel;
32mod range;
33mod stack;
34mod trace_state;
35
36#[cfg(test)]
37mod tests;
38
39pub use miden_air::trace::RowIndex;
43pub use parallel::{CORE_TRACE_WIDTH, build_trace, build_trace_with_max_len};
44pub use utils::{ChipletsLengths, TraceLenSummary};
45
46#[derive(Debug)]
58pub struct ExecutionTrace {
59 main_trace: MainTrace,
60 aux_trace_builders: AuxTraceBuilders,
61 program_info: ProgramInfo,
62 stack_outputs: StackOutputs,
63 advice: AdviceProvider,
64 final_pc_transcript: PrecompileTranscript,
65 trace_len_summary: TraceLenSummary,
66}
67
68impl ExecutionTrace {
69 pub fn new_from_parts(
73 program_info: ProgramInfo,
74 execution_output: ExecutionOutput,
75 main_trace: MainTrace,
76 aux_trace_builders: AuxTraceBuilders,
77 trace_len_summary: TraceLenSummary,
78 ) -> Self {
79 Self {
80 main_trace,
81 aux_trace_builders,
82 program_info,
83 stack_outputs: execution_output.stack,
84 advice: execution_output.advice,
85 final_pc_transcript: execution_output.final_pc_transcript,
86 trace_len_summary,
87 }
88 }
89
90 pub fn program_info(&self) -> &ProgramInfo {
95 &self.program_info
96 }
97
98 pub fn program_hash(&self) -> &Word {
100 self.program_info.program_hash()
101 }
102
103 pub fn stack_outputs(&self) -> &StackOutputs {
105 &self.stack_outputs
106 }
107
108 pub fn public_inputs(&self) -> PublicInputs {
110 PublicInputs::new(
111 self.program_info.clone(),
112 self.init_stack_state(),
113 self.stack_outputs,
114 self.final_pc_transcript.state(),
115 )
116 }
117
118 pub fn to_public_values(&self) -> Vec<Felt> {
120 self.public_inputs().to_elements()
121 }
122
123 pub fn aux_trace_builders(&self) -> AuxTraceBuilders {
125 self.aux_trace_builders.clone()
126 }
127
128 pub fn main_trace(&self) -> &MainTrace {
130 &self.main_trace
131 }
132
133 pub fn main_trace_mut(&mut self) -> &mut MainTrace {
135 &mut self.main_trace
136 }
137
138 pub fn precompile_requests(&self) -> &[PrecompileRequest] {
140 self.advice.precompile_requests()
141 }
142
143 pub fn take_precompile_requests(&mut self) -> Vec<PrecompileRequest> {
148 self.advice.take_precompile_requests()
149 }
150
151 pub fn final_precompile_transcript(&self) -> PrecompileTranscript {
153 self.final_pc_transcript
154 }
155
156 pub fn init_stack_state(&self) -> StackInputs {
158 let mut result = [ZERO; MIN_STACK_DEPTH];
159 for (i, result) in result.iter_mut().enumerate() {
160 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[0];
161 }
162 result.into()
163 }
164
165 pub fn last_stack_state(&self) -> StackOutputs {
167 let last_step = self.last_step();
168 let mut result = [ZERO; MIN_STACK_DEPTH];
169 for (i, result) in result.iter_mut().enumerate() {
170 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[last_step];
171 }
172 result.into()
173 }
174
175 pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
177 let mut result = [ZERO; NUM_USER_OP_HELPERS];
178 for (i, result) in result.iter_mut().enumerate() {
179 *result = self.main_trace.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i)
180 [clk as usize];
181 }
182 result
183 }
184
185 pub fn get_trace_len(&self) -> usize {
187 self.main_trace.num_rows()
188 }
189
190 pub fn length(&self) -> usize {
192 self.get_trace_len()
193 }
194
195 pub fn trace_len_summary(&self) -> &TraceLenSummary {
197 &self.trace_len_summary
198 }
199
200 pub fn advice_provider(&self) -> &AdviceProvider {
202 &self.advice
203 }
204
205 pub fn into_outputs(self) -> (StackOutputs, AdviceProvider) {
207 (self.stack_outputs, self.advice)
208 }
209
210 pub fn check_constraints(&self) {
224 let public_inputs = self.public_inputs();
225 let trace_matrix = self.to_row_major_matrix();
226
227 let (public_values, kernel_felts) = public_inputs.to_air_inputs();
228 let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts];
229
230 let aux_builder = self.aux_trace_builders();
231
232 let digest = crate::crypto::hash::Poseidon2::hash_elements(&public_values);
235 let challenges =
236 [QuadFelt::new([digest[0], digest[1]]), QuadFelt::new([digest[2], digest[3]])];
237
238 let witness = AirWitness::new(&trace_matrix, &public_values, var_len_public_inputs);
239 debug::check_constraints(&ProcessorAir, witness, &aux_builder, &challenges);
240 }
241
242 pub fn to_row_major_matrix(&self) -> RowMajorMatrix<Felt> {
249 let trace_len = self.get_trace_len();
250 let mut col_major_data = Vec::with_capacity(TRACE_WIDTH * trace_len);
251 for col_idx in 0..TRACE_WIDTH {
252 col_major_data.extend_from_slice(self.main_trace.get_column(col_idx));
253 }
254 let col_major_matrix = RowMajorMatrix::new(col_major_data, trace_len);
255 col_major_matrix.transpose()
256 }
257
258 fn last_step(&self) -> usize {
263 self.length() - 1
264 }
265
266 #[cfg(feature = "std")]
269 pub fn print(&self) {
270 use miden_air::trace::TRACE_WIDTH;
271
272 let mut row = [ZERO; PADDED_TRACE_WIDTH];
273 for i in 0..self.length() {
274 self.main_trace.read_row_into(i, &mut row);
275 std::println!(
276 "{:?}",
277 row.iter().take(TRACE_WIDTH).map(|v| v.as_canonical_u64()).collect::<Vec<_>>()
278 );
279 }
280 }
281
282 #[cfg(any(test, feature = "testing"))]
283 pub fn get_column_range(&self, range: Range<usize>) -> Vec<Vec<Felt>> {
284 self.main_trace.get_column_range(range)
285 }
286
287 pub fn build_aux_trace<E>(&self, rand_elements: &[E]) -> Option<ColMatrix<E>>
288 where
289 E: ExtensionField<Felt>,
290 {
291 let aux_columns =
292 self.aux_trace_builders.build_aux_columns(&self.main_trace, rand_elements);
293
294 Some(ColMatrix::new(aux_columns))
295 }
296}
297
298#[derive(Debug, Clone)]
302pub struct AuxTraceBuilders {
303 pub(crate) decoder: decoder::AuxTraceBuilder,
304 pub(crate) stack: stack::AuxTraceBuilder,
305 pub(crate) range: range::AuxTraceBuilder,
306 pub(crate) chiplets: chiplets::AuxTraceBuilder,
307}
308
309impl AuxTraceBuilders {
310 pub fn build_aux_columns<E>(&self, main_trace: &MainTrace, challenges: &[E]) -> Vec<Vec<E>>
314 where
315 E: ExtensionField<Felt>,
316 {
317 let challenges = Challenges::<E>::new(challenges[0], challenges[1]);
320
321 let decoder_cols = self.decoder.build_aux_columns(main_trace, &challenges);
322 let stack_cols = self.stack.build_aux_columns(main_trace, &challenges);
323 let range_cols = self.range.build_aux_columns(main_trace, &challenges);
324 let chiplets_cols = self.chiplets.build_aux_columns(main_trace, &challenges);
325
326 decoder_cols
327 .into_iter()
328 .chain(stack_cols)
329 .chain(range_cols)
330 .chain(chiplets_cols)
331 .collect()
332 }
333}
334
335impl<EF: ExtensionField<Felt>> AuxBuilder<Felt, EF> for AuxTraceBuilders {
344 fn build_aux_trace(
345 &self,
346 main: &RowMajorMatrix<Felt>,
347 challenges: &[EF],
348 ) -> (RowMajorMatrix<EF>, Vec<EF>) {
349 let _span = tracing::info_span!("build_aux_trace").entered();
350
351 let main_trace_col_major = {
355 let num_rows = main.height();
356 let last_program_row = (1..num_rows)
358 .find(|&i| {
359 main.get(i, 0).expect("valid indices")
360 != main.get(i - 1, 0).expect("valid indices") + Felt::ONE
361 })
362 .map_or(num_rows - 1, |i| i - 1);
363 let transposed = main.transpose();
364 let columns: Vec<Vec<Felt>> = transposed.row_slices().map(|row| row.to_vec()).collect();
365 MainTrace::new(ColMatrix::new(columns), last_program_row.into())
366 };
367
368 let aux_columns = self.build_aux_columns(&main_trace_col_major, challenges);
370 assert!(!aux_columns.is_empty(), "aux columns should not be empty");
371
372 let trace_len = main.height();
375 let num_ef_cols = aux_columns.len();
376 let mut col_major_data = Vec::with_capacity(trace_len * num_ef_cols);
377 for col in aux_columns {
378 col_major_data.extend_from_slice(&col);
379 }
380 let aux_trace = RowMajorMatrix::new(col_major_data, trace_len).transpose();
381
382 let last_row = aux_trace
384 .row_slice(trace_len - 1)
385 .expect("aux trace has at least one row")
386 .to_vec();
387
388 (aux_trace, last_row)
389 }
390}