miden_air/
lib.rs

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::vec::Vec;
11
12use miden_core::{
13    ExtensionOf, ONE, ProgramInfo, StackInputs, StackOutputs, ZERO,
14    utils::{ByteReader, ByteWriter, Deserializable, Serializable},
15};
16use winter_air::{
17    Air, AirContext, Assertion, EvaluationFrame, ProofOptions as WinterProofOptions, TraceInfo,
18    TransitionConstraintDegree,
19};
20use winter_prover::{
21    crypto::{RandomCoin, RandomCoinError},
22    math::get_power_series,
23    matrix::ColMatrix,
24};
25
26mod constraints;
27pub use constraints::stack;
28use constraints::{chiplets, range};
29
30pub mod trace;
31pub use trace::rows::RowIndex;
32use trace::*;
33
34mod errors;
35mod options;
36mod proof;
37
38mod utils;
39
40// RE-EXPORTS
41// ================================================================================================
42
43pub use errors::ExecutionOptionsError;
44pub use miden_core::{
45    Felt, FieldElement, StarkField,
46    utils::{DeserializationError, ToElements},
47};
48pub use options::{ExecutionOptions, ProvingOptions};
49pub use proof::{ExecutionProof, HashFunction};
50use utils::TransitionConstraintRange;
51pub use winter_air::{AuxRandElements, FieldExtension, PartitionOptions};
52
53/// Selects whether to include all existing constraints or only the ones currently encoded in
54/// the ACE circuit in the recursive verifier.
55const IS_FULL_CONSTRAINT_SET: bool = false;
56
57// PROCESSOR AIR
58// ================================================================================================
59
60/// TODO: add docs
61pub struct ProcessorAir {
62    context: AirContext<Felt>,
63    stack_inputs: StackInputs,
64    stack_outputs: StackOutputs,
65    constraint_ranges: TransitionConstraintRange,
66}
67
68impl ProcessorAir {
69    /// Returns last step of the execution trace.
70    pub fn last_step(&self) -> usize {
71        self.trace_length() - self.context().num_transition_exemptions()
72    }
73}
74
75impl Air for ProcessorAir {
76    type BaseField = Felt;
77    type PublicInputs = PublicInputs;
78
79    fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: WinterProofOptions) -> Self {
80        // --- system -----------------------------------------------------------------------------
81        let mut main_degrees = vec![
82            TransitionConstraintDegree::new(1), // clk' = clk + 1
83        ];
84
85        if IS_FULL_CONSTRAINT_SET {
86            // --- stack constraints
87            // -------------------------------------------------------------------
88            let mut stack_degrees = stack::get_transition_constraint_degrees();
89            main_degrees.append(&mut stack_degrees);
90
91            // --- range checker
92            // ----------------------------------------------------------------------
93            let mut range_checker_degrees = range::get_transition_constraint_degrees();
94            main_degrees.append(&mut range_checker_degrees);
95
96            // --- chiplets (hasher, bitwise, memory) -------------------------
97            let mut chiplets_degrees = chiplets::get_transition_constraint_degrees();
98            main_degrees.append(&mut chiplets_degrees);
99        }
100
101        let aux_degrees = range::get_aux_transition_constraint_degrees();
102
103        // Define the transition constraint ranges.
104        let constraint_ranges = TransitionConstraintRange::new(
105            1,
106            stack::get_transition_constraint_count(),
107            range::get_transition_constraint_count(),
108            chiplets::get_transition_constraint_count(),
109        );
110
111        // Define the number of boundary constraints for the main execution trace segment.
112        // TODO: determine dynamically
113        let num_main_assertions = if IS_FULL_CONSTRAINT_SET {
114            2 + stack::NUM_ASSERTIONS + range::NUM_ASSERTIONS
115        } else {
116            1
117        };
118
119        // Define the number of boundary constraints for the auxiliary execution trace segment.
120        let num_aux_assertions = if IS_FULL_CONSTRAINT_SET {
121            stack::NUM_AUX_ASSERTIONS + range::NUM_AUX_ASSERTIONS
122        } else {
123            1
124        };
125
126        // Create the context and set the number of transition constraint exemptions to two; this
127        // allows us to inject random values into the last row of the execution trace.
128        let context = AirContext::new_multi_segment(
129            trace_info,
130            main_degrees,
131            aux_degrees,
132            num_main_assertions,
133            num_aux_assertions,
134            options,
135        )
136        .set_num_transition_exemptions(2);
137
138        Self {
139            context,
140            stack_inputs: pub_inputs.stack_inputs,
141            stack_outputs: pub_inputs.stack_outputs,
142            constraint_ranges,
143        }
144    }
145
146    // PERIODIC COLUMNS
147    // --------------------------------------------------------------------------------------------
148
149    /// Returns a set of periodic columns for the ProcessorAir.
150    fn get_periodic_column_values(&self) -> Vec<Vec<Felt>> {
151        chiplets::get_periodic_column_values()
152    }
153
154    // ASSERTIONS
155    // --------------------------------------------------------------------------------------------
156
157    fn get_assertions(&self) -> Vec<Assertion<Felt>> {
158        // --- set assertions for the first step --------------------------------------------------
159        // first value of clk is 0
160        let mut result = vec![Assertion::single(CLK_COL_IDX, 0, ZERO)];
161
162        if IS_FULL_CONSTRAINT_SET {
163            // first value of fmp is 2^30
164            result.push(Assertion::single(FMP_COL_IDX, 0, Felt::new(2u64.pow(30))));
165
166            // add initial assertions for the stack.
167            stack::get_assertions_first_step(&mut result, &*self.stack_inputs);
168
169            // Add initial assertions for the range checker.
170            range::get_assertions_first_step(&mut result);
171
172            // --- set assertions for the last step
173            // ---------------------------------------------------
174            let last_step = self.last_step();
175
176            // add the stack's assertions for the last step.
177            stack::get_assertions_last_step(&mut result, last_step, &self.stack_outputs);
178
179            // Add the range checker's assertions for the last step.
180            range::get_assertions_last_step(&mut result, last_step);
181        }
182
183        result
184    }
185
186    fn get_aux_assertions<E: FieldElement<BaseField = Self::BaseField>>(
187        &self,
188        _aux_rand_elements: &AuxRandElements<E>,
189    ) -> Vec<Assertion<E>> {
190        let mut result: Vec<Assertion<E>> = Vec::new();
191
192        // --- set assertions for the first step --------------------------------------------------
193        if IS_FULL_CONSTRAINT_SET {
194            // add initial assertions for the stack's auxiliary columns.
195            stack::get_aux_assertions_first_step(&mut result);
196
197            // Add initial assertions for the range checker's auxiliary columns.
198            range::get_aux_assertions_first_step::<E>(&mut result);
199
200            // --- set assertions for the last step
201            // ---------------------------------------------------
202            let last_step = self.last_step();
203
204            // add the stack's auxiliary column assertions for the last step.
205            stack::get_aux_assertions_last_step(&mut result, last_step);
206        }
207        // Add the range checker's auxiliary column assertions for the last step.
208        let last_step = self.last_step();
209        range::get_aux_assertions_last_step::<E>(&mut result, last_step);
210
211        result
212    }
213
214    // TRANSITION CONSTRAINTS
215    // --------------------------------------------------------------------------------------------
216
217    fn evaluate_transition<E: FieldElement<BaseField = Felt>>(
218        &self,
219        frame: &EvaluationFrame<E>,
220        periodic_values: &[E],
221        result: &mut [E],
222    ) {
223        let current = frame.current();
224        let next = frame.next();
225
226        // --- system -----------------------------------------------------------------------------
227        // clk' = clk + 1
228        result[0] = next[CLK_COL_IDX] - (current[CLK_COL_IDX] + E::ONE);
229
230        if IS_FULL_CONSTRAINT_SET {
231            // --- stack operations
232            // -------------------------------------------------------------------
233            stack::enforce_constraints::<E>(
234                frame,
235                select_result_range!(result, self.constraint_ranges.stack),
236            );
237
238            // --- range checker
239            // ----------------------------------------------------------------------
240            range::enforce_constraints::<E>(
241                frame,
242                select_result_range!(result, self.constraint_ranges.range_checker),
243            );
244
245            // --- chiplets (hasher, bitwise, memory) -------------------------
246            chiplets::enforce_constraints::<E>(
247                frame,
248                periodic_values,
249                select_result_range!(result, self.constraint_ranges.chiplets),
250            );
251        }
252    }
253
254    fn evaluate_aux_transition<F, E>(
255        &self,
256        main_frame: &EvaluationFrame<F>,
257        aux_frame: &EvaluationFrame<E>,
258        _periodic_values: &[F],
259        aux_rand_elements: &AuxRandElements<E>,
260        result: &mut [E],
261    ) where
262        F: FieldElement<BaseField = Felt>,
263        E: FieldElement<BaseField = Felt> + ExtensionOf<F>,
264    {
265        // --- range checker ----------------------------------------------------------------------
266        range::enforce_aux_constraints::<F, E>(
267            main_frame,
268            aux_frame,
269            aux_rand_elements.rand_elements(),
270            result,
271        );
272    }
273
274    fn context(&self) -> &AirContext<Felt> {
275        &self.context
276    }
277
278    fn get_aux_rand_elements<E, R>(
279        &self,
280        public_coin: &mut R,
281    ) -> Result<AuxRandElements<E>, RandomCoinError>
282    where
283        E: FieldElement<BaseField = Self::BaseField>,
284        R: RandomCoin<BaseField = Self::BaseField>,
285    {
286        let num_elements = self.trace_info().get_num_aux_segment_rand_elements();
287        let mut rand_elements = Vec::with_capacity(num_elements);
288        let max_message_length = num_elements - 1;
289
290        let alpha = public_coin.draw()?;
291        let beta = public_coin.draw()?;
292
293        let betas = get_power_series(beta, max_message_length);
294
295        rand_elements.push(alpha);
296        rand_elements.extend_from_slice(&betas);
297
298        Ok(AuxRandElements::new(rand_elements))
299    }
300}
301
302// PUBLIC INPUTS
303// ================================================================================================
304
305#[derive(Debug)]
306pub struct PublicInputs {
307    program_info: ProgramInfo,
308    stack_inputs: StackInputs,
309    stack_outputs: StackOutputs,
310}
311
312impl PublicInputs {
313    pub fn new(
314        program_info: ProgramInfo,
315        stack_inputs: StackInputs,
316        stack_outputs: StackOutputs,
317    ) -> Self {
318        Self {
319            program_info,
320            stack_inputs,
321            stack_outputs,
322        }
323    }
324}
325
326impl miden_core::ToElements<Felt> for PublicInputs {
327    fn to_elements(&self) -> Vec<Felt> {
328        let mut result = self.stack_inputs.to_vec();
329        result.append(&mut self.stack_outputs.to_vec());
330        result.append(&mut self.program_info.to_elements());
331        result
332    }
333}
334
335// SERIALIZATION
336// ================================================================================================
337
338impl Serializable for PublicInputs {
339    fn write_into<W: ByteWriter>(&self, target: &mut W) {
340        self.program_info.write_into(target);
341        self.stack_inputs.write_into(target);
342        self.stack_outputs.write_into(target);
343    }
344}
345
346impl Deserializable for PublicInputs {
347    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
348        let program_info = ProgramInfo::read_from(source)?;
349        let stack_inputs = StackInputs::read_from(source)?;
350        let stack_outputs = StackOutputs::read_from(source)?;
351
352        Ok(PublicInputs {
353            program_info,
354            stack_inputs,
355            stack_outputs,
356        })
357    }
358}