1use alloc::vec::Vec;
2
3use miden_air::trace::{
4 decoder::{NUM_USER_OP_HELPERS, USER_OP_HELPERS_OFFSET},
5 main_trace::MainTrace,
6 AUX_TRACE_RAND_ELEMENTS, AUX_TRACE_WIDTH, DECODER_TRACE_OFFSET, MIN_TRACE_LEN,
7 STACK_TRACE_OFFSET, TRACE_WIDTH,
8};
9use vm_core::{stack::MIN_STACK_DEPTH, ProgramInfo, StackInputs, StackOutputs, ZERO};
10use winter_prover::{crypto::RandomCoin, EvaluationFrame, Trace, TraceInfo};
11
12use super::{
13 chiplets::AuxTraceBuilder as ChipletsAuxTraceBuilder, crypto::RpoRandomCoin,
14 decoder::AuxTraceBuilder as DecoderAuxTraceBuilder,
15 range::AuxTraceBuilder as RangeCheckerAuxTraceBuilder,
16 stack::AuxTraceBuilder as StackAuxTraceBuilder, ColMatrix, Digest, Felt, FieldElement, Process,
17};
18
19mod utils;
20pub use utils::{AuxColumnBuilder, ChipletsLengths, TraceFragment, TraceLenSummary};
21
22#[cfg(test)]
23mod tests;
24#[cfg(test)]
25use super::EMPTY_WORD;
26
27pub const NUM_RAND_ROWS: usize = 1;
32
33pub struct AuxTraceBuilders {
37 pub(crate) decoder: DecoderAuxTraceBuilder,
38 pub(crate) stack: StackAuxTraceBuilder,
39 pub(crate) range: RangeCheckerAuxTraceBuilder,
40 pub(crate) chiplets: ChipletsAuxTraceBuilder,
41}
42
43pub struct ExecutionTrace {
51 meta: Vec<u8>,
52 trace_info: TraceInfo,
53 main_trace: MainTrace,
54 aux_trace_builders: AuxTraceBuilders,
55 program_info: ProgramInfo,
56 stack_outputs: StackOutputs,
57 trace_len_summary: TraceLenSummary,
58}
59
60impl ExecutionTrace {
61 pub const NUM_RAND_ROWS: usize = NUM_RAND_ROWS;
66
67 pub fn new(process: Process, stack_outputs: StackOutputs) -> Self {
71 let program_hash = process.decoder.program_hash();
76 let rng = RpoRandomCoin::new(program_hash);
77
78 let kernel = process.kernel().clone();
80 let program_info = ProgramInfo::new(program_hash.into(), kernel);
81 let (main_trace, aux_trace_builders, trace_len_summary) = finalize_trace(process, rng);
82 let trace_info = TraceInfo::new_multi_segment(
83 TRACE_WIDTH,
84 AUX_TRACE_WIDTH,
85 AUX_TRACE_RAND_ELEMENTS,
86 main_trace.num_rows(),
87 vec![],
88 );
89
90 Self {
91 meta: Vec::new(),
92 trace_info,
93 aux_trace_builders,
94 main_trace,
95 program_info,
96 stack_outputs,
97 trace_len_summary,
98 }
99 }
100
101 pub fn program_info(&self) -> &ProgramInfo {
106 &self.program_info
107 }
108
109 pub fn program_hash(&self) -> &Digest {
111 self.program_info.program_hash()
112 }
113
114 pub fn stack_outputs(&self) -> &StackOutputs {
116 &self.stack_outputs
117 }
118
119 pub fn init_stack_state(&self) -> StackInputs {
121 let mut result = [ZERO; MIN_STACK_DEPTH];
122 for (i, result) in result.iter_mut().enumerate() {
123 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[0];
124 }
125 result.into()
126 }
127
128 pub fn last_stack_state(&self) -> StackOutputs {
130 let last_step = self.last_step();
131 let mut result = [ZERO; MIN_STACK_DEPTH];
132 for (i, result) in result.iter_mut().enumerate() {
133 *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[last_step];
134 }
135 result.into()
136 }
137
138 pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
140 let mut result = [ZERO; NUM_USER_OP_HELPERS];
141 for (i, result) in result.iter_mut().enumerate() {
142 *result = self.main_trace.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i)
143 [clk as usize];
144 }
145 result
146 }
147
148 pub fn get_trace_len(&self) -> usize {
150 self.main_trace.num_rows()
151 }
152
153 pub fn trace_len_summary(&self) -> &TraceLenSummary {
155 &self.trace_len_summary
156 }
157
158 pub fn meta(&self) -> &[u8] {
160 &self.meta
161 }
162
163 fn last_step(&self) -> usize {
168 self.length() - NUM_RAND_ROWS - 1
169 }
170
171 #[cfg(feature = "std")]
174 #[allow(dead_code)]
175 pub fn print(&self) {
176 let mut row = [ZERO; TRACE_WIDTH];
177 for i in 0..self.length() {
178 self.main_trace.read_row_into(i, &mut row);
179 std::println!("{:?}", row.iter().map(|v| v.as_int()).collect::<Vec<_>>());
180 }
181 }
182
183 #[cfg(test)]
184 pub fn test_finalize_trace(process: Process) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) {
185 let rng = RpoRandomCoin::new(EMPTY_WORD);
186 finalize_trace(process, rng)
187 }
188
189 pub fn build_aux_trace<E>(&self, rand_elements: &[E]) -> Option<ColMatrix<E>>
190 where
191 E: FieldElement<BaseField = Felt>,
192 {
193 let decoder_aux_columns = self
195 .aux_trace_builders
196 .decoder
197 .build_aux_columns(&self.main_trace, rand_elements);
198
199 let stack_aux_columns =
201 self.aux_trace_builders.stack.build_aux_columns(&self.main_trace, rand_elements);
202
203 let range_aux_columns =
205 self.aux_trace_builders.range.build_aux_columns(&self.main_trace, rand_elements);
206
207 let chiplets = self
209 .aux_trace_builders
210 .chiplets
211 .build_aux_columns(&self.main_trace, rand_elements);
212
213 let mut aux_columns = decoder_aux_columns
215 .into_iter()
216 .chain(stack_aux_columns)
217 .chain(range_aux_columns)
218 .chain(chiplets)
219 .collect::<Vec<_>>();
220
221 let mut rng = RpoRandomCoin::new(self.program_hash().into());
223 for i in self.length() - NUM_RAND_ROWS..self.length() {
224 for column in aux_columns.iter_mut() {
225 column[i] = rng.draw().expect("failed to draw a random value");
226 }
227 }
228
229 Some(ColMatrix::new(aux_columns))
230 }
231}
232
233impl Trace for ExecutionTrace {
237 type BaseField = Felt;
238
239 fn length(&self) -> usize {
240 self.main_trace.num_rows()
241 }
242
243 fn main_segment(&self) -> &ColMatrix<Felt> {
244 &self.main_trace
245 }
246
247 fn read_main_frame(&self, row_idx: usize, frame: &mut EvaluationFrame<Felt>) {
248 let next_row_idx = (row_idx + 1) % self.length();
249 self.main_trace.read_row_into(row_idx, frame.current_mut());
250 self.main_trace.read_row_into(next_row_idx, frame.next_mut());
251 }
252
253 fn info(&self) -> &TraceInfo {
254 &self.trace_info
255 }
256}
257
258fn finalize_trace(
270 process: Process,
271 mut rng: RpoRandomCoin,
272) -> (MainTrace, AuxTraceBuilders, TraceLenSummary) {
273 let (system, decoder, stack, mut range, chiplets) = process.into_parts();
274
275 let clk = system.clk();
276
277 assert_eq!(clk.as_usize(), system.trace_len(), "inconsistent system trace lengths");
279 assert_eq!(clk.as_usize(), decoder.trace_len(), "inconsistent decoder trace length");
280 assert_eq!(clk.as_usize(), stack.trace_len(), "inconsistent stack trace lengths");
281
282 chiplets.append_range_checks(&mut range);
284
285 let range_table_len = range.get_number_range_checker_rows();
287
288 let max_len = range_table_len.max(clk.into()).max(chiplets.trace_len());
290
291 let trace_len = (max_len + NUM_RAND_ROWS).next_power_of_two();
294 assert!(
295 trace_len >= MIN_TRACE_LEN,
296 "trace length must be at least {MIN_TRACE_LEN}, but was {trace_len}",
297 );
298
299 let trace_len_summary =
301 TraceLenSummary::new(clk.into(), range_table_len, ChipletsLengths::new(&chiplets));
302
303 let system_trace = system.into_trace(trace_len, NUM_RAND_ROWS);
305 let decoder_trace = decoder.into_trace(trace_len, NUM_RAND_ROWS);
306 let stack_trace = stack.into_trace(trace_len, NUM_RAND_ROWS);
307 let chiplets_trace = chiplets.into_trace(trace_len, NUM_RAND_ROWS);
308
309 let range_check_trace = range.into_trace_with_table(range_table_len, trace_len, NUM_RAND_ROWS);
311
312 let mut trace = system_trace
313 .into_iter()
314 .chain(decoder_trace.trace)
315 .chain(stack_trace.trace)
316 .chain(range_check_trace.trace)
317 .chain(chiplets_trace.trace)
318 .collect::<Vec<_>>();
319
320 for i in trace_len - NUM_RAND_ROWS..trace_len {
322 for column in trace.iter_mut() {
323 column[i] = rng.draw().expect("failed to draw a random value");
324 }
325 }
326
327 let aux_trace_hints = AuxTraceBuilders {
328 decoder: decoder_trace.aux_builder,
329 stack: StackAuxTraceBuilder,
330 range: range_check_trace.aux_builder,
331 chiplets: chiplets_trace.aux_builder,
332 };
333
334 let main_trace = MainTrace::new(ColMatrix::new(trace), clk);
335
336 (main_trace, aux_trace_hints, trace_len_summary)
337}