1use alloc::vec::Vec;
2
3use miden_air::trace::{
4 AUX_TRACE_RAND_ELEMENTS, AUX_TRACE_WIDTH, DECODER_TRACE_OFFSET, MIN_TRACE_LEN,
5 PADDED_TRACE_WIDTH, STACK_TRACE_OFFSET, TRACE_WIDTH,
6 decoder::{NUM_USER_OP_HELPERS, USER_OP_HELPERS_OFFSET},
7 main_trace::MainTrace,
8};
9use vm_core::{ProgramInfo, StackInputs, StackOutputs, ZERO, stack::MIN_STACK_DEPTH};
10use winter_prover::{EvaluationFrame, Trace, TraceInfo, crypto::RandomCoin};
11
12use super::{
13 ColMatrix, Digest, Felt, FieldElement, Process,
14 chiplets::AuxTraceBuilder as ChipletsAuxTraceBuilder, crypto::RpoRandomCoin,
15 decoder::AuxTraceBuilder as DecoderAuxTraceBuilder,
16 range::AuxTraceBuilder as RangeCheckerAuxTraceBuilder,
17 stack::AuxTraceBuilder as StackAuxTraceBuilder,
18};
19
20mod utils;
21pub use utils::{AuxColumnBuilder, ChipletsLengths, TraceFragment, TraceLenSummary};
22
23#[cfg(test)]
24mod tests;
25#[cfg(test)]
26use super::EMPTY_WORD;
27
28pub const NUM_RAND_ROWS: usize = 1;
33
34#[derive(Debug)]
38pub struct AuxTraceBuilders {
39 pub(crate) decoder: DecoderAuxTraceBuilder,
40 pub(crate) stack: StackAuxTraceBuilder,
41 pub(crate) range: RangeCheckerAuxTraceBuilder,
42 pub(crate) chiplets: ChipletsAuxTraceBuilder,
43}
44
45#[derive(Debug)]
53pub struct ExecutionTrace {
54 meta: Vec<u8>,
55 trace_info: TraceInfo,
56 main_trace: MainTrace,
57 aux_trace_builders: AuxTraceBuilders,
58 program_info: ProgramInfo,
59 stack_outputs: StackOutputs,
60 trace_len_summary: TraceLenSummary,
61}
62
63impl ExecutionTrace {
64 pub const NUM_RAND_ROWS: usize = NUM_RAND_ROWS;
69
70 pub fn new(process: Process, stack_outputs: StackOutputs) -> Self {
74 let program_hash = process.decoder.program_hash();
79 let rng = RpoRandomCoin::new(program_hash);
80
81 let kernel = process.kernel().clone();
83 let program_info = ProgramInfo::new(program_hash.into(), kernel);
84 let (main_trace, aux_trace_builders, trace_len_summary) = finalize_trace(process, rng);
85 let trace_info = TraceInfo::new_multi_segment(
86 PADDED_TRACE_WIDTH,
87 AUX_TRACE_WIDTH,
88 AUX_TRACE_RAND_ELEMENTS,
89 main_trace.num_rows(),
90 vec![],
91 );
92
93 Self {
94 meta: Vec::new(),
95 trace_info,
96 aux_trace_builders,
97 main_trace,
98 program_info,
99 stack_outputs,
100 trace_len_summary,
101 }
102 }
103
104 pub fn program_info(&self) -> &ProgramInfo {
109 &self.program_info
110 }
111
112 pub fn program_hash(&self) -> &Digest {
114 self.program_info.program_hash()
115 }
116
117 pub fn stack_outputs(&self) -> &StackOutputs {
119 &self.stack_outputs
120 }
121
122 pub fn init_stack_state(&self) -> StackInputs {
124 let mut result = [ZERO; MIN_STACK_DEPTH];
125 for (i, result) in result.iter_mut().enumerate() {
126 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[0];
127 }
128 result.into()
129 }
130
131 pub fn last_stack_state(&self) -> StackOutputs {
133 let last_step = self.last_step();
134 let mut result = [ZERO; MIN_STACK_DEPTH];
135 for (i, result) in result.iter_mut().enumerate() {
136 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[last_step];
137 }
138 result.into()
139 }
140
141 pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
143 let mut result = [ZERO; NUM_USER_OP_HELPERS];
144 for (i, result) in result.iter_mut().enumerate() {
145 *result = self.main_trace.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i)
146 [clk as usize];
147 }
148 result
149 }
150
151 pub fn get_trace_len(&self) -> usize {
153 self.main_trace.num_rows()
154 }
155
156 pub fn trace_len_summary(&self) -> &TraceLenSummary {
158 &self.trace_len_summary
159 }
160
161 pub fn meta(&self) -> &[u8] {
163 &self.meta
164 }
165
166 fn last_step(&self) -> usize {
171 self.length() - NUM_RAND_ROWS - 1
172 }
173
174 #[cfg(feature = "std")]
177 #[allow(dead_code)]
178 pub fn print(&self) {
179 let mut row = [ZERO; PADDED_TRACE_WIDTH];
180 for i in 0..self.length() {
181 self.main_trace.read_row_into(i, &mut row);
182 std::println!(
183 "{:?}",
184 row.iter().take(TRACE_WIDTH).map(|v| v.as_int()).collect::<Vec<_>>()
185 );
186 }
187 }
188
189 #[cfg(test)]
190 pub fn test_finalize_trace(process: Process) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) {
191 let rng = RpoRandomCoin::new(EMPTY_WORD);
192 finalize_trace(process, rng)
193 }
194
195 pub fn build_aux_trace<E>(&self, rand_elements: &[E]) -> Option<ColMatrix<E>>
196 where
197 E: FieldElement<BaseField = Felt>,
198 {
199 let decoder_aux_columns = self
201 .aux_trace_builders
202 .decoder
203 .build_aux_columns(&self.main_trace, rand_elements);
204
205 let stack_aux_columns =
207 self.aux_trace_builders.stack.build_aux_columns(&self.main_trace, rand_elements);
208
209 let range_aux_columns =
211 self.aux_trace_builders.range.build_aux_columns(&self.main_trace, rand_elements);
212
213 let chiplets = self
215 .aux_trace_builders
216 .chiplets
217 .build_aux_columns(&self.main_trace, rand_elements);
218
219 let mut aux_columns = decoder_aux_columns
221 .into_iter()
222 .chain(stack_aux_columns)
223 .chain(range_aux_columns)
224 .chain(chiplets)
225 .collect::<Vec<_>>();
226
227 let mut rng = RpoRandomCoin::new(self.program_hash().into());
229 for i in self.length() - NUM_RAND_ROWS..self.length() {
230 for column in aux_columns.iter_mut() {
231 column[i] = rng.draw().expect("failed to draw a random value");
232 }
233 }
234
235 Some(ColMatrix::new(aux_columns))
236 }
237}
238
239impl Trace for ExecutionTrace {
243 type BaseField = Felt;
244
245 fn length(&self) -> usize {
246 self.main_trace.num_rows()
247 }
248
249 fn main_segment(&self) -> &ColMatrix<Felt> {
250 &self.main_trace
251 }
252
253 fn read_main_frame(&self, row_idx: usize, frame: &mut EvaluationFrame<Felt>) {
254 let next_row_idx = (row_idx + 1) % self.length();
255 self.main_trace.read_row_into(row_idx, frame.current_mut());
256 self.main_trace.read_row_into(next_row_idx, frame.next_mut());
257 }
258
259 fn info(&self) -> &TraceInfo {
260 &self.trace_info
261 }
262}
263
264fn finalize_trace(
276 process: Process,
277 mut rng: RpoRandomCoin,
278) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) {
279 let (system, decoder, stack, mut range, chiplets) = process.into_parts();
280
281 let clk = system.clk();
282
283 assert_eq!(clk.as_usize(), system.trace_len(), "inconsistent system trace lengths");
285 assert_eq!(clk.as_usize(), decoder.trace_len(), "inconsistent decoder trace length");
286 assert_eq!(clk.as_usize(), stack.trace_len(), "inconsistent stack trace lengths");
287
288 chiplets.append_range_checks(&mut range);
290
291 let range_table_len = range.get_number_range_checker_rows();
293
294 let max_len = range_table_len.max(clk.into()).max(chiplets.trace_len());
296
297 let trace_len = (max_len + NUM_RAND_ROWS).next_power_of_two();
300 assert!(
301 trace_len >= MIN_TRACE_LEN,
302 "trace length must be at least {MIN_TRACE_LEN}, but was {trace_len}",
303 );
304
305 let trace_len_summary =
307 TraceLenSummary::new(clk.into(), range_table_len, ChipletsLengths::new(&chiplets));
308
309 let system_trace = system.into_trace(trace_len, NUM_RAND_ROWS);
311 let decoder_trace = decoder.into_trace(trace_len, NUM_RAND_ROWS);
312 let stack_trace = stack.into_trace(trace_len, NUM_RAND_ROWS);
313 let chiplets_trace = chiplets.into_trace(trace_len, NUM_RAND_ROWS);
314
315 let range_check_trace = range.into_trace_with_table(range_table_len, trace_len, NUM_RAND_ROWS);
317
318 let padding = vec![vec![ZERO; trace_len]; PADDED_TRACE_WIDTH - TRACE_WIDTH];
320
321 let mut trace = system_trace
322 .into_iter()
323 .chain(decoder_trace.trace)
324 .chain(stack_trace.trace)
325 .chain(range_check_trace.trace)
326 .chain(chiplets_trace.trace)
327 .chain(padding)
328 .collect::<Vec<_>>();
329
330 for i in trace_len - NUM_RAND_ROWS..trace_len {
332 for column in trace.iter_mut().take(TRACE_WIDTH) {
333 column[i] = rng.draw().expect("failed to draw a random value");
334 }
335 }
336
337 let aux_trace_hints = AuxTraceBuilders {
338 decoder: decoder_trace.aux_builder,
339 stack: StackAuxTraceBuilder,
340 range: range_check_trace.aux_builder,
341 chiplets: chiplets_trace.aux_builder,
342 };
343
344 let main_trace = MainTrace::new(ColMatrix::new(trace), clk);
345
346 (main_trace, aux_trace_hints, trace_len_summary)
347}