1use alloc::vec::Vec;
2use core::mem;
3
4use miden_air::trace::{
5 AUX_TRACE_RAND_ELEMENTS, AUX_TRACE_WIDTH, DECODER_TRACE_OFFSET, MIN_TRACE_LEN,
6 PADDED_TRACE_WIDTH, STACK_TRACE_OFFSET, TRACE_WIDTH,
7 decoder::{NUM_USER_OP_HELPERS, USER_OP_HELPERS_OFFSET},
8 main_trace::MainTrace,
9};
10use miden_core::{ProgramInfo, StackInputs, StackOutputs, Word, ZERO, stack::MIN_STACK_DEPTH};
11use winter_prover::{EvaluationFrame, Trace, TraceInfo, crypto::RandomCoin};
12
13use super::{
14 AdviceProvider, ColMatrix, Felt, FieldElement, Process,
15 chiplets::AuxTraceBuilder as ChipletsAuxTraceBuilder, crypto::RpoRandomCoin,
16 decoder::AuxTraceBuilder as DecoderAuxTraceBuilder,
17 range::AuxTraceBuilder as RangeCheckerAuxTraceBuilder,
18 stack::AuxTraceBuilder as StackAuxTraceBuilder,
19};
20
21mod utils;
22pub use utils::{AuxColumnBuilder, ChipletsLengths, TraceFragment, TraceLenSummary};
23
24#[cfg(test)]
25mod tests;
26#[cfg(test)]
27use super::EMPTY_WORD;
28
29pub const NUM_RAND_ROWS: usize = 1;
34
35#[derive(Debug)]
39pub struct AuxTraceBuilders {
40 pub(crate) decoder: DecoderAuxTraceBuilder,
41 pub(crate) stack: StackAuxTraceBuilder,
42 pub(crate) range: RangeCheckerAuxTraceBuilder,
43 pub(crate) chiplets: ChipletsAuxTraceBuilder,
44}
45
46#[derive(Debug)]
54pub struct ExecutionTrace {
55 meta: Vec<u8>,
56 trace_info: TraceInfo,
57 main_trace: MainTrace,
58 aux_trace_builders: AuxTraceBuilders,
59 program_info: ProgramInfo,
60 stack_outputs: StackOutputs,
61 advice: AdviceProvider,
62 trace_len_summary: TraceLenSummary,
63}
64
65impl ExecutionTrace {
66 pub const NUM_RAND_ROWS: usize = NUM_RAND_ROWS;
71
72 pub fn new(mut process: Process, stack_outputs: StackOutputs) -> Self {
76 let program_hash = process.decoder.program_hash().into();
81 let rng = RpoRandomCoin::new(program_hash);
82
83 let kernel = process.kernel().clone();
85 let program_info = ProgramInfo::new(program_hash, kernel);
86 let advice = mem::take(&mut process.advice);
87 let (main_trace, aux_trace_builders, trace_len_summary) = finalize_trace(process, rng);
88 let trace_info = TraceInfo::new_multi_segment(
89 PADDED_TRACE_WIDTH,
90 AUX_TRACE_WIDTH,
91 AUX_TRACE_RAND_ELEMENTS,
92 main_trace.num_rows(),
93 vec![],
94 );
95
96 Self {
97 meta: Vec::new(),
98 trace_info,
99 aux_trace_builders,
100 main_trace,
101 program_info,
102 stack_outputs,
103 advice,
104 trace_len_summary,
105 }
106 }
107
108 pub fn program_info(&self) -> &ProgramInfo {
113 &self.program_info
114 }
115
116 pub fn program_hash(&self) -> &Word {
118 self.program_info.program_hash()
119 }
120
121 pub fn stack_outputs(&self) -> &StackOutputs {
123 &self.stack_outputs
124 }
125
126 pub fn init_stack_state(&self) -> StackInputs {
128 let mut result = [ZERO; MIN_STACK_DEPTH];
129 for (i, result) in result.iter_mut().enumerate() {
130 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[0];
131 }
132 result.into()
133 }
134
135 pub fn last_stack_state(&self) -> StackOutputs {
137 let last_step = self.last_step();
138 let mut result = [ZERO; MIN_STACK_DEPTH];
139 for (i, result) in result.iter_mut().enumerate() {
140 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[last_step];
141 }
142 result.into()
143 }
144
145 pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
147 let mut result = [ZERO; NUM_USER_OP_HELPERS];
148 for (i, result) in result.iter_mut().enumerate() {
149 *result = self.main_trace.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i)
150 [clk as usize];
151 }
152 result
153 }
154
155 pub fn get_trace_len(&self) -> usize {
157 self.main_trace.num_rows()
158 }
159
160 pub fn trace_len_summary(&self) -> &TraceLenSummary {
162 &self.trace_len_summary
163 }
164
165 pub fn advice_provider(&self) -> &AdviceProvider {
167 &self.advice
168 }
169
170 pub fn meta(&self) -> &[u8] {
172 &self.meta
173 }
174
175 pub fn into_outputs(self) -> (StackOutputs, AdviceProvider) {
177 (self.stack_outputs, self.advice)
178 }
179
180 fn last_step(&self) -> usize {
185 self.length() - NUM_RAND_ROWS - 1
186 }
187
188 #[cfg(feature = "std")]
191 #[allow(dead_code)]
192 pub fn print(&self) {
193 let mut row = [ZERO; PADDED_TRACE_WIDTH];
194 for i in 0..self.length() {
195 self.main_trace.read_row_into(i, &mut row);
196 std::println!(
197 "{:?}",
198 row.iter().take(TRACE_WIDTH).map(|v| v.as_int()).collect::<Vec<_>>()
199 );
200 }
201 }
202
203 #[cfg(test)]
204 pub fn test_finalize_trace(process: Process) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) {
205 let rng = RpoRandomCoin::new(EMPTY_WORD);
206 finalize_trace(process, rng)
207 }
208
209 pub fn build_aux_trace<E>(&self, rand_elements: &[E]) -> Option<ColMatrix<E>>
210 where
211 E: FieldElement<BaseField = Felt>,
212 {
213 let decoder_aux_columns = self
215 .aux_trace_builders
216 .decoder
217 .build_aux_columns(&self.main_trace, rand_elements);
218
219 let stack_aux_columns =
221 self.aux_trace_builders.stack.build_aux_columns(&self.main_trace, rand_elements);
222
223 let range_aux_columns =
225 self.aux_trace_builders.range.build_aux_columns(&self.main_trace, rand_elements);
226
227 let chiplets = self
229 .aux_trace_builders
230 .chiplets
231 .build_aux_columns(&self.main_trace, rand_elements);
232
233 let mut aux_columns = decoder_aux_columns
235 .into_iter()
236 .chain(stack_aux_columns)
237 .chain(range_aux_columns)
238 .chain(chiplets)
239 .collect::<Vec<_>>();
240
241 let mut rng = RpoRandomCoin::new(*self.program_hash());
243 for i in self.length() - NUM_RAND_ROWS..self.length() {
244 for column in aux_columns.iter_mut() {
245 column[i] = rng.draw().expect("failed to draw a random value");
246 }
247 }
248
249 Some(ColMatrix::new(aux_columns))
250 }
251}
252
253impl Trace for ExecutionTrace {
257 type BaseField = Felt;
258
259 fn length(&self) -> usize {
260 self.main_trace.num_rows()
261 }
262
263 fn main_segment(&self) -> &ColMatrix<Felt> {
264 &self.main_trace
265 }
266
267 fn read_main_frame(&self, row_idx: usize, frame: &mut EvaluationFrame<Felt>) {
268 let next_row_idx = (row_idx + 1) % self.length();
269 self.main_trace.read_row_into(row_idx, frame.current_mut());
270 self.main_trace.read_row_into(next_row_idx, frame.next_mut());
271 }
272
273 fn info(&self) -> &TraceInfo {
274 &self.trace_info
275 }
276}
277
278fn finalize_trace(
290 process: Process,
291 mut rng: RpoRandomCoin,
292) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) {
293 let (system, decoder, stack, mut range, chiplets) = process.into_parts();
294
295 let clk = system.clk();
296
297 assert_eq!(clk.as_usize(), system.trace_len(), "inconsistent system trace lengths");
299 assert_eq!(clk.as_usize(), decoder.trace_len(), "inconsistent decoder trace length");
300 assert_eq!(clk.as_usize(), stack.trace_len(), "inconsistent stack trace lengths");
301
302 chiplets.append_range_checks(&mut range);
304
305 let range_table_len = range.get_number_range_checker_rows();
307
308 let max_len = range_table_len.max(clk.into()).max(chiplets.trace_len());
310
311 let trace_len = (max_len + NUM_RAND_ROWS).next_power_of_two();
314 assert!(
315 trace_len >= MIN_TRACE_LEN,
316 "trace length must be at least {MIN_TRACE_LEN}, but was {trace_len}",
317 );
318
319 let trace_len_summary =
321 TraceLenSummary::new(clk.into(), range_table_len, ChipletsLengths::new(&chiplets));
322
323 let system_trace = system.into_trace(trace_len, NUM_RAND_ROWS);
325 let decoder_trace = decoder.into_trace(trace_len, NUM_RAND_ROWS);
326 let stack_trace = stack.into_trace(trace_len, NUM_RAND_ROWS);
327 let chiplets_trace = chiplets.into_trace(trace_len, NUM_RAND_ROWS);
328
329 let range_check_trace = range.into_trace_with_table(range_table_len, trace_len, NUM_RAND_ROWS);
331
332 let padding = vec![vec![ZERO; trace_len]; PADDED_TRACE_WIDTH - TRACE_WIDTH];
334
335 let mut trace = system_trace
336 .into_iter()
337 .chain(decoder_trace.trace)
338 .chain(stack_trace.trace)
339 .chain(range_check_trace.trace)
340 .chain(chiplets_trace.trace)
341 .chain(padding)
342 .collect::<Vec<_>>();
343
344 for i in trace_len - NUM_RAND_ROWS..trace_len {
346 for column in trace.iter_mut().take(TRACE_WIDTH) {
347 column[i] = rng.draw().expect("failed to draw a random value");
348 }
349 }
350
351 let aux_trace_hints = AuxTraceBuilders {
352 decoder: decoder_trace.aux_builder,
353 stack: StackAuxTraceBuilder,
354 range: range_check_trace.aux_builder,
355 chiplets: chiplets_trace.aux_builder,
356 };
357
358 let main_trace = MainTrace::new(ColMatrix::new(trace), clk);
359
360 (main_trace, aux_trace_hints, trace_len_summary)
361}