Skip to main content

sp1_core_machine/range/
trace.rs

1use slop_algebra::PrimeField32;
2use sp1_core_executor::{events::ByteRecord, ByteOpcode, ExecutionRecord, Program};
3use sp1_hypercube::air::MachineAir;
4use std::mem::MaybeUninit;
5
6use crate::range::columns::RangePreprocessedCols;
7
8use super::{
9    columns::{NUM_RANGE_MULT_COLS, NUM_RANGE_PREPROCESSED_COLS},
10    RangeChip,
11};
12
13use struct_reflection::StructReflectionHelper;
14
15pub const NUM_ROWS: usize = 1 << 17;
16
17impl<F: PrimeField32> MachineAir<F> for RangeChip<F> {
18    type Record = ExecutionRecord;
19
20    type Program = Program;
21
22    fn name(&self) -> &'static str {
23        "Range"
24    }
25
26    fn num_rows(&self, _: &Self::Record) -> Option<usize> {
27        Some(NUM_ROWS)
28    }
29
30    fn preprocessed_width(&self) -> usize {
31        NUM_RANGE_PREPROCESSED_COLS
32    }
33
34    fn preprocessed_num_rows(&self, _program: &Self::Program) -> Option<usize> {
35        Some(NUM_ROWS)
36    }
37
38    fn preprocessed_num_rows_with_instrs_len(
39        &self,
40        _program: &Self::Program,
41        _instrs_len: usize,
42    ) -> Option<usize> {
43        Some(NUM_ROWS)
44    }
45
46    fn generate_preprocessed_trace_into(
47        &self,
48        _program: &Self::Program,
49        buffer: &mut [MaybeUninit<F>],
50    ) {
51        Self::trace(buffer);
52    }
53
54    fn generate_dependencies(&self, input: &ExecutionRecord, output: &mut ExecutionRecord) {
55        let initial_timestamp_0 = ((input.public_values.initial_timestamp >> 32) & 0xFFFF) as u16;
56        let initial_timestamp_3 = (input.public_values.initial_timestamp & 0xFFFF) as u16;
57        let last_timestamp_0 = ((input.public_values.last_timestamp >> 32) & 0xFFFF) as u16;
58        let last_timestamp_3 = (input.public_values.last_timestamp & 0xFFFF) as u16;
59
60        output.add_bit_range_check(initial_timestamp_0, 16);
61        output.add_bit_range_check((initial_timestamp_3 - 1) / 8, 13);
62        output.add_bit_range_check(last_timestamp_0, 16);
63        output.add_bit_range_check((last_timestamp_3 - 1) / 8, 13);
64
65        for addr in [
66            input.public_values.pc_start,
67            input.public_values.next_pc,
68            input.public_values.previous_init_addr,
69            input.public_values.last_init_addr,
70            input.public_values.previous_finalize_addr,
71            input.public_values.last_finalize_addr,
72        ] {
73            let limb_0 = (addr & 0xFFFF) as u16;
74            let limb_1 = ((addr >> 16) & 0xFFFF) as u16;
75            let limb_2 = ((addr >> 32) & 0xFFFF) as u16;
76            output.add_bit_range_check(limb_0, 16);
77            output.add_bit_range_check(limb_1, 16);
78            output.add_bit_range_check(limb_2, 16);
79        }
80
81        #[cfg(feature = "mprotect")]
82        for addr in [
83            input.public_values.trap_context[0],
84            input.public_values.trap_context[1],
85            input.public_values.trap_context[2],
86            input.public_values.untrusted_memory[0],
87            input.public_values.untrusted_memory[1],
88        ] {
89            let limb_0 = (addr & 0xFFFF) as u16;
90            let limb_1 = ((addr >> 16) & 0xFFFF) as u16;
91            let limb_2 = ((addr >> 32) & 0xFFFF) as u16;
92            output.add_bit_range_check(limb_0, 16);
93            output.add_bit_range_check(limb_1, 16);
94            output.add_bit_range_check(limb_2, 16);
95        }
96    }
97
98    fn generate_trace_into(
99        &self,
100        input: &ExecutionRecord,
101        _output: &mut ExecutionRecord,
102        buffer: &mut [MaybeUninit<F>],
103    ) {
104        let buffer_ptr = buffer.as_mut_ptr() as *mut F;
105        let values =
106            unsafe { core::slice::from_raw_parts_mut(buffer_ptr, NUM_RANGE_MULT_COLS * NUM_ROWS) };
107        unsafe {
108            core::ptr::write_bytes(values.as_mut_ptr(), 0, NUM_RANGE_MULT_COLS * NUM_ROWS);
109        }
110
111        for (lookup, mult) in input.byte_lookups.iter() {
112            if lookup.opcode != ByteOpcode::Range {
113                continue;
114            }
115            let row = (lookup.a as usize) + (1 << lookup.b);
116            values[row] = F::from_canonical_usize(*mult);
117        }
118    }
119
120    fn included(&self, _shard: &Self::Record) -> bool {
121        true
122    }
123
124    fn column_names(&self) -> Vec<String> {
125        RangePreprocessedCols::<F>::struct_reflection().unwrap()
126    }
127}