miden_air/
lib.rs

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