1#![no_std]
2#![allow(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 {
63 context: AirContext<Felt>,
64 stack_inputs: StackInputs,
65 stack_outputs: StackOutputs,
66 program_digest: Word,
67 kernel_digests: Vec<Word>,
68 pc_transcript_state: PrecompileTranscriptState,
69 constraint_ranges: TransitionConstraintRange,
70}
71
72impl ProcessorAir {
73 pub fn last_step(&self) -> usize {
75 self.trace_length() - self.context().num_transition_exemptions()
76 }
77}
78
79impl Air for ProcessorAir {
80 type BaseField = Felt;
81 type PublicInputs = PublicInputs;
82
83 fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: WinterProofOptions) -> Self {
84 let mut main_degrees = vec![
86 TransitionConstraintDegree::new(1), ];
88
89 if IS_FULL_CONSTRAINT_SET {
90 let mut stack_degrees = stack::get_transition_constraint_degrees();
93 main_degrees.append(&mut stack_degrees);
94
95 let mut range_checker_degrees = range::get_transition_constraint_degrees();
98 main_degrees.append(&mut range_checker_degrees);
99
100 let mut chiplets_degrees = chiplets::get_transition_constraint_degrees();
102 main_degrees.append(&mut chiplets_degrees);
103 }
104
105 let aux_degrees = range::get_aux_transition_constraint_degrees();
106
107 let constraint_ranges = TransitionConstraintRange::new(
109 1,
110 stack::get_transition_constraint_count(),
111 range::get_transition_constraint_count(),
112 chiplets::get_transition_constraint_count(),
113 );
114
115 let num_main_assertions = if IS_FULL_CONSTRAINT_SET {
118 2 + stack::NUM_ASSERTIONS + range::NUM_ASSERTIONS
119 } else {
120 1
121 };
122
123 let num_aux_assertions = if IS_FULL_CONSTRAINT_SET {
126 stack::NUM_AUX_ASSERTIONS + range::NUM_AUX_ASSERTIONS + 1
127 } else {
128 3 + 1 };
130
131 let context = AirContext::new_multi_segment(
134 trace_info,
135 main_degrees,
136 aux_degrees,
137 num_main_assertions,
138 num_aux_assertions,
139 options,
140 )
141 .set_num_transition_exemptions(2);
142
143 Self {
144 context,
145 stack_inputs: pub_inputs.stack_inputs,
146 stack_outputs: pub_inputs.stack_outputs,
147 constraint_ranges,
148 program_digest: pub_inputs.program_info.program_hash().to_owned(),
149 kernel_digests: pub_inputs.program_info.kernel_procedures().to_owned(),
150 pc_transcript_state: pub_inputs.pc_transcript_state,
151 }
152 }
153
154 fn get_periodic_column_values(&self) -> Vec<Vec<Felt>> {
159 chiplets::get_periodic_column_values()
160 }
161
162 fn get_assertions(&self) -> Vec<Assertion<Felt>> {
166 let mut result = vec![Assertion::single(CLK_COL_IDX, 0, ZERO)];
169
170 if IS_FULL_CONSTRAINT_SET {
171 stack::get_assertions_first_step(&mut result, &*self.stack_inputs);
173
174 range::get_assertions_first_step(&mut result);
176
177 let last_step = self.last_step();
180
181 stack::get_assertions_last_step(&mut result, last_step, &self.stack_outputs);
183
184 range::get_assertions_last_step(&mut result, last_step);
186 }
187
188 result
189 }
190
191 fn get_aux_assertions<E: FieldElement<BaseField = Self::BaseField>>(
192 &self,
193 aux_rand_elements: &AuxRandElements<E>,
194 ) -> Vec<Assertion<E>> {
195 let mut result: Vec<Assertion<E>> = Vec::new();
196
197 range::get_aux_assertions_first_step::<E>(&mut result);
199
200 chiplets::get_aux_assertions_first_step::<E>(
202 &mut result,
203 &self.kernel_digests,
204 aux_rand_elements,
205 self.pc_transcript_state,
206 );
207
208 if IS_FULL_CONSTRAINT_SET {
210 stack::get_aux_assertions_first_step(&mut result);
212
213 let last_step = self.last_step();
216
217 stack::get_aux_assertions_last_step(&mut result, last_step);
219 }
220 let last_step = self.last_step();
222 range::get_aux_assertions_last_step::<E>(&mut result, last_step);
223
224 result
225 }
226
227 fn evaluate_transition<E: FieldElement<BaseField = Felt>>(
231 &self,
232 frame: &EvaluationFrame<E>,
233 periodic_values: &[E],
234 result: &mut [E],
235 ) {
236 let current = frame.current();
237 let next = frame.next();
238
239 result[0] = next[CLK_COL_IDX] - (current[CLK_COL_IDX] + E::ONE);
242
243 if IS_FULL_CONSTRAINT_SET {
244 stack::enforce_constraints::<E>(
247 frame,
248 select_result_range!(result, self.constraint_ranges.stack),
249 );
250
251 range::enforce_constraints::<E>(
254 frame,
255 select_result_range!(result, self.constraint_ranges.range_checker),
256 );
257
258 chiplets::enforce_constraints::<E>(
260 frame,
261 periodic_values,
262 select_result_range!(result, self.constraint_ranges.chiplets),
263 );
264 }
265 }
266
267 fn evaluate_aux_transition<F, E>(
268 &self,
269 main_frame: &EvaluationFrame<F>,
270 aux_frame: &EvaluationFrame<E>,
271 _periodic_values: &[F],
272 aux_rand_elements: &AuxRandElements<E>,
273 result: &mut [E],
274 ) where
275 F: FieldElement<BaseField = Felt>,
276 E: FieldElement<BaseField = Felt> + ExtensionOf<F>,
277 {
278 range::enforce_aux_constraints::<F, E>(
280 main_frame,
281 aux_frame,
282 aux_rand_elements.rand_elements(),
283 result,
284 );
285 }
286
287 fn context(&self) -> &AirContext<Felt> {
288 &self.context
289 }
290
291 fn get_aux_rand_elements<E, R>(
292 &self,
293 public_coin: &mut R,
294 ) -> Result<AuxRandElements<E>, RandomCoinError>
295 where
296 E: FieldElement<BaseField = Self::BaseField>,
297 R: RandomCoin<BaseField = Self::BaseField>,
298 {
299 let num_elements = self.trace_info().get_num_aux_segment_rand_elements();
300 let mut rand_elements = Vec::with_capacity(num_elements);
301 let max_message_length = num_elements - 1;
302
303 let alpha = public_coin.draw()?;
304 let beta = public_coin.draw()?;
305
306 let betas = get_power_series(beta, max_message_length);
307
308 rand_elements.push(alpha);
309 rand_elements.extend_from_slice(&betas);
310
311 Ok(AuxRandElements::new(rand_elements))
312 }
313}
314
315#[derive(Debug)]
319pub struct PublicInputs {
320 program_info: ProgramInfo,
321 stack_inputs: StackInputs,
322 stack_outputs: StackOutputs,
323 pc_transcript_state: PrecompileTranscriptState,
324}
325
326impl PublicInputs {
327 pub fn new(
330 program_info: ProgramInfo,
331 stack_inputs: StackInputs,
332 stack_outputs: StackOutputs,
333 pc_transcript_state: PrecompileTranscriptState,
334 ) -> Self {
335 Self {
336 program_info,
337 stack_inputs,
338 stack_outputs,
339 pc_transcript_state,
340 }
341 }
342}
343
344impl miden_core::ToElements<Felt> for PublicInputs {
345 fn to_elements(&self) -> Vec<Felt> {
346 let mut result = self.stack_inputs.to_vec();
347 result.append(&mut self.stack_outputs.to_vec());
348 result.append(&mut self.program_info.to_elements());
349 let pc_state: [Felt; 4] = self.pc_transcript_state.into();
350 result.extend_from_slice(&pc_state);
351 result
352 }
353}
354
355impl Serializable for PublicInputs {
359 fn write_into<W: ByteWriter>(&self, target: &mut W) {
360 self.program_info.write_into(target);
361 self.stack_inputs.write_into(target);
362 self.stack_outputs.write_into(target);
363 self.pc_transcript_state.write_into(target);
364 }
365}
366
367impl Deserializable for PublicInputs {
368 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
369 let program_info = ProgramInfo::read_from(source)?;
370 let stack_inputs = StackInputs::read_from(source)?;
371 let stack_outputs = StackOutputs::read_from(source)?;
372 let pc_transcript_state = Word::read_from(source)?;
373
374 Ok(PublicInputs {
375 program_info,
376 stack_inputs,
377 stack_outputs,
378 pc_transcript_state,
379 })
380 }
381}