Skip to main content

sp1_core_machine/memory/consistency/
trace.rs

1use slop_algebra::PrimeField32;
2use sp1_core_executor::events::{ByteRecord, MemoryRecordEnum, PageProtRecord};
3
4use super::{
5    MemoryAccessCols, MemoryAccessColsU8, MemoryAccessTimestamp, PageProtAccessCols,
6    RegisterAccessCols, RegisterAccessTimestamp,
7};
8
9impl<F: PrimeField32> MemoryAccessCols<F> {
10    pub fn populate(&mut self, record: MemoryRecordEnum, output: &mut impl ByteRecord) {
11        let prev_record = record.previous_record();
12        let current_record = record.current_record();
13        self.prev_value = prev_record.value.into();
14        self.access_timestamp.populate_timestamp(
15            prev_record.timestamp,
16            current_record.timestamp,
17            output,
18        );
19    }
20}
21
22impl<F: PrimeField32> RegisterAccessCols<F> {
23    pub fn populate(&mut self, record: MemoryRecordEnum, output: &mut impl ByteRecord) {
24        let prev_record = record.previous_record();
25        let current_record = record.current_record();
26        self.prev_value = prev_record.value.into();
27        self.access_timestamp.populate_timestamp(
28            prev_record.timestamp,
29            current_record.timestamp,
30            output,
31        );
32    }
33}
34
35impl<F: PrimeField32> MemoryAccessColsU8<F> {
36    pub fn populate(&mut self, record: MemoryRecordEnum, output: &mut impl ByteRecord) {
37        let prev_record = record.previous_record();
38        let current_record = record.current_record();
39        self.memory_access.prev_value = prev_record.value.into();
40        self.prev_value_u8.populate_u16_to_u8_safe(output, prev_record.value);
41        self.memory_access.access_timestamp.populate_timestamp(
42            prev_record.timestamp,
43            current_record.timestamp,
44            output,
45        );
46    }
47}
48
49impl<F: PrimeField32> PageProtAccessCols<F> {
50    pub fn populate(
51        &mut self,
52        prev_page_prot: &PageProtRecord,
53        current_timestamp: u64,
54        output: &mut impl ByteRecord,
55    ) {
56        self.prev_prot_bitmap = F::from_canonical_u8(prev_page_prot.page_prot);
57        self.access_timestamp.populate_timestamp(
58            prev_page_prot.timestamp,
59            current_timestamp,
60            output,
61        );
62    }
63}
64
65impl<F: PrimeField32> MemoryAccessTimestamp<F> {
66    pub fn populate_timestamp(
67        &mut self,
68        prev_timestamp: u64,
69        current_timestamp: u64,
70        output: &mut impl ByteRecord,
71    ) {
72        assert!(
73            prev_timestamp < current_timestamp,
74            "prev_timestamp: {prev_timestamp}, current_timestamp: {current_timestamp}"
75        );
76        let prev_high = (prev_timestamp >> 24) as u32;
77        let prev_low = (prev_timestamp & 0xFFFFFF) as u32;
78        let current_high = (current_timestamp >> 24) as u32;
79        let current_low = (current_timestamp & 0xFFFFFF) as u32;
80        self.prev_high = F::from_canonical_u32(prev_high);
81        self.prev_low = F::from_canonical_u32(prev_low);
82
83        // Fill columns used for verifying memory access time is increasing.
84        let use_low_comparison = prev_high == current_high;
85        self.compare_low = F::from_bool(use_low_comparison);
86        let prev_time_value = if use_low_comparison { prev_low } else { prev_high };
87        let current_time_value = if use_low_comparison { current_low } else { current_high };
88
89        let diff_minus_one = current_time_value - prev_time_value - 1;
90        let diff_low_limb = (diff_minus_one & 0xFFFF) as u16;
91        self.diff_low_limb = F::from_canonical_u16(diff_low_limb);
92        let diff_high_limb = (diff_minus_one >> 16) as u8;
93        self.diff_high_limb = F::from_canonical_u8(diff_high_limb);
94
95        // Add a byte table lookup with the u16 range check.
96        output.add_bit_range_check(diff_low_limb, 16);
97        output.add_u8_range_check(diff_high_limb, 0);
98    }
99}
100
101impl<F: PrimeField32> RegisterAccessTimestamp<F> {
102    pub fn populate_timestamp(
103        &mut self,
104        prev_timestamp: u64,
105        current_timestamp: u64,
106        output: &mut impl ByteRecord,
107    ) {
108        let prev_high = (prev_timestamp >> 24) as u32;
109        let prev_low = (prev_timestamp & 0xFFFFFF) as u32;
110        let current_high = (current_timestamp >> 24) as u32;
111        let current_low = (current_timestamp & 0xFFFFFF) as u32;
112
113        let old_timestamp = if prev_high == current_high { prev_low } else { 0 };
114        self.prev_low = F::from_canonical_u32(old_timestamp);
115        let diff_minus_one = current_low - old_timestamp - 1;
116        let diff_low_limb = (diff_minus_one & 0xFFFF) as u16;
117        self.diff_low_limb = F::from_canonical_u16(diff_low_limb);
118        let diff_high_limb = (diff_minus_one >> 16) as u8;
119
120        // Add a byte table lookup with the u16 range check.
121        output.add_bit_range_check(diff_low_limb, 16);
122        output.add_u8_range_check(diff_high_limb, 0);
123    }
124}