Skip to main content

sp1_core_machine/range/
mod.rs

1pub mod air;
2pub mod columns;
3pub mod trace;
4
5use core::borrow::BorrowMut;
6use slop_algebra::Field;
7use std::{marker::PhantomData, mem::MaybeUninit};
8
9use self::columns::{RangePreprocessedCols, NUM_RANGE_PREPROCESSED_COLS};
10use crate::range::trace::NUM_ROWS;
11
12/// A chip for range checking a limb with maximum number of bits.
13#[derive(Debug, Clone, Copy, Default)]
14pub struct RangeChip<F>(PhantomData<F>);
15
16impl<F: Field> RangeChip<F> {
17    /// Creates the preprocessed range table trace.
18    pub fn trace(buffer: &mut [MaybeUninit<F>]) {
19        let buffer_ptr = buffer.as_mut_ptr() as *mut F;
20        let values = unsafe {
21            core::slice::from_raw_parts_mut(buffer_ptr, NUM_RANGE_PREPROCESSED_COLS * NUM_ROWS)
22        };
23
24        // Set the first row to (0, 0).
25        let col: &mut RangePreprocessedCols<F> = values[0..2].borrow_mut();
26        col.a = F::zero();
27        col.bits = F::zero();
28
29        // For `0 <= bits <= 16`, put `(a, bits)` with `0 <= a < 2^bits` into the trace.
30        for bits in 0..=16 {
31            for a in 0..(1 << bits) {
32                let row_index = (1 << bits) + a;
33                let col: &mut RangePreprocessedCols<F> =
34                    values[row_index * 2..(row_index + 1) * 2].borrow_mut();
35                col.a = F::from_canonical_usize(a);
36                col.bits = F::from_canonical_usize(bits);
37            }
38        }
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    #![allow(clippy::print_stdout)]
45
46    use sp1_primitives::SP1Field;
47    use std::time::Instant;
48
49    use super::*;
50
51    #[test]
52    pub fn test_trace_and_map() {
53        let mut vec: Vec<SP1Field> = Vec::with_capacity(NUM_ROWS * NUM_RANGE_PREPROCESSED_COLS);
54        let start = Instant::now();
55        RangeChip::<SP1Field>::trace(vec.spare_capacity_mut());
56        println!("trace and map: {:?}", start.elapsed());
57    }
58}