#![no_std]
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
use alloc::vec::Vec;
use vm_core::{
utils::{ByteReader, ByteWriter, Deserializable, Serializable},
ExtensionOf, ProgramInfo, StackInputs, StackOutputs, ONE, ZERO,
};
use winter_air::{
Air, AirContext, Assertion, AuxTraceRandElements, EvaluationFrame,
ProofOptions as WinterProofOptions, TraceInfo, TransitionConstraintDegree,
};
use winter_prover::matrix::ColMatrix;
mod constraints;
pub use constraints::stack;
use constraints::{chiplets, range};
pub mod trace;
use trace::*;
mod errors;
mod options;
mod proof;
mod utils;
use utils::TransitionConstraintRange;
pub use errors::ExecutionOptionsError;
pub use options::{ExecutionOptions, ProvingOptions};
pub use proof::{ExecutionProof, HashFunction};
pub use vm_core::{
utils::{DeserializationError, ToElements},
Felt, FieldElement, StarkField,
};
pub use winter_air::FieldExtension;
pub struct ProcessorAir {
context: AirContext<Felt>,
stack_inputs: StackInputs,
stack_outputs: StackOutputs,
constraint_ranges: TransitionConstraintRange,
}
impl ProcessorAir {
pub fn last_step(&self) -> usize {
self.trace_length() - self.context().num_transition_exemptions()
}
}
impl Air for ProcessorAir {
type BaseField = Felt;
type PublicInputs = PublicInputs;
fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: WinterProofOptions) -> Self {
let mut main_degrees = vec![
TransitionConstraintDegree::new(1), ];
let mut stack_degrees = stack::get_transition_constraint_degrees();
main_degrees.append(&mut stack_degrees);
let mut range_checker_degrees = range::get_transition_constraint_degrees();
main_degrees.append(&mut range_checker_degrees);
let aux_degrees = range::get_aux_transition_constraint_degrees();
let mut chiplets_degrees = chiplets::get_transition_constraint_degrees();
main_degrees.append(&mut chiplets_degrees);
let constraint_ranges = TransitionConstraintRange::new(
1,
stack::get_transition_constraint_count(),
range::get_transition_constraint_count(),
chiplets::get_transition_constraint_count(),
);
let num_main_assertions = 2 + stack::NUM_ASSERTIONS + range::NUM_ASSERTIONS;
let num_aux_assertions = stack::NUM_AUX_ASSERTIONS + range::NUM_AUX_ASSERTIONS;
let context = AirContext::new_multi_segment(
trace_info,
main_degrees,
aux_degrees,
num_main_assertions,
num_aux_assertions,
options,
)
.set_num_transition_exemptions(2);
Self {
context,
stack_inputs: pub_inputs.stack_inputs,
stack_outputs: pub_inputs.stack_outputs,
constraint_ranges,
}
}
fn get_periodic_column_values(&self) -> Vec<Vec<Felt>> {
chiplets::get_periodic_column_values()
}
#[allow(clippy::vec_init_then_push)]
fn get_assertions(&self) -> Vec<Assertion<Felt>> {
let mut result = Vec::new();
result.push(Assertion::single(CLK_COL_IDX, 0, ZERO));
result.push(Assertion::single(FMP_COL_IDX, 0, Felt::new(2u64.pow(30))));
stack::get_assertions_first_step(&mut result, self.stack_inputs.values());
range::get_assertions_first_step(&mut result);
let last_step = self.last_step();
stack::get_assertions_last_step(&mut result, last_step, &self.stack_outputs);
range::get_assertions_last_step(&mut result, last_step);
result
}
fn get_aux_assertions<E: FieldElement<BaseField = Self::BaseField>>(
&self,
aux_rand_elements: &winter_air::AuxTraceRandElements<E>,
) -> Vec<Assertion<E>> {
let mut result: Vec<Assertion<E>> = Vec::new();
stack::get_aux_assertions_first_step(
&mut result,
aux_rand_elements,
self.stack_inputs.values(),
);
range::get_aux_assertions_first_step::<E>(&mut result);
let last_step = self.last_step();
stack::get_aux_assertions_last_step(
&mut result,
aux_rand_elements,
&self.stack_outputs,
last_step,
);
range::get_aux_assertions_last_step::<E>(&mut result, last_step);
result
}
fn evaluate_transition<E: FieldElement<BaseField = Felt>>(
&self,
frame: &EvaluationFrame<E>,
periodic_values: &[E],
result: &mut [E],
) {
let current = frame.current();
let next = frame.next();
result[0] = next[CLK_COL_IDX] - (current[CLK_COL_IDX] + E::ONE);
stack::enforce_constraints::<E>(
frame,
select_result_range!(result, self.constraint_ranges.stack),
);
range::enforce_constraints::<E>(
frame,
select_result_range!(result, self.constraint_ranges.range_checker),
);
chiplets::enforce_constraints::<E>(
frame,
periodic_values,
select_result_range!(result, self.constraint_ranges.chiplets),
);
}
fn evaluate_aux_transition<F, E>(
&self,
main_frame: &EvaluationFrame<F>,
aux_frame: &EvaluationFrame<E>,
_periodic_values: &[F],
aux_rand_elements: &AuxTraceRandElements<E>,
result: &mut [E],
) where
F: FieldElement<BaseField = Felt>,
E: FieldElement<BaseField = Felt> + ExtensionOf<F>,
{
range::enforce_aux_constraints::<F, E>(main_frame, aux_frame, aux_rand_elements, result);
}
fn context(&self) -> &AirContext<Felt> {
&self.context
}
}
#[derive(Debug)]
pub struct PublicInputs {
program_info: ProgramInfo,
stack_inputs: StackInputs,
stack_outputs: StackOutputs,
}
impl PublicInputs {
pub fn new(
program_info: ProgramInfo,
stack_inputs: StackInputs,
stack_outputs: StackOutputs,
) -> Self {
Self {
program_info,
stack_inputs,
stack_outputs,
}
}
}
impl vm_core::ToElements<Felt> for PublicInputs {
fn to_elements(&self) -> Vec<Felt> {
let mut result = self.program_info.to_elements();
result.append(&mut self.stack_inputs.to_elements());
result.append(&mut self.stack_outputs.to_elements());
result
}
}
impl Serializable for PublicInputs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.program_info.write_into(target);
self.stack_inputs.write_into(target);
self.stack_outputs.write_into(target);
}
}
impl Deserializable for PublicInputs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let program_info = ProgramInfo::read_from(source)?;
let stack_inputs = StackInputs::read_from(source)?;
let stack_outputs = StackOutputs::read_from(source)?;
Ok(PublicInputs {
program_info,
stack_inputs,
stack_outputs,
})
}
}