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::{
11 Kernel, ProgramInfo, StackInputs, StackOutputs, Word, ZERO,
12 precompile::{PrecompileRequest, PrecompileTranscript},
13 stack::MIN_STACK_DEPTH,
14};
15use winter_prover::{EvaluationFrame, Trace, TraceInfo, crypto::RandomCoin};
16
17use super::{
18 AdviceProvider, ColMatrix, Felt, FieldElement, Process,
19 chiplets::AuxTraceBuilder as ChipletsAuxTraceBuilder, crypto::RpoRandomCoin,
20 decoder::AuxTraceBuilder as DecoderAuxTraceBuilder,
21 range::AuxTraceBuilder as RangeCheckerAuxTraceBuilder,
22 stack::AuxTraceBuilder as StackAuxTraceBuilder,
23};
24use crate::fast::ExecutionOutput;
25
26mod utils;
27pub use utils::{AuxColumnBuilder, ChipletsLengths, TraceFragment, TraceLenSummary};
28
29#[cfg(test)]
30mod tests;
31#[cfg(test)]
32use super::EMPTY_WORD;
33
34pub const NUM_RAND_ROWS: usize = 1;
39
40#[derive(Debug)]
44pub struct AuxTraceBuilders {
45 pub(crate) decoder: DecoderAuxTraceBuilder,
46 pub(crate) stack: StackAuxTraceBuilder,
47 pub(crate) range: RangeCheckerAuxTraceBuilder,
48 pub(crate) chiplets: ChipletsAuxTraceBuilder,
49}
50
51#[derive(Debug)]
59pub struct ExecutionTrace {
60 meta: Vec<u8>,
61 trace_info: TraceInfo,
62 main_trace: MainTrace,
63 aux_trace_builders: AuxTraceBuilders,
64 program_info: ProgramInfo,
65 stack_outputs: StackOutputs,
66 advice: AdviceProvider,
67 trace_len_summary: TraceLenSummary,
68 final_pc_transcript: PrecompileTranscript,
69}
70
71impl ExecutionTrace {
72 pub const NUM_RAND_ROWS: usize = NUM_RAND_ROWS;
77
78 pub fn new(mut process: Process, stack_outputs: StackOutputs) -> Self {
82 let program_hash = process.decoder.program_hash().into();
87 let rng = RpoRandomCoin::new(program_hash);
88
89 let kernel = process.kernel().clone();
91 let program_info = ProgramInfo::new(program_hash, kernel);
92 let advice = mem::take(&mut process.advice);
93 let (main_trace, aux_trace_builders, trace_len_summary, final_pc_transcript) =
94 finalize_trace(process, rng);
95 let trace_info = TraceInfo::new_multi_segment(
96 PADDED_TRACE_WIDTH,
97 AUX_TRACE_WIDTH,
98 AUX_TRACE_RAND_ELEMENTS,
99 main_trace.num_rows(),
100 vec![],
101 );
102
103 Self {
104 meta: Vec::new(),
105 trace_info,
106 aux_trace_builders,
107 main_trace,
108 program_info,
109 stack_outputs,
110 advice,
111 trace_len_summary,
112 final_pc_transcript,
113 }
114 }
115
116 pub fn new_from_parts(
117 program_hash: Word,
118 kernel: Kernel,
119 execution_output: ExecutionOutput,
120 main_trace: MainTrace,
121 aux_trace_builders: AuxTraceBuilders,
122 trace_len_summary: TraceLenSummary,
123 ) -> Self {
124 let program_info = ProgramInfo::new(program_hash, kernel);
125 let trace_info = TraceInfo::new_multi_segment(
126 PADDED_TRACE_WIDTH,
127 AUX_TRACE_WIDTH,
128 AUX_TRACE_RAND_ELEMENTS,
129 main_trace.num_rows(),
130 vec![],
131 );
132
133 Self {
134 meta: Vec::new(),
135 trace_info,
136 aux_trace_builders,
137 main_trace,
138 program_info,
139 stack_outputs: execution_output.stack,
140 advice: execution_output.advice,
141 trace_len_summary,
142 final_pc_transcript: execution_output.final_pc_transcript,
143 }
144 }
145
146 pub fn program_info(&self) -> &ProgramInfo {
151 &self.program_info
152 }
153
154 pub fn program_hash(&self) -> &Word {
156 self.program_info.program_hash()
157 }
158
159 pub fn stack_outputs(&self) -> &StackOutputs {
161 &self.stack_outputs
162 }
163
164 pub fn precompile_requests(&self) -> &[PrecompileRequest] {
166 self.advice.precompile_requests()
167 }
168
169 pub fn take_precompile_requests(&mut self) -> Vec<PrecompileRequest> {
174 self.advice.take_precompile_requests()
175 }
176
177 pub fn final_precompile_transcript(&self) -> PrecompileTranscript {
179 self.final_pc_transcript
180 }
181
182 pub fn init_stack_state(&self) -> StackInputs {
184 let mut result = [ZERO; MIN_STACK_DEPTH];
185 for (i, result) in result.iter_mut().enumerate() {
186 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[0];
187 }
188 result.into()
189 }
190
191 pub fn last_stack_state(&self) -> StackOutputs {
193 let last_step = self.last_step();
194 let mut result = [ZERO; MIN_STACK_DEPTH];
195 for (i, result) in result.iter_mut().enumerate() {
196 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[last_step];
197 }
198 result.into()
199 }
200
201 pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
203 let mut result = [ZERO; NUM_USER_OP_HELPERS];
204 for (i, result) in result.iter_mut().enumerate() {
205 *result = self.main_trace.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i)
206 [clk as usize];
207 }
208 result
209 }
210
211 pub fn get_trace_len(&self) -> usize {
213 self.main_trace.num_rows()
214 }
215
216 pub fn trace_len_summary(&self) -> &TraceLenSummary {
218 &self.trace_len_summary
219 }
220
221 pub fn advice_provider(&self) -> &AdviceProvider {
223 &self.advice
224 }
225
226 pub fn meta(&self) -> &[u8] {
228 &self.meta
229 }
230
231 pub fn into_outputs(self) -> (StackOutputs, AdviceProvider) {
233 (self.stack_outputs, self.advice)
234 }
235
236 fn last_step(&self) -> usize {
241 self.length() - NUM_RAND_ROWS - 1
242 }
243
244 #[cfg(feature = "std")]
247 #[allow(dead_code)]
248 pub fn print(&self) {
249 let mut row = [ZERO; PADDED_TRACE_WIDTH];
250 for i in 0..self.length() {
251 self.main_trace.read_row_into(i, &mut row);
252 std::println!(
253 "{:?}",
254 row.iter().take(TRACE_WIDTH).map(|v| v.as_int()).collect::<Vec<_>>()
255 );
256 }
257 }
258
259 #[cfg(test)]
260 pub fn test_finalize_trace(process: Process) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) {
261 let rng = RpoRandomCoin::new(EMPTY_WORD);
262 let (main_trace, aux_trace_builders, trace_len_summary, _final_pc_transcript) =
263 finalize_trace(process, rng);
264 (main_trace, aux_trace_builders, trace_len_summary)
265 }
266
267 pub fn build_aux_trace<E>(&self, rand_elements: &[E]) -> Option<ColMatrix<E>>
268 where
269 E: FieldElement<BaseField = Felt>,
270 {
271 let decoder_aux_columns = self
273 .aux_trace_builders
274 .decoder
275 .build_aux_columns(&self.main_trace, rand_elements);
276
277 let stack_aux_columns =
279 self.aux_trace_builders.stack.build_aux_columns(&self.main_trace, rand_elements);
280
281 let range_aux_columns =
283 self.aux_trace_builders.range.build_aux_columns(&self.main_trace, rand_elements);
284
285 let chiplets = self
287 .aux_trace_builders
288 .chiplets
289 .build_aux_columns(&self.main_trace, rand_elements);
290
291 let mut aux_columns = decoder_aux_columns
293 .into_iter()
294 .chain(stack_aux_columns)
295 .chain(range_aux_columns)
296 .chain(chiplets)
297 .collect::<Vec<_>>();
298
299 let mut rng = RpoRandomCoin::new(*self.program_hash());
301 for i in self.length() - NUM_RAND_ROWS..self.length() {
302 for column in aux_columns.iter_mut() {
303 column[i] = rng.draw().expect("failed to draw a random value");
304 }
305 }
306
307 Some(ColMatrix::new(aux_columns))
308 }
309}
310
311impl Trace for ExecutionTrace {
315 type BaseField = Felt;
316
317 fn length(&self) -> usize {
318 self.main_trace.num_rows()
319 }
320
321 fn main_segment(&self) -> &ColMatrix<Felt> {
322 &self.main_trace
323 }
324
325 fn read_main_frame(&self, row_idx: usize, frame: &mut EvaluationFrame<Felt>) {
326 let next_row_idx = (row_idx + 1) % self.length();
327 self.main_trace.read_row_into(row_idx, frame.current_mut());
328 self.main_trace.read_row_into(next_row_idx, frame.next_mut());
329 }
330
331 fn info(&self) -> &TraceInfo {
332 &self.trace_info
333 }
334}
335
336fn finalize_trace(
348 process: Process,
349 mut rng: RpoRandomCoin,
350) -> (MainTrace, AuxTraceBuilders, TraceLenSummary, PrecompileTranscript) {
351 let (system, decoder, stack, mut range, chiplets, final_capacity) = process.into_parts();
352 let final_pc_transcript = PrecompileTranscript::from_state(final_capacity);
353
354 let clk = system.clk();
355
356 assert_eq!(clk.as_usize(), system.trace_len(), "inconsistent system trace lengths");
358 assert_eq!(clk.as_usize(), decoder.trace_len(), "inconsistent decoder trace length");
359 assert_eq!(clk.as_usize(), stack.trace_len(), "inconsistent stack trace lengths");
360
361 chiplets.append_range_checks(&mut range);
363
364 let range_table_len = range.get_number_range_checker_rows();
366
367 let max_len = range_table_len.max(clk.into()).max(chiplets.trace_len());
369
370 let trace_len = (max_len + NUM_RAND_ROWS).next_power_of_two();
373 assert!(
374 trace_len >= MIN_TRACE_LEN,
375 "trace length must be at least {MIN_TRACE_LEN}, but was {trace_len}",
376 );
377
378 let trace_len_summary =
380 TraceLenSummary::new(clk.into(), range_table_len, ChipletsLengths::new(&chiplets));
381
382 let system_trace = system.into_trace(trace_len, NUM_RAND_ROWS);
384 let decoder_trace = decoder.into_trace(trace_len, NUM_RAND_ROWS);
385 let stack_trace = stack.into_trace(trace_len, NUM_RAND_ROWS);
386 let chiplets_trace = chiplets.into_trace(trace_len, NUM_RAND_ROWS, final_capacity);
387
388 let range_check_trace = range.into_trace_with_table(range_table_len, trace_len, NUM_RAND_ROWS);
390
391 let padding = vec![vec![ZERO; trace_len]; PADDED_TRACE_WIDTH - TRACE_WIDTH];
393
394 let mut trace = system_trace
395 .into_iter()
396 .chain(decoder_trace.trace)
397 .chain(stack_trace.trace)
398 .chain(range_check_trace.trace)
399 .chain(chiplets_trace.trace)
400 .chain(padding)
401 .collect::<Vec<_>>();
402
403 for i in trace_len - NUM_RAND_ROWS..trace_len {
405 for column in trace.iter_mut().take(TRACE_WIDTH) {
406 column[i] = rng.draw().expect("failed to draw a random value");
407 }
408 }
409
410 let aux_trace_hints = AuxTraceBuilders {
411 decoder: decoder_trace.aux_builder,
412 stack: StackAuxTraceBuilder,
413 range: range_check_trace.aux_builder,
414 chiplets: chiplets_trace.aux_builder,
415 };
416
417 let main_trace = MainTrace::new(ColMatrix::new(trace), clk);
418
419 (main_trace, aux_trace_hints, trace_len_summary, final_pc_transcript)
420}