sp1_core_machine/bytes/
trace.rs1use std::mem::MaybeUninit;
2
3use slop_algebra::PrimeField32;
4use sp1_core_executor::{events::ByteRecord, ByteOpcode, ExecutionRecord, Program};
5use sp1_hypercube::air::{MachineAir, PV_DIGEST_NUM_WORDS};
6use struct_reflection::StructReflectionHelper;
7
8use crate::bytes::columns::BytePreprocessedCols;
9
10use super::{
11 columns::{NUM_BYTE_MULT_COLS, NUM_BYTE_PREPROCESSED_COLS},
12 ByteChip,
13};
14
15pub const NUM_ROWS: usize = 1 << 16;
16
17impl<F: PrimeField32> MachineAir<F> for ByteChip<F> {
18 type Record = ExecutionRecord;
19
20 type Program = Program;
21
22 fn name(&self) -> &'static str {
23 "Byte"
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_BYTE_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(&self, _: &Self::Program, buffer: &mut [MaybeUninit<F>]) {
47 Self::trace(buffer)
48 }
49
50 fn generate_dependencies(&self, input: &ExecutionRecord, output: &mut ExecutionRecord) {
51 let initial_timestamp_1 = ((input.public_values.initial_timestamp >> 24) & 0xFF) as u8;
52 let initial_timestamp_2 = ((input.public_values.initial_timestamp >> 16) & 0xFF) as u8;
53 let last_timestamp_1 = ((input.public_values.last_timestamp >> 24) & 0xFF) as u8;
54 let last_timestamp_2 = ((input.public_values.last_timestamp >> 16) & 0xFF) as u8;
55
56 output.add_u8_range_check(initial_timestamp_1, initial_timestamp_2);
57 output.add_u8_range_check(last_timestamp_1, last_timestamp_2);
58 for i in 0..PV_DIGEST_NUM_WORDS {
59 output.add_u8_range_checks(&u32::to_le_bytes(
60 input.public_values.prev_committed_value_digest[i],
61 ));
62 output.add_u8_range_checks(&u32::to_le_bytes(
63 input.public_values.committed_value_digest[i],
64 ));
65 }
66 }
67
68 fn generate_trace_into(
69 &self,
70 input: &ExecutionRecord,
71 _output: &mut ExecutionRecord,
72 buffer: &mut [MaybeUninit<F>],
73 ) {
74 let buffer_ptr = buffer.as_mut_ptr() as *mut F;
75 let values =
76 unsafe { core::slice::from_raw_parts_mut(buffer_ptr, NUM_BYTE_MULT_COLS * NUM_ROWS) };
77 unsafe {
78 core::ptr::write_bytes(values.as_mut_ptr(), 0, NUM_BYTE_MULT_COLS * NUM_ROWS);
79 }
80
81 for (lookup, mult) in input.byte_lookups.iter() {
82 if lookup.opcode == ByteOpcode::Range {
83 continue;
84 }
85 let row = (((lookup.b as u16) << 8) + lookup.c as u16) as usize;
86 let index = lookup.opcode as usize;
87
88 values[row * NUM_BYTE_MULT_COLS + index] = F::from_canonical_usize(*mult);
89 }
90 }
91
92 fn included(&self, _shard: &Self::Record) -> bool {
93 true
94 }
95
96 fn column_names(&self) -> Vec<String> {
97 BytePreprocessedCols::<F>::struct_reflection().unwrap()
98 }
99}