1use alloc::vec::Vec;
2#[cfg(any(test, feature = "testing"))]
3use core::ops::Range;
4
5use miden_air::{
6 MidenMultiAir, ProverStatement, PublicInputs, StarkConfig, Statement, config, debug,
7 trace::{MainTrace, decoder::NUM_USER_OP_HELPERS},
8};
9use miden_core::{crypto::hash::Blake3_256, serde::Serializable};
10
11use crate::{
12 Felt, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs, Word, ZERO,
13 fast::ExecutionOutput,
14 field::QuadFelt,
15 precompile::{PrecompileRequest, PrecompileTranscript},
16 utils::RowMajorMatrix,
17};
18
19pub(crate) mod utils;
20use utils::ChipletTraceFragment;
21
22pub mod chiplets;
23pub(crate) mod execution_tracer;
24
25mod block_stack;
26mod parallel;
27mod range;
28mod stack;
29mod trace_state;
30
31#[cfg(test)]
32mod tests;
33
34pub use execution_tracer::TraceGenerationContext;
38pub use miden_air::trace::RowIndex;
39pub use parallel::{CORE_TRACE_WIDTH, build_trace, build_trace_with_max_len};
40pub use utils::{ChipletsLengths, TraceLenSummary};
41
42#[derive(Debug)]
44pub struct TraceBuildInputs {
45 trace_output: TraceBuildOutput,
46 trace_generation_context: TraceGenerationContext,
47 program_info: ProgramInfo,
48}
49
50#[derive(Debug)]
51pub(crate) struct TraceBuildOutput {
52 stack_outputs: StackOutputs,
53 final_precompile_transcript: PrecompileTranscript,
54 precompile_requests: Vec<PrecompileRequest>,
55 precompile_requests_digest: [u8; 32],
56}
57
58impl TraceBuildOutput {
59 fn from_execution_output(execution_output: ExecutionOutput) -> Self {
60 let ExecutionOutput {
61 stack,
62 mut advice,
63 memory: _,
64 final_precompile_transcript,
65 } = execution_output;
66
67 Self {
68 stack_outputs: stack,
69 final_precompile_transcript,
70 precompile_requests: advice.take_precompile_requests(),
71 precompile_requests_digest: [0; 32],
72 }
73 .with_precompile_requests_digest()
74 }
75
76 fn with_precompile_requests_digest(mut self) -> Self {
77 self.precompile_requests_digest =
78 Blake3_256::hash(&self.precompile_requests.to_bytes()).into();
79 self
80 }
81
82 fn has_matching_precompile_requests_digest(&self) -> bool {
83 let expected_digest: [u8; 32] =
84 Blake3_256::hash(&self.precompile_requests.to_bytes()).into();
85 self.precompile_requests_digest == expected_digest
86 }
87}
88
89impl TraceBuildInputs {
90 pub(crate) fn from_execution(
91 program: &Program,
92 execution_output: ExecutionOutput,
93 trace_generation_context: TraceGenerationContext,
94 ) -> Self {
95 let trace_output = TraceBuildOutput::from_execution_output(execution_output);
96 let program_info = program.to_info();
97 Self {
98 trace_output,
99 trace_generation_context,
100 program_info,
101 }
102 }
103
104 pub fn stack_outputs(&self) -> &StackOutputs {
106 &self.trace_output.stack_outputs
107 }
108
109 pub fn precompile_requests(&self) -> &[PrecompileRequest] {
111 &self.trace_output.precompile_requests
112 }
113
114 pub fn final_precompile_transcript(&self) -> &PrecompileTranscript {
116 &self.trace_output.final_precompile_transcript
117 }
118
119 pub fn program_info(&self) -> &ProgramInfo {
121 &self.program_info
122 }
123
124 #[cfg(any(test, feature = "testing"))]
126 #[cfg_attr(all(feature = "testing", not(test)), expect(dead_code))]
127 pub(crate) fn into_parts(self) -> (TraceBuildOutput, TraceGenerationContext, ProgramInfo) {
128 (self.trace_output, self.trace_generation_context, self.program_info)
129 }
130
131 #[cfg(any(test, feature = "testing"))]
132 pub fn trace_generation_context(&self) -> &TraceGenerationContext {
134 &self.trace_generation_context
135 }
136
137 #[cfg(any(test, feature = "testing"))]
139 #[cfg_attr(all(feature = "testing", not(test)), expect(dead_code))]
140 pub(crate) fn trace_generation_context_mut(&mut self) -> &mut TraceGenerationContext {
141 &mut self.trace_generation_context
142 }
143
144 #[cfg(test)]
145 pub(crate) fn from_parts(
146 trace_output: TraceBuildOutput,
147 trace_generation_context: TraceGenerationContext,
148 program_info: ProgramInfo,
149 ) -> Self {
150 Self {
151 trace_output,
152 trace_generation_context,
153 program_info,
154 }
155 }
156}
157
158#[derive(Debug)]
170pub struct ExecutionTrace {
171 main_trace: MainTrace,
172 program_info: ProgramInfo,
173 stack_outputs: StackOutputs,
174 precompile_requests: Vec<PrecompileRequest>,
175 final_precompile_transcript: PrecompileTranscript,
176 trace_len_summary: TraceLenSummary,
177}
178
179impl ExecutionTrace {
180 pub(crate) fn new_from_parts(
184 program_info: ProgramInfo,
185 trace_output: TraceBuildOutput,
186 main_trace: MainTrace,
187 trace_len_summary: TraceLenSummary,
188 ) -> Self {
189 let TraceBuildOutput {
190 stack_outputs,
191 final_precompile_transcript,
192 precompile_requests,
193 ..
194 } = trace_output;
195
196 Self {
197 main_trace,
198 program_info,
199 stack_outputs,
200 precompile_requests,
201 final_precompile_transcript,
202 trace_len_summary,
203 }
204 }
205
206 pub fn program_info(&self) -> &ProgramInfo {
211 &self.program_info
212 }
213
214 pub fn program_hash(&self) -> &Word {
216 self.program_info.program_hash()
217 }
218
219 pub fn stack_outputs(&self) -> &StackOutputs {
221 &self.stack_outputs
222 }
223
224 pub fn public_inputs(&self) -> PublicInputs {
226 PublicInputs::new(
227 self.program_info.clone(),
228 self.init_stack_state(),
229 self.stack_outputs,
230 self.final_precompile_transcript.state(),
231 )
232 }
233
234 pub fn to_public_values(&self) -> Vec<Felt> {
236 self.public_inputs().to_elements()
237 }
238
239 pub fn main_trace(&self) -> &MainTrace {
241 &self.main_trace
242 }
243
244 pub fn main_trace_mut(&mut self) -> &mut MainTrace {
246 &mut self.main_trace
247 }
248
249 pub fn precompile_requests(&self) -> &[PrecompileRequest] {
251 &self.precompile_requests
252 }
253
254 pub fn final_precompile_transcript(&self) -> PrecompileTranscript {
256 self.final_precompile_transcript
257 }
258
259 pub fn into_outputs(self) -> (StackOutputs, Vec<PrecompileRequest>, PrecompileTranscript) {
261 (self.stack_outputs, self.precompile_requests, self.final_precompile_transcript)
262 }
263
264 pub fn init_stack_state(&self) -> StackInputs {
266 let mut result = [ZERO; MIN_STACK_DEPTH];
267 let row = RowIndex::from(0_u32);
268 for (i, result) in result.iter_mut().enumerate() {
269 *result = self.main_trace.stack_element(i, row);
270 }
271 result.into()
272 }
273
274 pub fn last_stack_state(&self) -> StackOutputs {
276 let last_step = RowIndex::from(self.last_step());
277 let mut result = [ZERO; MIN_STACK_DEPTH];
278 for (i, result) in result.iter_mut().enumerate() {
279 *result = self.main_trace.stack_element(i, last_step);
280 }
281 result.into()
282 }
283
284 pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
286 let mut result = [ZERO; NUM_USER_OP_HELPERS];
287 let row = RowIndex::from(clk);
288 for (i, result) in result.iter_mut().enumerate() {
289 *result = self.main_trace.helper_register(i, row);
290 }
291 result
292 }
293
294 pub fn get_trace_len(&self) -> usize {
296 self.main_trace.num_rows()
297 }
298
299 pub fn length(&self) -> usize {
301 self.get_trace_len()
302 }
303
304 pub fn trace_len_summary(&self) -> &TraceLenSummary {
306 &self.trace_len_summary
307 }
308
309 pub fn check_constraints(&self) {
323 let public_inputs = self.public_inputs();
324 let (core_matrix, chiplets_matrix) = self.main_trace.to_core_chiplets_matrices();
325
326 let (public_values, kernel_felts) = public_inputs.to_air_inputs();
327
328 let statement =
329 Statement::<Felt, QuadFelt, _>::new(MidenMultiAir::new(), public_values, kernel_felts)
330 .expect("valid statement inputs");
331 let prover_statement = ProverStatement::new(statement, vec![core_matrix, chiplets_matrix])
332 .expect("valid trace shapes");
333
334 let config = config::poseidon2_config(config::pcs_params());
337 debug::check_constraints(&prover_statement, config.challenger());
338 }
339
340 pub fn to_core_chiplets_matrices(&self) -> (RowMajorMatrix<Felt>, RowMajorMatrix<Felt>) {
344 self.main_trace.to_core_chiplets_matrices()
345 }
346
347 pub fn into_core_chiplets_matrices(self) -> (RowMajorMatrix<Felt>, RowMajorMatrix<Felt>) {
350 self.main_trace.into_core_chiplets_matrices()
351 }
352
353 fn last_step(&self) -> usize {
358 self.main_trace.core_height() - 1
359 }
360
361 #[cfg(any(test, feature = "testing"))]
362 pub fn get_column_range(&self, range: Range<usize>) -> Vec<Vec<Felt>> {
363 self.main_trace.get_column_range(range)
364 }
365}