1#![no_std]
2#![expect(dead_code)]
3
4#[macro_use]
5extern crate alloc;
6
7#[cfg(feature = "std")]
8extern crate std;
9
10use alloc::{borrow::ToOwned, vec::Vec};
11
12use miden_core::{
13 ExtensionOf, ONE, ProgramInfo, StackInputs, StackOutputs, Word, ZERO,
14 precompile::PrecompileTranscriptState,
15 utils::{ByteReader, ByteWriter, Deserializable, Serializable},
16};
17use winter_air::{
18 Air, AirContext, Assertion, EvaluationFrame, ProofOptions as WinterProofOptions, TraceInfo,
19 TransitionConstraintDegree,
20};
21use winter_prover::{
22 crypto::{RandomCoin, RandomCoinError},
23 math::get_power_series,
24 matrix::ColMatrix,
25};
26
27mod constraints;
28pub use constraints::stack;
29use constraints::{chiplets, range};
30
31pub mod trace;
32pub use trace::rows::RowIndex;
33use trace::*;
34
35mod errors;
36mod options;
37mod proof;
38
39mod utils;
40
41pub use errors::ExecutionOptionsError;
45pub use miden_core::{
46 Felt, FieldElement, StarkField,
47 utils::{DeserializationError, ToElements},
48};
49pub use options::{ExecutionOptions, ProvingOptions};
50pub use proof::{ExecutionProof, HashFunction};
51use utils::TransitionConstraintRange;
52pub use winter_air::{AuxRandElements, FieldExtension, PartitionOptions};
53
54const IS_FULL_CONSTRAINT_SET: bool = false;
57
58pub struct ProcessorAir {
70 context: AirContext<Felt>,
71 stack_inputs: StackInputs,
72 stack_outputs: StackOutputs,
73 program_digest: Word,
74 kernel_digests: Vec<Word>,
75 pc_transcript_state: PrecompileTranscriptState,
76 constraint_ranges: TransitionConstraintRange,
77}
78
79impl ProcessorAir {
80 pub fn last_step(&self) -> usize {
82 self.trace_length() - self.context().num_transition_exemptions()
83 }
84}
85
86impl Air for ProcessorAir {
87 type BaseField = Felt;
88 type PublicInputs = PublicInputs;
89
90 fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: WinterProofOptions) -> Self {
91 let mut main_degrees = vec![
93 TransitionConstraintDegree::new(1), ];
95
96 if IS_FULL_CONSTRAINT_SET {
97 let mut stack_degrees = stack::get_transition_constraint_degrees();
100 main_degrees.append(&mut stack_degrees);
101
102 let mut range_checker_degrees = range::get_transition_constraint_degrees();
105 main_degrees.append(&mut range_checker_degrees);
106
107 let mut chiplets_degrees = chiplets::get_transition_constraint_degrees();
109 main_degrees.append(&mut chiplets_degrees);
110 }
111
112 let aux_degrees = range::get_aux_transition_constraint_degrees();
113
114 let constraint_ranges = TransitionConstraintRange::new(
116 1,
117 stack::get_transition_constraint_count(),
118 range::get_transition_constraint_count(),
119 chiplets::get_transition_constraint_count(),
120 );
121
122 let num_main_assertions = if IS_FULL_CONSTRAINT_SET {
125 2 + stack::NUM_ASSERTIONS + range::NUM_ASSERTIONS
126 } else {
127 1
128 };
129
130 let num_aux_assertions = if IS_FULL_CONSTRAINT_SET {
133 stack::NUM_AUX_ASSERTIONS + range::NUM_AUX_ASSERTIONS + 1
134 } else {
135 3 + 1 };
137
138 let context = AirContext::new_multi_segment(
141 trace_info,
142 main_degrees,
143 aux_degrees,
144 num_main_assertions,
145 num_aux_assertions,
146 options,
147 )
148 .set_num_transition_exemptions(2);
149
150 Self {
151 context,
152 stack_inputs: pub_inputs.stack_inputs,
153 stack_outputs: pub_inputs.stack_outputs,
154 constraint_ranges,
155 program_digest: pub_inputs.program_info.program_hash().to_owned(),
156 kernel_digests: pub_inputs.program_info.kernel_procedures().to_owned(),
157 pc_transcript_state: pub_inputs.pc_transcript_state,
158 }
159 }
160
161 fn get_periodic_column_values(&self) -> Vec<Vec<Felt>> {
166 chiplets::get_periodic_column_values()
167 }
168
169 fn get_assertions(&self) -> Vec<Assertion<Felt>> {
173 let mut result = vec![Assertion::single(CLK_COL_IDX, 0, ZERO)];
176
177 if IS_FULL_CONSTRAINT_SET {
178 stack::get_assertions_first_step(&mut result, &*self.stack_inputs);
180
181 range::get_assertions_first_step(&mut result);
183
184 let last_step = self.last_step();
187
188 stack::get_assertions_last_step(&mut result, last_step, &self.stack_outputs);
190
191 range::get_assertions_last_step(&mut result, last_step);
193 }
194
195 result
196 }
197
198 fn get_aux_assertions<E: FieldElement<BaseField = Self::BaseField>>(
199 &self,
200 aux_rand_elements: &AuxRandElements<E>,
201 ) -> Vec<Assertion<E>> {
202 let mut result: Vec<Assertion<E>> = Vec::new();
203
204 range::get_aux_assertions_first_step::<E>(&mut result);
206
207 chiplets::get_aux_assertions_first_step::<E>(
209 &mut result,
210 &self.kernel_digests,
211 aux_rand_elements,
212 self.pc_transcript_state,
213 );
214
215 if IS_FULL_CONSTRAINT_SET {
217 stack::get_aux_assertions_first_step(&mut result);
219
220 let last_step = self.last_step();
223
224 stack::get_aux_assertions_last_step(&mut result, last_step);
226 }
227 let last_step = self.last_step();
229 range::get_aux_assertions_last_step::<E>(&mut result, last_step);
230
231 result
232 }
233
234 fn evaluate_transition<E: FieldElement<BaseField = Felt>>(
238 &self,
239 frame: &EvaluationFrame<E>,
240 periodic_values: &[E],
241 result: &mut [E],
242 ) {
243 let current = frame.current();
244 let next = frame.next();
245
246 result[0] = next[CLK_COL_IDX] - (current[CLK_COL_IDX] + E::ONE);
249
250 if IS_FULL_CONSTRAINT_SET {
251 stack::enforce_constraints::<E>(
254 frame,
255 select_result_range!(result, self.constraint_ranges.stack),
256 );
257
258 range::enforce_constraints::<E>(
261 frame,
262 select_result_range!(result, self.constraint_ranges.range_checker),
263 );
264
265 chiplets::enforce_constraints::<E>(
267 frame,
268 periodic_values,
269 select_result_range!(result, self.constraint_ranges.chiplets),
270 );
271 }
272 }
273
274 fn evaluate_aux_transition<F, E>(
275 &self,
276 main_frame: &EvaluationFrame<F>,
277 aux_frame: &EvaluationFrame<E>,
278 _periodic_values: &[F],
279 aux_rand_elements: &AuxRandElements<E>,
280 result: &mut [E],
281 ) where
282 F: FieldElement<BaseField = Felt>,
283 E: FieldElement<BaseField = Felt> + ExtensionOf<F>,
284 {
285 range::enforce_aux_constraints::<F, E>(
287 main_frame,
288 aux_frame,
289 aux_rand_elements.rand_elements(),
290 result,
291 );
292 }
293
294 fn context(&self) -> &AirContext<Felt> {
295 &self.context
296 }
297
298 fn get_aux_rand_elements<E, R>(
299 &self,
300 public_coin: &mut R,
301 ) -> Result<AuxRandElements<E>, RandomCoinError>
302 where
303 E: FieldElement<BaseField = Self::BaseField>,
304 R: RandomCoin<BaseField = Self::BaseField>,
305 {
306 let num_elements = self.trace_info().get_num_aux_segment_rand_elements();
307 let mut rand_elements = Vec::with_capacity(num_elements);
308 let max_message_length = num_elements - 1;
309
310 let alpha = public_coin.draw()?;
311 let beta = public_coin.draw()?;
312
313 let betas = get_power_series(beta, max_message_length);
314
315 rand_elements.push(alpha);
316 rand_elements.extend_from_slice(&betas);
317
318 Ok(AuxRandElements::new(rand_elements))
319 }
320}
321
322#[derive(Debug)]
326pub struct PublicInputs {
327 program_info: ProgramInfo,
328 stack_inputs: StackInputs,
329 stack_outputs: StackOutputs,
330 pc_transcript_state: PrecompileTranscriptState,
331}
332
333impl PublicInputs {
334 pub fn new(
337 program_info: ProgramInfo,
338 stack_inputs: StackInputs,
339 stack_outputs: StackOutputs,
340 pc_transcript_state: PrecompileTranscriptState,
341 ) -> Self {
342 Self {
343 program_info,
344 stack_inputs,
345 stack_outputs,
346 pc_transcript_state,
347 }
348 }
349}
350
351impl miden_core::ToElements<Felt> for PublicInputs {
352 fn to_elements(&self) -> Vec<Felt> {
353 let mut result = self.stack_inputs.to_vec();
354 result.append(&mut self.stack_outputs.to_vec());
355 result.append(&mut self.program_info.to_elements());
356 let pc_state: [Felt; 4] = self.pc_transcript_state.into();
357 result.extend_from_slice(&pc_state);
358 result
359 }
360}
361
362impl Serializable for PublicInputs {
366 fn write_into<W: ByteWriter>(&self, target: &mut W) {
367 self.program_info.write_into(target);
368 self.stack_inputs.write_into(target);
369 self.stack_outputs.write_into(target);
370 self.pc_transcript_state.write_into(target);
371 }
372}
373
374impl Deserializable for PublicInputs {
375 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
376 let program_info = ProgramInfo::read_from(source)?;
377 let stack_inputs = StackInputs::read_from(source)?;
378 let stack_outputs = StackOutputs::read_from(source)?;
379 let pc_transcript_state = Word::read_from(source)?;
380
381 Ok(PublicInputs {
382 program_info,
383 stack_inputs,
384 stack_outputs,
385 pc_transcript_state,
386 })
387 }
388}