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