1use alloc::vec::Vec;
2#[cfg(any(test, feature = "testing"))]
3use core::ops::Range;
4
5use miden_air::{
6 AirWitness, ProcessorAir, PublicInputs, debug,
7 trace::{
8 DECODER_TRACE_OFFSET, MainTrace, TRACE_WIDTH,
9 decoder::{NUM_USER_OP_HELPERS, USER_OP_HELPERS_OFFSET},
10 },
11};
12use miden_core::{crypto::hash::Blake3_256, serde::Serializable};
13
14use crate::{
15 Felt, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs, Word, ZERO,
16 fast::ExecutionOutput,
17 field::QuadFelt,
18 precompile::{PrecompileRequest, PrecompileTranscript, PrecompileTranscriptDigest},
19 utils::{Matrix, RowMajorMatrix},
20};
21
22pub(crate) mod utils;
23use utils::TraceFragment;
24
25pub mod chiplets;
26pub(crate) mod execution_tracer;
27
28mod block_stack;
29mod parallel;
30mod range;
31mod stack;
32mod trace_state;
33
34#[cfg(test)]
35mod tests;
36
37pub use execution_tracer::TraceGenerationContext;
41pub use miden_air::trace::RowIndex;
42pub use parallel::{CORE_TRACE_WIDTH, build_trace, build_trace_with_max_len};
43pub use utils::{ChipletsLengths, TraceLenSummary};
44
45#[derive(Debug)]
47pub struct TraceBuildInputs {
48 trace_output: TraceBuildOutput,
49 trace_generation_context: TraceGenerationContext,
50 program_info: ProgramInfo,
51}
52
53#[derive(Debug)]
54pub(crate) struct TraceBuildOutput {
55 stack_outputs: StackOutputs,
56 final_precompile_transcript: PrecompileTranscript,
57 precompile_requests: Vec<PrecompileRequest>,
58 precompile_requests_digest: [u8; 32],
59}
60
61impl TraceBuildOutput {
62 fn from_execution_output(execution_output: ExecutionOutput) -> Self {
63 let ExecutionOutput {
64 stack,
65 mut advice,
66 memory: _,
67 final_precompile_transcript,
68 } = execution_output;
69
70 Self {
71 stack_outputs: stack,
72 final_precompile_transcript,
73 precompile_requests: advice.take_precompile_requests(),
74 precompile_requests_digest: [0; 32],
75 }
76 .with_precompile_requests_digest()
77 }
78
79 fn with_precompile_requests_digest(mut self) -> Self {
80 self.precompile_requests_digest =
81 Blake3_256::hash(&self.precompile_requests.to_bytes()).into();
82 self
83 }
84
85 fn has_matching_precompile_requests_digest(&self) -> bool {
86 let expected_digest: [u8; 32] =
87 Blake3_256::hash(&self.precompile_requests.to_bytes()).into();
88 self.precompile_requests_digest == expected_digest
89 }
90}
91
92impl TraceBuildInputs {
93 pub(crate) fn from_execution(
94 program: &Program,
95 execution_output: ExecutionOutput,
96 trace_generation_context: TraceGenerationContext,
97 ) -> Self {
98 let trace_output = TraceBuildOutput::from_execution_output(execution_output);
99 let program_info = program.to_info();
100 Self {
101 trace_output,
102 trace_generation_context,
103 program_info,
104 }
105 }
106
107 pub fn stack_outputs(&self) -> &StackOutputs {
109 &self.trace_output.stack_outputs
110 }
111
112 pub fn precompile_requests(&self) -> &[PrecompileRequest] {
114 &self.trace_output.precompile_requests
115 }
116
117 pub fn final_precompile_transcript(&self) -> &PrecompileTranscript {
119 &self.trace_output.final_precompile_transcript
120 }
121
122 pub fn precompile_transcript_digest(&self) -> PrecompileTranscriptDigest {
124 self.final_precompile_transcript().finalize()
125 }
126
127 pub fn program_info(&self) -> &ProgramInfo {
129 &self.program_info
130 }
131
132 #[cfg(any(test, feature = "testing"))]
134 #[cfg_attr(all(feature = "testing", not(test)), expect(dead_code))]
135 pub(crate) fn into_parts(self) -> (TraceBuildOutput, TraceGenerationContext, ProgramInfo) {
136 (self.trace_output, self.trace_generation_context, self.program_info)
137 }
138
139 #[cfg(any(test, feature = "testing"))]
140 pub fn trace_generation_context(&self) -> &TraceGenerationContext {
142 &self.trace_generation_context
143 }
144
145 #[cfg(any(test, feature = "testing"))]
147 #[cfg_attr(all(feature = "testing", not(test)), expect(dead_code))]
148 pub(crate) fn trace_generation_context_mut(&mut self) -> &mut TraceGenerationContext {
149 &mut self.trace_generation_context
150 }
151
152 #[cfg(test)]
153 pub(crate) fn from_parts(
154 trace_output: TraceBuildOutput,
155 trace_generation_context: TraceGenerationContext,
156 program_info: ProgramInfo,
157 ) -> Self {
158 Self {
159 trace_output,
160 trace_generation_context,
161 program_info,
162 }
163 }
164}
165
166#[derive(Debug)]
178pub struct ExecutionTrace {
179 main_trace: MainTrace,
180 program_info: ProgramInfo,
181 stack_outputs: StackOutputs,
182 precompile_requests: Vec<PrecompileRequest>,
183 final_precompile_transcript: PrecompileTranscript,
184 trace_len_summary: TraceLenSummary,
185}
186
187impl ExecutionTrace {
188 pub(crate) fn new_from_parts(
192 program_info: ProgramInfo,
193 trace_output: TraceBuildOutput,
194 main_trace: MainTrace,
195 trace_len_summary: TraceLenSummary,
196 ) -> Self {
197 let TraceBuildOutput {
198 stack_outputs,
199 final_precompile_transcript,
200 precompile_requests,
201 ..
202 } = trace_output;
203
204 Self {
205 main_trace,
206 program_info,
207 stack_outputs,
208 precompile_requests,
209 final_precompile_transcript,
210 trace_len_summary,
211 }
212 }
213
214 pub fn program_info(&self) -> &ProgramInfo {
219 &self.program_info
220 }
221
222 pub fn program_hash(&self) -> &Word {
224 self.program_info.program_hash()
225 }
226
227 pub fn stack_outputs(&self) -> &StackOutputs {
229 &self.stack_outputs
230 }
231
232 pub fn public_inputs(&self) -> PublicInputs {
234 PublicInputs::new(
235 self.program_info.clone(),
236 self.init_stack_state(),
237 self.stack_outputs,
238 self.final_precompile_transcript.state(),
239 )
240 }
241
242 pub fn to_public_values(&self) -> Vec<Felt> {
244 self.public_inputs().to_elements()
245 }
246
247 pub fn main_trace(&self) -> &MainTrace {
249 &self.main_trace
250 }
251
252 pub fn main_trace_mut(&mut self) -> &mut MainTrace {
254 &mut self.main_trace
255 }
256
257 pub fn precompile_requests(&self) -> &[PrecompileRequest] {
259 &self.precompile_requests
260 }
261
262 pub fn final_precompile_transcript(&self) -> PrecompileTranscript {
264 self.final_precompile_transcript
265 }
266
267 pub fn precompile_transcript_digest(&self) -> PrecompileTranscriptDigest {
269 self.final_precompile_transcript().finalize()
270 }
271
272 pub fn into_outputs(self) -> (StackOutputs, Vec<PrecompileRequest>, PrecompileTranscript) {
274 (self.stack_outputs, self.precompile_requests, self.final_precompile_transcript)
275 }
276
277 pub fn init_stack_state(&self) -> StackInputs {
279 let mut result = [ZERO; MIN_STACK_DEPTH];
280 let row = RowIndex::from(0_u32);
281 for (i, result) in result.iter_mut().enumerate() {
282 *result = self.main_trace.stack_element(i, row);
283 }
284 result.into()
285 }
286
287 pub fn last_stack_state(&self) -> StackOutputs {
289 let last_step = RowIndex::from(self.last_step());
290 let mut result = [ZERO; MIN_STACK_DEPTH];
291 for (i, result) in result.iter_mut().enumerate() {
292 *result = self.main_trace.stack_element(i, last_step);
293 }
294 result.into()
295 }
296
297 pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
299 let mut result = [ZERO; NUM_USER_OP_HELPERS];
300 let row = RowIndex::from(clk);
301 for (i, result) in result.iter_mut().enumerate() {
302 *result = self.main_trace.get(row, DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i);
303 }
304 result
305 }
306
307 pub fn get_trace_len(&self) -> usize {
309 self.main_trace.num_rows()
310 }
311
312 pub fn length(&self) -> usize {
314 self.get_trace_len()
315 }
316
317 pub fn trace_len_summary(&self) -> &TraceLenSummary {
319 &self.trace_len_summary
320 }
321
322 pub fn check_constraints(&self) {
336 let public_inputs = self.public_inputs();
337 let trace_matrix = self.to_row_major_matrix();
338
339 let (public_values, kernel_felts) = public_inputs.to_air_inputs();
340 let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts];
341
342 let digest = crate::crypto::hash::Poseidon2::hash_elements(&public_values);
345 let challenges =
346 [QuadFelt::new([digest[0], digest[1]]), QuadFelt::new([digest[2], digest[3]])];
347
348 let witness = AirWitness::new(&trace_matrix, &public_values, var_len_public_inputs);
349 debug::check_constraints(&ProcessorAir, witness, &ProcessorAir, &challenges);
350 }
351
352 pub fn to_row_major_matrix(&self) -> RowMajorMatrix<Felt> {
354 let row_major = self.main_trace.to_row_major();
355 debug_assert_eq!(row_major.width(), TRACE_WIDTH);
356 row_major
357 }
358
359 fn last_step(&self) -> usize {
364 self.length() - 1
365 }
366
367 #[cfg(feature = "std")]
370 pub fn print(&self) {
371 let mut row = [ZERO; TRACE_WIDTH];
372 for i in 0..self.length() {
373 self.main_trace.read_row_into(i, &mut row);
374 std::println!("{:?}", row.map(|v| v.as_canonical_u64()));
375 }
376 }
377
378 #[cfg(any(test, feature = "testing"))]
379 pub fn get_column_range(&self, range: Range<usize>) -> Vec<Vec<Felt>> {
380 self.main_trace.get_column_range(range)
381 }
382}