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