1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
pub mod air;
pub mod columns;
pub mod event;
pub mod opcode;
pub mod trace;
pub use event::RangeCheckEvent;
pub use opcode::*;
use alloc::collections::BTreeMap;
use core::borrow::BorrowMut;
use std::marker::PhantomData;
use p3_field::Field;
use p3_matrix::dense::RowMajorMatrix;
use self::columns::{RangeCheckPreprocessedCols, NUM_RANGE_CHECK_PREPROCESSED_COLS};
use crate::range_check::trace::NUM_ROWS;
/// The number of different range check operations.
pub const NUM_RANGE_CHECK_OPS: usize = 2;
/// A chip for computing range check operations.
///
/// The chip contains a preprocessed table of all possible range check operations. Other chips can
/// then use lookups into this table to range check their values.
#[derive(Debug, Clone, Copy, Default)]
pub struct RangeCheckChip<F>(PhantomData<F>);
impl<F: Field> RangeCheckChip<F> {
/// Creates the preprocessed range check trace and event map.
///
/// This function returns a pair `(trace, map)`, where:
/// - `trace` is a matrix containing all possible range check values.
/// - `map` is a map from a range check lookup to the value's corresponding row it appears in
/// the table and
/// the index of the result in the array of multiplicities.
pub fn trace_and_map() -> (RowMajorMatrix<F>, BTreeMap<RangeCheckEvent, (usize, usize)>) {
// A map from a byte lookup to its corresponding row in the table and index in the array of
// multiplicities.
let mut event_map = BTreeMap::new();
// The trace containing all values, with all multiplicities set to zero.
let mut initial_trace = RowMajorMatrix::new(
vec![F::zero(); NUM_ROWS * NUM_RANGE_CHECK_PREPROCESSED_COLS],
NUM_RANGE_CHECK_PREPROCESSED_COLS,
);
// Record all the necessary operations for each range check lookup.
let opcodes = RangeCheckOpcode::all();
// Iterate over all U16 values.
for (row_index, val) in (0..=u16::MAX).enumerate() {
let col: &mut RangeCheckPreprocessedCols<F> =
initial_trace.row_mut(row_index).borrow_mut();
// Set the u16 value.
col.value_u16 = F::from_canonical_u16(val);
// Iterate over all range check operations to update col values and the table map.
for (i, opcode) in opcodes.iter().enumerate() {
if *opcode == RangeCheckOpcode::U12 {
col.u12_out_range = F::from_bool(val > 0xFFF);
}
let event = RangeCheckEvent::new(*opcode, val);
event_map.insert(event, (row_index, i));
}
}
(initial_trace, event_map)
}
}