use super::{matrix::MultiColumnIter, Matrix};
use air::{Air, AuxTraceRandElements, EvaluationFrame, TraceInfo, TraceLayout};
use math::{polynom, FieldElement, StarkField};
mod trace_lde;
pub use trace_lde::TraceLde;
mod poly_table;
pub use poly_table::TracePolyTable;
mod trace_table;
pub use trace_table::{TraceTable, TraceTableFragment};
mod commitment;
pub use commitment::TraceCommitment;
#[cfg(test)]
mod tests;
pub trait Trace: Sized {
type BaseField: StarkField;
fn layout(&self) -> &TraceLayout;
fn length(&self) -> usize;
fn meta(&self) -> &[u8];
fn main_segment(&self) -> &Matrix<Self::BaseField>;
fn build_aux_segment<E: FieldElement<BaseField = Self::BaseField>>(
&mut self,
aux_segments: &[Matrix<E>],
rand_elements: &[E],
) -> Option<Matrix<E>>;
fn read_main_frame(&self, row_idx: usize, frame: &mut EvaluationFrame<Self::BaseField>);
fn get_info(&self) -> TraceInfo {
TraceInfo::new_multi_segment(self.layout().clone(), self.length(), self.meta().to_vec())
}
fn main_trace_width(&self) -> usize {
self.layout().main_trace_width()
}
fn aux_trace_width(&self) -> usize {
self.layout().aux_trace_width()
}
fn validate<A, E>(
&self,
air: &A,
aux_segments: &[Matrix<E>],
aux_rand_elements: &AuxTraceRandElements<E>,
) where
A: Air<BaseField = Self::BaseField>,
E: FieldElement<BaseField = Self::BaseField>,
{
assert_eq!(
self.main_trace_width(),
air.trace_layout().main_trace_width(),
"inconsistent trace width: expected {}, but was {}",
self.main_trace_width(),
air.trace_layout().main_trace_width(),
);
for assertion in air.get_assertions() {
assertion.apply(self.length(), |step, value| {
assert!(
value == self.main_segment().get(assertion.column(), step),
"trace does not satisfy assertion main_trace({}, {}) == {}",
assertion.column(),
step,
value
);
});
}
for assertion in air.get_aux_assertions(aux_rand_elements) {
let mut column_idx = assertion.column();
let mut segment_idx = 0;
for i in 0..self.layout().num_aux_segments() {
let segment_width = self.layout().get_aux_segment_width(i);
if column_idx < segment_width {
segment_idx = i;
break;
}
column_idx -= segment_width;
}
assertion.apply(self.length(), |step, value| {
assert!(
value == aux_segments[segment_idx].get(column_idx, step),
"trace does not satisfy assertion aux_trace({}, {}) == {}",
assertion.column(),
step,
value
);
});
}
let g = air.trace_domain_generator();
let periodic_values_polys = air.get_periodic_column_polys();
let mut periodic_values = vec![Self::BaseField::ZERO; periodic_values_polys.len()];
let mut x = Self::BaseField::ONE;
let mut main_frame = EvaluationFrame::new(self.main_trace_width());
let mut aux_frame = if air.trace_info().is_multi_segment() {
Some(EvaluationFrame::<E>::new(self.aux_trace_width()))
} else {
None
};
let mut main_evaluations =
vec![Self::BaseField::ZERO; air.context().num_main_transition_constraints()];
let mut aux_evaluations = vec![E::ZERO; air.context().num_aux_transition_constraints()];
for step in 0..self.length() - air.context().num_transition_exemptions() {
for (p, v) in periodic_values_polys.iter().zip(periodic_values.iter_mut()) {
let num_cycles = air.trace_length() / p.len();
let x = x.exp((num_cycles as u32).into());
*v = polynom::eval(p, x);
}
self.read_main_frame(step, &mut main_frame);
air.evaluate_transition(&main_frame, &periodic_values, &mut main_evaluations);
for (i, &evaluation) in main_evaluations.iter().enumerate() {
assert!(
evaluation == Self::BaseField::ZERO,
"main transition constraint {} did not evaluate to ZERO at step {}",
i,
step
);
}
if let Some(ref mut aux_frame) = aux_frame {
read_aux_frame(aux_segments, step, aux_frame);
air.evaluate_aux_transition(
&main_frame,
aux_frame,
&periodic_values,
aux_rand_elements,
&mut aux_evaluations,
);
for (i, &evaluation) in aux_evaluations.iter().enumerate() {
assert!(
evaluation == E::ZERO,
"auxiliary transition constraint {} did not evaluate to ZERO at step {}",
i,
step
);
}
}
x *= g;
}
}
}
fn read_aux_frame<E>(aux_segments: &[Matrix<E>], row_idx: usize, frame: &mut EvaluationFrame<E>)
where
E: FieldElement,
{
for (column, current_value) in MultiColumnIter::new(aux_segments).zip(frame.current_mut()) {
*current_value = column[row_idx];
}
let next_row_idx = (row_idx + 1) % aux_segments[0].num_rows();
for (column, next_value) in MultiColumnIter::new(aux_segments).zip(frame.next_mut()) {
*next_value = column[next_row_idx];
}
}