diff --git a/crates/brainfuck_prover/src/components/memory/table.rs b/crates/brainfuck_prover/src/components/memory/table.rs index f0c8ca8..ba7a00f 100644 --- a/crates/brainfuck_prover/src/components/memory/table.rs +++ b/crates/brainfuck_prover/src/components/memory/table.rs @@ -106,10 +106,48 @@ impl MemoryTable { self.table.iter().find(|r| *r == row) } - /// Sorts in-place the existing [`MemoryTableRow`] rows in the Memory Table by `mp`. + /// Returns a reference to a row in the Memory Table given its index. + /// + /// # Arguments + /// * `index` - The [`usize`] index to search for in the table. + /// + /// # Returns + /// An `Option` containing a reference to the matching row if found, + /// or `None` if the row does not exist in the table. + pub fn get_row_from_index(&self, index: usize) -> Option<&MemoryTableRow> { + self.table.get(index) + } + + /// Sorts in-place the existing [`MemoryTableRow`] rows in the Memory Table by `mp`, then `clk`. + /// + /// Having the rows sorted is required to ensure a correct proof generation (such that the + /// constraints can be verified). pub fn sort(&mut self) { self.table.sort_by_key(|x| (x.mp, x.clk)); } + + /// Fills the jumps in `clk` with dummy rows. + /// + /// Required to ensure the correct sorting of the [`MemoryTable`] in the constraints. + pub fn complete_with_dummy_rows(&mut self) { + let mut new_table = Vec::with_capacity(self.table.len()); + let mut prev_row = self.get_row_from_index(0).unwrap(); + + for row in &self.table { + let next_clk = prev_row.clk + BaseField::one(); + if row.mp == prev_row.mp && row.clk > next_clk { + let mut clk = next_clk; + while clk < row.clk { + new_table.push(MemoryTableRow::new_dummy(clk, prev_row.mp, prev_row.mv)); + clk += BaseField::one(); + } + } + new_table.push(row.clone()); + prev_row = row; + } + new_table.shrink_to_fit(); + self.table = new_table; + } } #[cfg(test)] @@ -268,4 +306,28 @@ mod tests { assert_eq!(memory_table, expected_memory_table); } + + #[test] + fn test_complete_wih_dummy_rows() { + let mut memory_table = MemoryTable::new(); + let row1 = MemoryTableRow::new(BaseField::zero(), BaseField::zero(), BaseField::zero()); + let row2 = MemoryTableRow::new(BaseField::zero(), BaseField::one(), BaseField::zero()); + let row3 = MemoryTableRow::new(BaseField::from(5), BaseField::one(), BaseField::one()); + memory_table.add_rows(vec![row3.clone(), row1.clone(), row2.clone()]); + memory_table.sort(); + memory_table.complete_with_dummy_rows(); + + let mut expected_memory_table = MemoryTable::new(); + expected_memory_table.add_rows(vec![ + row1, + row2, + MemoryTableRow::new_dummy(BaseField::from(1), BaseField::one(), BaseField::zero()), + MemoryTableRow::new_dummy(BaseField::from(2), BaseField::one(), BaseField::zero()), + MemoryTableRow::new_dummy(BaseField::from(3), BaseField::one(), BaseField::zero()), + MemoryTableRow::new_dummy(BaseField::from(4), BaseField::one(), BaseField::zero()), + row3, + ]); + + assert_eq!(memory_table, expected_memory_table); + } }