diff --git a/air/src/trace/main_trace.rs b/air/src/trace/main_trace.rs index 454074a714..dc4db3ca88 100644 --- a/air/src/trace/main_trace.rs +++ b/air/src/trace/main_trace.rs @@ -291,6 +291,11 @@ impl MainTrace { self.columns.get_column(CHIPLETS_OFFSET + 4)[i] } + /// Returns `true` if a row is part of the hash chiplet. + pub fn is_hash_row(&self, i: usize) -> bool { + self.chiplet_selector_0(i) == ZERO + } + /// Returns the (full) state of the hasher chiplet at row i. pub fn chiplet_hasher_state(&self, i: usize) -> [Felt; STATE_WIDTH] { let mut state = [ZERO; STATE_WIDTH]; @@ -306,6 +311,11 @@ impl MainTrace { self.columns.get(HASHER_NODE_INDEX_COL_IDX, i) } + /// Returns `true` if a row is part of the bitwise chiplet. + pub fn is_bitwise_row(&self, i: usize) -> bool { + self.chiplet_selector_0(i) == ONE && self.chiplet_selector_1(i) == ZERO + } + /// Returns the bitwise column holding the aggregated value of input `a` at row i. pub fn chiplet_bitwise_a(&self, i: usize) -> Felt { self.columns.get_column(BITWISE_A_COL_IDX)[i] @@ -321,6 +331,13 @@ impl MainTrace { self.columns.get_column(BITWISE_OUTPUT_COL_IDX)[i] } + /// Returns `true` if a row is part of the memory chiplet. + pub fn is_memory_row(&self, i: usize) -> bool { + self.chiplet_selector_0(i) == ONE + && self.chiplet_selector_1(i) == ONE + && self.chiplet_selector_2(i) == ZERO + } + /// Returns the i-th row of the chiplet column containing memory context. pub fn chiplet_memory_ctx(&self, i: usize) -> Felt { self.columns.get_column(MEMORY_CTX_COL_IDX)[i] @@ -356,6 +373,14 @@ impl MainTrace { self.columns.get_column(MEMORY_V_COL_RANGE.start + 3)[i] } + /// Returns `true` if a row is part of the kernel chiplet. + pub fn is_kernel_row(&self, i: usize) -> bool { + self.chiplet_selector_0(i) == ONE + && self.chiplet_selector_1(i) == ONE + && self.chiplet_selector_2(i) == ONE + && self.chiplet_selector_3(i) == ZERO + } + /// Returns the i-th row of the kernel chiplet `addr` column. pub fn chiplet_kernel_addr(&self, i: usize) -> Felt { self.columns.get_column(CHIPLETS_OFFSET + 5)[i] @@ -385,14 +410,6 @@ impl MainTrace { self.columns.get_column(CHIPLETS_OFFSET + 9)[i] } - /// Returns `true` if a row is part of the kernel chiplet. - pub fn is_kernel_row(&self, i: usize) -> bool { - self.chiplet_selector_0(i) == ONE - && self.chiplet_selector_1(i) == ONE - && self.chiplet_selector_2(i) == ONE - && self.chiplet_selector_3(i) == ZERO - } - // MERKLE PATH HASHING SELECTORS // -------------------------------------------------------------------------------------------- diff --git a/processor/src/chiplets/aux_trace/mod.rs b/processor/src/chiplets/aux_trace/mod.rs index f1a78f8e58..0580e2f60a 100644 --- a/processor/src/chiplets/aux_trace/mod.rs +++ b/processor/src/chiplets/aux_trace/mod.rs @@ -69,82 +69,7 @@ impl AuxTraceBuilder { } } -// BUS TRACE BUILDER -// ================================================================================================ - -/// Describes how to construct the execution trace of the chiplets bus auxiliary trace column. -#[derive(Default)] -pub struct BusColumnBuilder {} - -impl> AuxColumnBuilder for BusColumnBuilder { - /// Constructs the requests made by the VM-components to the chiplets at row i. - fn get_requests_at(&self, main_trace: &MainTrace, alphas: &[E], row: usize) -> E - where - E: FieldElement, - { - let op_code_felt = main_trace.get_op_code(row); - let op_code = op_code_felt.as_int() as u8; - - match op_code { - JOIN | SPLIT | LOOP | DYN | CALL => { - build_control_block_request(main_trace, op_code_felt, alphas, row) - } - SYSCALL => build_syscall_block_request(main_trace, op_code_felt, alphas, row), - SPAN => build_span_block_request(main_trace, alphas, row), - RESPAN => build_respan_block_request(main_trace, alphas, row), - END => build_end_block_request(main_trace, alphas, row), - AND => build_bitwise_request(main_trace, ZERO, alphas, row), - XOR => build_bitwise_request(main_trace, ONE, alphas, row), - MLOADW => build_mem_request_word(main_trace, MEMORY_READ_LABEL, alphas, row), - MSTOREW => build_mem_request_word(main_trace, MEMORY_WRITE_LABEL, alphas, row), - MLOAD => build_mem_request_element(main_trace, MEMORY_READ_LABEL, alphas, row), - MSTORE => build_mem_request_element(main_trace, MEMORY_WRITE_LABEL, alphas, row), - MSTREAM => build_mstream_request(main_trace, alphas, row), - RCOMBBASE => build_rcomb_base_request(main_trace, alphas, row), - HPERM => build_hperm_request(main_trace, alphas, row), - MPVERIFY => build_mpverify_request(main_trace, alphas, row), - MRUPDATE => build_mrupdate_request(main_trace, alphas, row), - _ => E::ONE, - } - } - - /// Constructs the responses from the chiplets to the other VM-components at row i. - fn get_responses_at(&self, main_trace: &MainTrace, alphas: &[E], row: usize) -> E - where - E: FieldElement, - { - let selector0 = main_trace.chiplet_selector_0(row); - let selector1 = main_trace.chiplet_selector_1(row); - let selector2 = main_trace.chiplet_selector_2(row); - let selector3 = main_trace.chiplet_selector_3(row); - let selector4 = main_trace.chiplet_selector_4(row); - - if selector0 == ZERO { - build_hasher_chiplet_responses(main_trace, row, alphas, selector1, selector2, selector3) - } else if selector1 == ZERO { - debug_assert_eq!(selector0, ONE); - build_bitwise_chiplet_responses(main_trace, row, selector2, alphas) - } else if selector2 == ZERO { - debug_assert_eq!(selector0, ONE); - debug_assert_eq!(selector1, ONE); - build_memory_chiplet_responses(main_trace, row, selector3, alphas) - } else if selector3 == ZERO { - debug_assert_eq!(selector0, ONE); - debug_assert_eq!(selector1, ONE); - debug_assert_eq!(selector2, ONE); - build_kernel_chiplet_responses(main_trace, row, selector4, alphas) - * build_kernel_procedure_table_responses(main_trace, row, alphas) - } else { - debug_assert_eq!(selector0, ONE); - debug_assert_eq!(selector1, ONE); - debug_assert_eq!(selector2, ONE); - debug_assert_eq!(selector3, ONE); - E::ONE - } - } -} - -// VIRTUAL TABLE TRACE BUILDER +// VIRTUAL TABLE COLUMN BUILDER // ================================================================================================ /// Describes how to construct the execution trace of the chiplets virtual table auxiliary trace @@ -159,24 +84,24 @@ impl> AuxColumnBuilder for ChipletsVTableCo fn get_responses_at(&self, main_trace: &MainTrace, alphas: &[E], row: usize) -> E { chiplets_vtable_add_sibling(main_trace, alphas, row) - * chiplets_kernel_table_include(main_trace, alphas, row) + * build_kernel_procedure_table_inclusions(main_trace, alphas, row) } } -// CHIPLETS VIRTUAL TABLE REQUESTS +// VIRTUAL TABLE REQUESTS // ================================================================================================ -/// Constructs the inclusions to the table when the hasher absorbs a new sibling node while -/// computing the old Merkle root. -fn chiplets_vtable_add_sibling(main_trace: &MainTrace, alphas: &[E], row: usize) -> E +/// Constructs the removals from the table when the hasher absorbs a new sibling node while +/// computing the new Merkle root. +fn chiplets_vtable_remove_sibling(main_trace: &MainTrace, alphas: &[E], row: usize) -> E where E: FieldElement, { - let f_mv: bool = main_trace.f_mv(row); - let f_mva: bool = if row == 0 { false } else { main_trace.f_mva(row - 1) }; + let f_mu: bool = main_trace.f_mu(row); + let f_mua: bool = if row == 0 { false } else { main_trace.f_mua(row - 1) }; - if f_mv || f_mva { - let index = if f_mva { + if f_mu || f_mua { + let index = if f_mua { main_trace.chiplet_node_index(row - 1) } else { main_trace.chiplet_node_index(row) @@ -204,17 +129,20 @@ where } } -/// Constructs the removals from the table when the hasher absorbs a new sibling node while -/// computing the new Merkle root. -fn chiplets_vtable_remove_sibling(main_trace: &MainTrace, alphas: &[E], row: usize) -> E +// VIRTUAL TABLE RESPONSES +// ================================================================================================ + +/// Constructs the inclusions to the table when the hasher absorbs a new sibling node while +/// computing the old Merkle root. +fn chiplets_vtable_add_sibling(main_trace: &MainTrace, alphas: &[E], row: usize) -> E where E: FieldElement, { - let f_mu: bool = main_trace.f_mu(row); - let f_mua: bool = if row == 0 { false } else { main_trace.f_mua(row - 1) }; + let f_mv: bool = main_trace.f_mv(row); + let f_mva: bool = if row == 0 { false } else { main_trace.f_mva(row - 1) }; - if f_mu || f_mua { - let index = if f_mua { + if f_mv || f_mva { + let index = if f_mva { main_trace.chiplet_node_index(row - 1) } else { main_trace.chiplet_node_index(row) @@ -242,23 +170,91 @@ where } } -/// Constructs the inclusions to the kernel procedure table. -fn chiplets_kernel_table_include(main_trace: &MainTrace, alphas: &[E], row: usize) -> E +/// Builds the inclusions to the kernel procedure table at `row`. +fn build_kernel_procedure_table_inclusions(main_trace: &MainTrace, alphas: &[E], row: usize) -> E where E: FieldElement, { - if main_trace.is_kernel_row(row) && main_trace.is_addr_change(row) { - alphas[0] - + alphas[1].mul_base(main_trace.addr(row)) - + alphas[2].mul_base(main_trace.chiplet_kernel_root_0(row)) - + alphas[3].mul_base(main_trace.chiplet_kernel_root_1(row)) - + alphas[4].mul_base(main_trace.chiplet_kernel_root_2(row)) - + alphas[5].mul_base(main_trace.chiplet_kernel_root_3(row)) + if main_trace.is_kernel_row(row) { + let addr = main_trace.chiplet_kernel_addr(row); + let addr_nxt = main_trace.chiplet_kernel_addr(row + 1); + let addr_delta = addr_nxt - addr; + let root0 = main_trace.chiplet_kernel_root_0(row); + let root1 = main_trace.chiplet_kernel_root_1(row); + let root2 = main_trace.chiplet_kernel_root_2(row); + let root3 = main_trace.chiplet_kernel_root_3(row); + + let v = alphas[0] + + alphas[1].mul_base(addr) + + alphas[2].mul_base(root0) + + alphas[3].mul_base(root1) + + alphas[4].mul_base(root2) + + alphas[5].mul_base(root3); + + v.mul_base(addr_delta) + E::from(ONE - addr_delta) } else { E::ONE } } +// BUS COLUMN BUILDER +// ================================================================================================ + +/// Describes how to construct the execution trace of the chiplets bus auxiliary trace column. +#[derive(Default)] +pub struct BusColumnBuilder {} + +impl> AuxColumnBuilder for BusColumnBuilder { + /// Constructs the requests made by the VM-components to the chiplets at `row`. + fn get_requests_at(&self, main_trace: &MainTrace, alphas: &[E], row: usize) -> E + where + E: FieldElement, + { + let op_code_felt = main_trace.get_op_code(row); + let op_code = op_code_felt.as_int() as u8; + + match op_code { + JOIN | SPLIT | LOOP | DYN | CALL => { + build_control_block_request(main_trace, op_code_felt, alphas, row) + } + SYSCALL => build_syscall_block_request(main_trace, op_code_felt, alphas, row), + SPAN => build_span_block_request(main_trace, alphas, row), + RESPAN => build_respan_block_request(main_trace, alphas, row), + END => build_end_block_request(main_trace, alphas, row), + AND => build_bitwise_request(main_trace, ZERO, alphas, row), + XOR => build_bitwise_request(main_trace, ONE, alphas, row), + MLOADW => build_mem_request_word(main_trace, MEMORY_READ_LABEL, alphas, row), + MSTOREW => build_mem_request_word(main_trace, MEMORY_WRITE_LABEL, alphas, row), + MLOAD => build_mem_request_element(main_trace, MEMORY_READ_LABEL, alphas, row), + MSTORE => build_mem_request_element(main_trace, MEMORY_WRITE_LABEL, alphas, row), + MSTREAM => build_mstream_request(main_trace, alphas, row), + RCOMBBASE => build_rcomb_base_request(main_trace, alphas, row), + HPERM => build_hperm_request(main_trace, alphas, row), + MPVERIFY => build_mpverify_request(main_trace, alphas, row), + MRUPDATE => build_mrupdate_request(main_trace, alphas, row), + _ => E::ONE, + } + } + + /// Constructs the responses from the chiplets to the other VM-components at `row`. + fn get_responses_at(&self, main_trace: &MainTrace, alphas: &[E], row: usize) -> E + where + E: FieldElement, + { + if main_trace.is_hash_row(row) { + build_hasher_chiplet_responses(main_trace, row, alphas) + } else if main_trace.is_bitwise_row(row) { + build_bitwise_chiplet_responses(main_trace, row, alphas) + } else if main_trace.is_memory_row(row) { + build_memory_chiplet_responses(main_trace, row, alphas) + } else if main_trace.is_kernel_row(row) { + build_kernel_chiplet_responses(main_trace, row, alphas) + } else { + E::ONE + } + } +} + // CHIPLETS REQUESTS // ================================================================================================ @@ -726,15 +722,15 @@ fn build_hasher_chiplet_responses( // TODO: change type of the `row` variable to `u32` row: usize, alphas: &[E], - selector1: Felt, - selector2: Felt, - selector3: Felt, ) -> E where E: FieldElement, { let mut multiplicand = E::ONE; let selector0 = main_trace.chiplet_selector_0(row); + let selector1 = main_trace.chiplet_selector_1(row); + let selector2 = main_trace.chiplet_selector_2(row); + let selector3 = main_trace.chiplet_selector_3(row); let op_label = get_op_label(selector0, selector1, selector2, selector3); // f_bp, f_mp, f_mv or f_mu == 1 @@ -823,15 +819,11 @@ where } /// Builds the response from the bitwise chiplet at `row`. -fn build_bitwise_chiplet_responses( - main_trace: &MainTrace, - row: usize, - is_xor: Felt, - alphas: &[E], -) -> E +fn build_bitwise_chiplet_responses(main_trace: &MainTrace, row: usize, alphas: &[E]) -> E where E: FieldElement, { + let is_xor = main_trace.chiplet_selector_2(row); if row % BITWISE_OP_CYCLE_LEN == BITWISE_OP_CYCLE_LEN - 1 { let op_label = get_op_label(ONE, ZERO, is_xor, ZERO); @@ -850,15 +842,11 @@ where } /// Builds the response from the memory chiplet at `row`. -fn build_memory_chiplet_responses( - main_trace: &MainTrace, - row: usize, - is_read: Felt, - alphas: &[E], -) -> E +fn build_memory_chiplet_responses(main_trace: &MainTrace, row: usize, alphas: &[E]) -> E where E: FieldElement, { + let is_read = main_trace.chiplet_selector_3(row); let op_label = get_op_label(ONE, ONE, ZERO, is_read); let ctx = main_trace.chiplet_memory_ctx(row); @@ -881,12 +869,7 @@ where } /// Builds the response from the kernel chiplet at `row`. -fn build_kernel_chiplet_responses( - main_trace: &MainTrace, - row: usize, - kernel_chiplet_selector: Felt, - alphas: &[E], -) -> E +fn build_kernel_chiplet_responses(main_trace: &MainTrace, row: usize, alphas: &[E]) -> E where E: FieldElement, { @@ -904,32 +887,10 @@ where + alphas[4].mul_base(root2) + alphas[5].mul_base(root3); + let kernel_chiplet_selector = main_trace.chiplet_selector_4(row); v.mul_base(kernel_chiplet_selector) + E::from(ONE - kernel_chiplet_selector) } -/// Builds the response from the kernel procedure table at `row`. -fn build_kernel_procedure_table_responses(main_trace: &MainTrace, row: usize, alphas: &[E]) -> E -where - E: FieldElement, -{ - let addr = main_trace.chiplet_kernel_addr(row); - let addr_nxt = main_trace.chiplet_kernel_addr(row + 1); - let addr_delta = addr_nxt - addr; - let root0 = main_trace.chiplet_kernel_root_0(row); - let root1 = main_trace.chiplet_kernel_root_1(row); - let root2 = main_trace.chiplet_kernel_root_2(row); - let root3 = main_trace.chiplet_kernel_root_3(row); - - let v = alphas[0] - + alphas[1].mul_base(addr) - + alphas[2].mul_base(root0) - + alphas[3].mul_base(root1) - + alphas[4].mul_base(root2) - + alphas[5].mul_base(root3); - - v.mul_base(addr_delta) + E::from(ONE - addr_delta) -} - // HELPER FUNCTIONS // ================================================================================================