From 156a2579b17597f08c182e8869d9be7088a298a4 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Thu, 8 Feb 2024 18:31:53 +0100 Subject: [PATCH] Handle additional memory requests made by `RCOMBBASE` (#1229) --- air/src/trace/main_trace.rs | 28 +- docs/src/design/stack/crypto_ops.md | 26 +- docs/src/design/stack/op_constraints.md | 2 +- processor/src/chiplets/aux_trace/mod.rs | 484 +++++++++++++----------- processor/src/operations/comb_ops.rs | 6 +- 5 files changed, 296 insertions(+), 250 deletions(-) diff --git a/air/src/trace/main_trace.rs b/air/src/trace/main_trace.rs index 699e38bf5d..8c23672c3d 100644 --- a/air/src/trace/main_trace.rs +++ b/air/src/trace/main_trace.rs @@ -1,7 +1,7 @@ -use super::super::ColMatrix; use super::{ + super::ColMatrix, chiplets::{ - hasher::{DIGEST_LEN, STATE_WIDTH}, + hasher::{DIGEST_LEN, HASH_CYCLE_LEN, STATE_WIDTH}, BITWISE_A_COL_IDX, BITWISE_B_COL_IDX, BITWISE_OUTPUT_COL_IDX, HASHER_NODE_INDEX_COL_IDX, HASHER_STATE_COL_RANGE, MEMORY_ADDR_COL_IDX, MEMORY_CLK_COL_IDX, MEMORY_CTX_COL_IDX, MEMORY_V_COL_RANGE, @@ -92,19 +92,9 @@ impl MainTrace { self.addr(i) != self.addr(i + 1) } - /// First decoder helper register at row i. - pub fn helper_0(&self, i: usize) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET)[i] - } - - /// Second decoder helper register at row i. - pub fn helper_1(&self, i: usize) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + 1)[i] - } - - /// Third decoder helper register at row i. - pub fn helper_2(&self, i: usize) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + 2)[i] + /// The i-th decoder helper register at `row`. + pub fn helper_register(&self, i: usize, row: usize) -> Felt { + self.columns.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i)[row] } /// Returns the hasher state at row i. @@ -405,7 +395,7 @@ impl MainTrace { /// Returns `true` if the hasher chiplet flags indicate the initialization of verifying /// a Merkle path to an old node during Merkle root update procedure (MRUPDATE). pub fn f_mv(&self, i: usize) -> bool { - (i % 8 == 0) + (i % HASH_CYCLE_LEN == 0) && self.chiplet_selector_0(i) == ZERO && self.chiplet_selector_1(i) == ONE && self.chiplet_selector_2(i) == ONE @@ -415,7 +405,7 @@ impl MainTrace { /// Returns `true` if the hasher chiplet flags indicate the continuation of verifying /// a Merkle path to an old node during Merkle root update procedure (MRUPDATE). pub fn f_mva(&self, i: usize) -> bool { - (i % 8 == 7) + (i % HASH_CYCLE_LEN == HASH_CYCLE_LEN - 1) && self.chiplet_selector_0(i) == ZERO && self.chiplet_selector_1(i) == ONE && self.chiplet_selector_2(i) == ONE @@ -425,7 +415,7 @@ impl MainTrace { /// Returns `true` if the hasher chiplet flags indicate the initialization of verifying /// a Merkle path to a new node during Merkle root update procedure (MRUPDATE). pub fn f_mu(&self, i: usize) -> bool { - (i % 8 == 0) + (i % HASH_CYCLE_LEN == 0) && self.chiplet_selector_0(i) == ZERO && self.chiplet_selector_1(i) == ONE && self.chiplet_selector_2(i) == ONE @@ -435,7 +425,7 @@ impl MainTrace { /// Returns `true` if the hasher chiplet flags indicate the continuation of verifying /// a Merkle path to a new node during Merkle root update procedure (MRUPDATE). pub fn f_mua(&self, i: usize) -> bool { - (i % 8 == 7) + (i % HASH_CYCLE_LEN == HASH_CYCLE_LEN - 1) && self.chiplet_selector_0(i) == ZERO && self.chiplet_selector_1(i) == ONE && self.chiplet_selector_2(i) == ONE diff --git a/docs/src/design/stack/crypto_ops.md b/docs/src/design/stack/crypto_ops.md index 1f7e7d7ed9..fffad56411 100644 --- a/docs/src/design/stack/crypto_ops.md +++ b/docs/src/design/stack/crypto_ops.md @@ -178,4 +178,28 @@ After calling the `mem_stream ` with `x_ptr`, the operation does the following: > TODO: add detailed constraint descriptions. See discussion [here](https://github.com/0xPolygonMiden/miden-vm/issues/869). The effect on the rest of the stack is: -* **No change.** \ No newline at end of file +* **No change.** + +The `RCOMBBASE` makes two memory access request. To simplify the description of these, we first define the following variables : + +$$ +v_1 = \sum_{i=0}^3\alpha_{i+5} \cdot h_{i} +$$ + +$$ +v_2 = \sum_{i=0}^1\alpha_{i+5} \cdot h_{i + 4} +$$ + +Using the above variables, we define the values representing the memory access request as follows: + +$$ +u_{mem, 1} = \alpha_0 + \alpha_1 \cdot op_{mem\_read} + \alpha_2 \cdot ctx + \alpha_3 \cdot s_{13} + \alpha_4 \cdot clk + v_1 +$$ + +$$ +u_{mem, 2} = \alpha_0 + \alpha_1 \cdot op_{mem\_read} + \alpha_2 \cdot ctx + \alpha_3 \cdot s_{14} + \alpha_4 \cdot clk + v_2 +$$ + +$$ +u_{mem} = u_{mem, 1} \cdot u_{mem, 2} +$$ \ No newline at end of file diff --git a/docs/src/design/stack/op_constraints.md b/docs/src/design/stack/op_constraints.md index d8f00282c6..f4502b2daa 100644 --- a/docs/src/design/stack/op_constraints.md +++ b/docs/src/design/stack/op_constraints.md @@ -188,7 +188,7 @@ This group contains operations which require constraints with degree up to $3$. | `SPAN` | $86$ | `101_0110` | [Flow control ops](../decoder/main.md) | $5$ | | `JOIN` | $87$ | `101_0111` | [Flow control ops](../decoder/main.md) | $5$ | | `DYN` | $88$ | `101_1000` | [Flow control ops](../decoder/main.md) | $5$ | -| `RCombBase` | $89$ | `101_1001` | [Crypto ops](./crypto_ops.md) | $5$ | +| `RCOMBBASE` | $89$ | `101_1001` | [Crypto ops](./crypto_ops.md) | $5$ | | `` | $90$ | `101_1010` | | $5$ | | `` | $91$ | `101_1011` | | $5$ | | `` | $92$ | `101_1100` | | $5$ | diff --git a/processor/src/chiplets/aux_trace/mod.rs b/processor/src/chiplets/aux_trace/mod.rs index 2aceaff772..70a1ac2b0e 100644 --- a/processor/src/chiplets/aux_trace/mod.rs +++ b/processor/src/chiplets/aux_trace/mod.rs @@ -14,7 +14,7 @@ use miden_air::trace::{ main_trace::MainTrace, }; -use vm_core::{Operation, ONE, ZERO}; +use vm_core::{Operation, Word, ONE, ZERO}; // CONSTANTS // ================================================================================================ @@ -35,6 +35,7 @@ const MSTOREW: u8 = Operation::MStoreW.op_code(); const MLOAD: u8 = Operation::MLoad.op_code(); const MSTORE: u8 = Operation::MStore.op_code(); const MSTREAM: u8 = Operation::MStream.op_code(); +const RCOMBBASE: u8 = Operation::RCombBase.op_code(); const HPERM: u8 = Operation::HPerm.op_code(); const MPVERIFY: u8 = Operation::MpVerify.op_code(); const MRUPDATE: u8 = Operation::MrUpdate.op_code(); @@ -76,60 +77,61 @@ 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], i: usize) -> E + 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(i); + 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, i) + build_control_block_request(main_trace, op_code_felt, alphas, row) } - SYSCALL => build_syscall_block_request(main_trace, op_code_felt, alphas, i), - SPAN => build_span_block_request(main_trace, alphas, i), - RESPAN => build_respan_block_request(main_trace, alphas, i), - END => build_end_block_request(main_trace, alphas, i), - AND => build_bitwise_request(main_trace, ZERO, alphas, i), - XOR => build_bitwise_request(main_trace, ONE, alphas, i), - MLOADW => build_mem_request(main_trace, MEMORY_READ_LABEL, true, alphas, i), - MSTOREW => build_mem_request(main_trace, MEMORY_WRITE_LABEL, true, alphas, i), - MLOAD => build_mem_request(main_trace, MEMORY_READ_LABEL, false, alphas, i), - MSTORE => build_mem_request(main_trace, MEMORY_WRITE_LABEL, false, alphas, i), - MSTREAM => build_mstream_request(main_trace, alphas, i), - HPERM => build_hperm_request(main_trace, alphas, i), - MPVERIFY => build_mpverify_request(main_trace, alphas, i), - MRUPDATE => build_mrupdate_request(main_trace, alphas, i), + 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], i: usize) -> E + fn get_responses_at(&self, main_trace: &MainTrace, alphas: &[E], row: usize) -> E where E: FieldElement, { - let selector0 = main_trace.chiplet_selector_0(i); - let selector1 = main_trace.chiplet_selector_1(i); - let selector2 = main_trace.chiplet_selector_2(i); - let selector3 = main_trace.chiplet_selector_3(i); - let selector4 = main_trace.chiplet_selector_4(i); + 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, i, alphas, selector1, selector2, selector3) + 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, i, selector2, alphas) + 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, i, selector3, alphas) + build_memory_chiplet_responses(main_trace, row, selector3, alphas) } else if selector3 == ZERO && selector4 == ONE { debug_assert_eq!(selector0, ONE); debug_assert_eq!(selector1, ONE); debug_assert_eq!(selector2, ONE); - build_kernel_chiplet_responses(main_trace, i, alphas) + build_kernel_chiplet_responses(main_trace, row, alphas) } else { debug_assert_eq!(selector0, ONE); debug_assert_eq!(selector1, ONE); @@ -149,13 +151,13 @@ impl> AuxColumnBuilder for BusColumnBuilder pub struct ChipletsVTableColBuilder {} impl> AuxColumnBuilder for ChipletsVTableColBuilder { - fn get_requests_at(&self, main_trace: &MainTrace, alphas: &[E], i: usize) -> E { - chiplets_vtable_remove_sibling(main_trace, alphas, i) + fn get_requests_at(&self, main_trace: &MainTrace, alphas: &[E], row: usize) -> E { + chiplets_vtable_remove_sibling(main_trace, alphas, row) } - fn get_responses_at(&self, main_trace: &MainTrace, alphas: &[E], i: usize) -> E { - chiplets_vtable_add_sibling(main_trace, alphas, i) - * chiplets_kernel_table_include(main_trace, alphas, i) + 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) } } @@ -164,22 +166,22 @@ impl> AuxColumnBuilder for ChipletsVTableCo /// 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], i: usize) -> E +fn chiplets_vtable_add_sibling(main_trace: &MainTrace, alphas: &[E], row: usize) -> E where E: FieldElement, { - let f_mv: bool = main_trace.f_mv(i); - let f_mva: bool = if i == 0 { false } else { main_trace.f_mva(i - 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_mv || f_mva { let index = if f_mva { - main_trace.chiplet_node_index(i - 1) + main_trace.chiplet_node_index(row - 1) } else { - main_trace.chiplet_node_index(i) + main_trace.chiplet_node_index(row) }; let lsb = index.as_int() & 1; if lsb == 0 { - let sibling = &main_trace.chiplet_hasher_state(i)[DIGEST_RANGE.end..]; + let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE.end..]; alphas[0] + alphas[3].mul_base(index) + alphas[12].mul_base(sibling[0]) @@ -187,7 +189,7 @@ where + alphas[14].mul_base(sibling[2]) + alphas[15].mul_base(sibling[3]) } else { - let sibling = &main_trace.chiplet_hasher_state(i)[DIGEST_RANGE]; + let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE]; alphas[0] + alphas[3].mul_base(index) + alphas[8].mul_base(sibling[0]) @@ -202,22 +204,22 @@ 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], i: usize) -> E +fn chiplets_vtable_remove_sibling(main_trace: &MainTrace, alphas: &[E], row: usize) -> E where E: FieldElement, { - let f_mu: bool = main_trace.f_mu(i); - let f_mua: bool = if i == 0 { false } else { main_trace.f_mua(i - 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_mu || f_mua { let index = if f_mua { - main_trace.chiplet_node_index(i - 1) + main_trace.chiplet_node_index(row - 1) } else { - main_trace.chiplet_node_index(i) + main_trace.chiplet_node_index(row) }; let lsb = index.as_int() & 1; if lsb == 0 { - let sibling = &main_trace.chiplet_hasher_state(i)[DIGEST_RANGE.end..]; + let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE.end..]; alphas[0] + alphas[3].mul_base(index) + alphas[12].mul_base(sibling[0]) @@ -225,7 +227,7 @@ where + alphas[14].mul_base(sibling[2]) + alphas[15].mul_base(sibling[3]) } else { - let sibling = &main_trace.chiplet_hasher_state(i)[DIGEST_RANGE]; + let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE]; alphas[0] + alphas[3].mul_base(index) + alphas[8].mul_base(sibling[0]) @@ -239,17 +241,17 @@ where } /// Constructs the inclusions to the kernel table. -fn chiplets_kernel_table_include(main_trace: &MainTrace, alphas: &[E], i: usize) -> E +fn chiplets_kernel_table_include(main_trace: &MainTrace, alphas: &[E], row: usize) -> E where E: FieldElement, { - if main_trace.is_kernel_row(i) && main_trace.is_addr_change(i) { + if main_trace.is_kernel_row(row) && main_trace.is_addr_change(row) { alphas[0] - + alphas[1].mul_base(main_trace.addr(i)) - + alphas[2].mul_base(main_trace.chiplet_kernel_root_0(i)) - + alphas[3].mul_base(main_trace.chiplet_kernel_root_1(i)) - + alphas[4].mul_base(main_trace.chiplet_kernel_root_2(i)) - + alphas[5].mul_base(main_trace.chiplet_kernel_root_3(i)) + + 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)) } else { E::ONE } @@ -263,17 +265,17 @@ fn build_control_block_request>( main_trace: &MainTrace, op_code_felt: Felt, alphas: &[E], - i: usize, + row: usize, ) -> E { let op_label = LINEAR_HASH_LABEL; - let addr_nxt = main_trace.addr(i + 1); + let addr_nxt = main_trace.addr(row + 1); let first_cycle_row = addr_to_row_index(addr_nxt) % HASH_CYCLE_LEN == 0; let transition_label = if first_cycle_row { op_label + 16 } else { op_label + 32 }; let header = alphas[0] + alphas[1].mul_base(Felt::from(transition_label)) + alphas[2].mul_base(addr_nxt); - let state = main_trace.decoder_hasher_state(i); + let state = main_trace.decoder_hasher_state(row); header + build_value(&alphas[8..16], &state) + alphas[5].mul_base(op_code_felt) } @@ -283,12 +285,12 @@ fn build_syscall_block_request>( main_trace: &MainTrace, op_code_felt: Felt, alphas: &[E], - i: usize, + row: usize, ) -> E { - let factor1 = build_control_block_request(main_trace, op_code_felt, alphas, i); + let factor1 = build_control_block_request(main_trace, op_code_felt, alphas, row); let op_label = KERNEL_PROC_LABEL; - let state = main_trace.decoder_hasher_state(i); + let state = main_trace.decoder_hasher_state(row); let factor2 = alphas[0] + alphas[1].mul_base(op_label) + alphas[2].mul_base(state[0]) @@ -303,17 +305,17 @@ fn build_syscall_block_request>( fn build_span_block_request>( main_trace: &MainTrace, alphas: &[E], - i: usize, + row: usize, ) -> E { let op_label = LINEAR_HASH_LABEL; - let addr_nxt = main_trace.addr(i + 1); + let addr_nxt = main_trace.addr(row + 1); let first_cycle_row = addr_to_row_index(addr_nxt) % HASH_CYCLE_LEN == 0; let transition_label = if first_cycle_row { op_label + 16 } else { op_label + 32 }; let header = alphas[0] + alphas[1].mul_base(Felt::from(transition_label)) + alphas[2].mul_base(addr_nxt); - let state = main_trace.decoder_hasher_state(i); + let state = main_trace.decoder_hasher_state(row); header + build_value(&alphas[8..16], &state) } @@ -322,10 +324,10 @@ fn build_span_block_request>( fn build_respan_block_request>( main_trace: &MainTrace, alphas: &[E], - i: usize, + row: usize, ) -> E { let op_label = LINEAR_HASH_LABEL; - let addr_nxt = main_trace.addr(i + 1); + let addr_nxt = main_trace.addr(row + 1); let first_cycle_row = addr_to_row_index(addr_nxt - ONE) % HASH_CYCLE_LEN == 0; let transition_label = if first_cycle_row { op_label + 16 } else { op_label + 32 }; @@ -335,8 +337,8 @@ fn build_respan_block_request>( + alphas[2].mul_base(addr_nxt - ONE) + alphas[3].mul_base(ZERO); - let state = &main_trace.chiplet_hasher_state(i - 2)[CAPACITY_LEN..]; - let state_nxt = &main_trace.chiplet_hasher_state(i - 1)[CAPACITY_LEN..]; + let state = &main_trace.chiplet_hasher_state(row - 2)[CAPACITY_LEN..]; + let state_nxt = &main_trace.chiplet_hasher_state(row - 1)[CAPACITY_LEN..]; header + build_value(&alphas[8..16], state_nxt) - build_value(&alphas[8..16], state) } @@ -345,10 +347,10 @@ fn build_respan_block_request>( fn build_end_block_request>( main_trace: &MainTrace, alphas: &[E], - i: usize, + row: usize, ) -> E { let op_label = RETURN_HASH_LABEL; - let addr = main_trace.addr(i) + Felt::from(NUM_ROUNDS as u8); + let addr = main_trace.addr(row) + Felt::from(NUM_ROUNDS as u8); let first_cycle_row = addr_to_row_index(addr) % HASH_CYCLE_LEN == 0; let transition_label = if first_cycle_row { op_label + 16 } else { op_label + 32 }; @@ -356,7 +358,7 @@ fn build_end_block_request>( let header = alphas[0] + alphas[1].mul_base(Felt::from(transition_label)) + alphas[2].mul_base(addr); - let state = main_trace.decoder_hasher_state(i); + let state = main_trace.decoder_hasher_state(row); let digest = &state[..4]; header + build_value(&alphas[8..12], digest) @@ -368,12 +370,12 @@ fn build_bitwise_request>( main_trace: &MainTrace, is_xor: Felt, alphas: &[E], - i: usize, + row: usize, ) -> E { let op_label = get_op_label(ONE, ZERO, is_xor, ZERO); - let a = main_trace.stack_element(1, i); - let b = main_trace.stack_element(0, i); - let z = main_trace.stack_element(0, i + 1); + let a = main_trace.stack_element(1, row); + let b = main_trace.stack_element(0, row); + let z = main_trace.stack_element(0, row + 1); alphas[0] + alphas[1].mul_base(op_label) @@ -382,87 +384,90 @@ fn build_bitwise_request>( + alphas[4].mul_base(z) } -/// Builds `MLOAD*` and `MSTORE*` requests made to the memory chiplet. -fn build_mem_request>( +/// Builds `MLOAD` and `MSTORE` requests made to the memory chiplet. +fn build_mem_request_element>( main_trace: &MainTrace, op_label: u8, - word: bool, alphas: &[E], - i: usize, + row: usize, ) -> E { - let ctx = main_trace.ctx(i); - let clk = main_trace.clk(i); - - let (v0, v1, v2, v3) = if word { - ( - main_trace.stack_element(0, i + 1), - main_trace.stack_element(1, i + 1), - main_trace.stack_element(2, i + 1), - main_trace.stack_element(3, i + 1), - ) - } else { - ( - main_trace.helper_0(i), - main_trace.helper_1(i), - main_trace.helper_2(i), - main_trace.stack_element(0, i + 1), - ) - }; + let word = [ + main_trace.stack_element(0, row + 1), + main_trace.helper_register(2, row), + main_trace.helper_register(1, row), + main_trace.helper_register(0, row), + ]; + let addr = main_trace.stack_element(0, row); - let s0_cur = main_trace.stack_element(0, i); + compute_memory_request(main_trace, op_label, alphas, row, addr, word) +} - alphas[0] - + alphas[1].mul_base(Felt::from(op_label)) - + alphas[2].mul_base(ctx) - + alphas[3].mul_base(s0_cur) - + alphas[4].mul_base(clk) - + alphas[5].mul_base(v3) - + alphas[6].mul_base(v2) - + alphas[7].mul_base(v1) - + alphas[8].mul_base(v0) +/// Builds `MLOADW` and `MSTOREW` requests made to the memory chiplet. +fn build_mem_request_word>( + main_trace: &MainTrace, + op_label: u8, + alphas: &[E], + row: usize, +) -> E { + let word = [ + main_trace.stack_element(3, row + 1), + main_trace.stack_element(2, row + 1), + main_trace.stack_element(1, row + 1), + main_trace.stack_element(0, row + 1), + ]; + let addr = main_trace.stack_element(0, row); + + compute_memory_request(main_trace, op_label, alphas, row, addr, word) } /// Builds `MSTREAM` requests made to the memory chiplet. fn build_mstream_request>( main_trace: &MainTrace, alphas: &[E], - i: usize, + row: usize, ) -> E { - let ctx = main_trace.ctx(i); - let clk = main_trace.clk(i); + let word1 = [ + main_trace.stack_element(7, row + 1), + main_trace.stack_element(6, row + 1), + main_trace.stack_element(5, row + 1), + main_trace.stack_element(4, row + 1), + ]; + let word2 = [ + main_trace.stack_element(3, row + 1), + main_trace.stack_element(2, row + 1), + main_trace.stack_element(1, row + 1), + main_trace.stack_element(0, row + 1), + ]; + let addr = main_trace.stack_element(12, row); + let op_label = MEMORY_READ_LABEL; - let s0_nxt = main_trace.stack_element(0, i + 1); - let s1_nxt = main_trace.stack_element(1, i + 1); - let s2_nxt = main_trace.stack_element(2, i + 1); - let s3_nxt = main_trace.stack_element(3, i + 1); - let s4_nxt = main_trace.stack_element(4, i + 1); - let s5_nxt = main_trace.stack_element(5, i + 1); - let s6_nxt = main_trace.stack_element(6, i + 1); - let s7_nxt = main_trace.stack_element(7, i + 1); + let factor1 = compute_memory_request(main_trace, op_label, alphas, row, addr, word1); + let factor2 = compute_memory_request(main_trace, op_label, alphas, row, addr + ONE, word2); - let s12_cur = main_trace.stack_element(12, i); + factor1 * factor2 +} +/// Builds `RCOMBBASE` requests made to the memory chiplet. +fn build_rcomb_base_request>( + main_trace: &MainTrace, + alphas: &[E], + row: usize, +) -> E { + let tz0 = main_trace.helper_register(0, row); + let tz1 = main_trace.helper_register(1, row); + let tzg0 = main_trace.helper_register(2, row); + let tzg1 = main_trace.helper_register(3, row); + let a0 = main_trace.helper_register(4, row); + let a1 = main_trace.helper_register(5, row); + let z_ptr = main_trace.stack_element(13, row); + let a_ptr = main_trace.stack_element(14, row); let op_label = MEMORY_READ_LABEL; - let factor1 = alphas[0] - + alphas[1].mul_base(Felt::from(op_label)) - + alphas[2].mul_base(ctx) - + alphas[3].mul_base(s12_cur) - + alphas[4].mul_base(clk) - + alphas[5].mul_base(s7_nxt) - + alphas[6].mul_base(s6_nxt) - + alphas[7].mul_base(s5_nxt) - + alphas[8].mul_base(s4_nxt); + let factor1 = + compute_memory_request(main_trace, op_label, alphas, row, z_ptr, [tz0, tz1, tzg0, tzg1]); + let factor2 = + compute_memory_request(main_trace, op_label, alphas, row, a_ptr, [a0, a1, ZERO, ZERO]); - let factor2 = alphas[0] - + alphas[1].mul_base(Felt::from(op_label)) - + alphas[2].mul_base(ctx) - + alphas[3].mul_base(s12_cur + ONE) - + alphas[4].mul_base(clk) - + alphas[5].mul_base(s3_nxt) - + alphas[6].mul_base(s2_nxt) - + alphas[7].mul_base(s1_nxt) - + alphas[8].mul_base(s0_nxt); factor1 * factor2 } @@ -470,38 +475,38 @@ fn build_mstream_request>( fn build_hperm_request>( main_trace: &MainTrace, alphas: &[E], - i: usize, + row: usize, ) -> E { - let helper_0 = main_trace.helper_0(i); + let helper_0 = main_trace.helper_register(0, row); let s0_s12_cur = [ - main_trace.stack_element(0, i), - main_trace.stack_element(1, i), - main_trace.stack_element(2, i), - main_trace.stack_element(3, i), - main_trace.stack_element(4, i), - main_trace.stack_element(5, i), - main_trace.stack_element(6, i), - main_trace.stack_element(7, i), - main_trace.stack_element(8, i), - main_trace.stack_element(9, i), - main_trace.stack_element(10, i), - main_trace.stack_element(11, i), + main_trace.stack_element(0, row), + main_trace.stack_element(1, row), + main_trace.stack_element(2, row), + main_trace.stack_element(3, row), + main_trace.stack_element(4, row), + main_trace.stack_element(5, row), + main_trace.stack_element(6, row), + main_trace.stack_element(7, row), + main_trace.stack_element(8, row), + main_trace.stack_element(9, row), + main_trace.stack_element(10, row), + main_trace.stack_element(11, row), ]; let s0_s12_nxt = [ - main_trace.stack_element(0, i + 1), - main_trace.stack_element(1, i + 1), - main_trace.stack_element(2, i + 1), - main_trace.stack_element(3, i + 1), - main_trace.stack_element(4, i + 1), - main_trace.stack_element(5, i + 1), - main_trace.stack_element(6, i + 1), - main_trace.stack_element(7, i + 1), - main_trace.stack_element(8, i + 1), - main_trace.stack_element(9, i + 1), - main_trace.stack_element(10, i + 1), - main_trace.stack_element(11, i + 1), + main_trace.stack_element(0, row + 1), + main_trace.stack_element(1, row + 1), + main_trace.stack_element(2, row + 1), + main_trace.stack_element(3, row + 1), + main_trace.stack_element(4, row + 1), + main_trace.stack_element(5, row + 1), + main_trace.stack_element(6, row + 1), + main_trace.stack_element(7, row + 1), + main_trace.stack_element(8, row + 1), + main_trace.stack_element(9, row + 1), + main_trace.stack_element(10, row + 1), + main_trace.stack_element(11, row + 1), ]; let op_label = LINEAR_HASH_LABEL; @@ -545,23 +550,23 @@ fn build_hperm_request>( fn build_mpverify_request>( main_trace: &MainTrace, alphas: &[E], - i: usize, + row: usize, ) -> E { - let helper_0 = main_trace.helper_0(i); + let helper_0 = main_trace.helper_register(0, row); let s0_s3 = [ - main_trace.stack_element(0, i), - main_trace.stack_element(1, i), - main_trace.stack_element(2, i), - main_trace.stack_element(3, i), + main_trace.stack_element(0, row), + main_trace.stack_element(1, row), + main_trace.stack_element(2, row), + main_trace.stack_element(3, row), ]; - let s4 = main_trace.stack_element(4, i); - let s5 = main_trace.stack_element(5, i); + let s4 = main_trace.stack_element(4, row); + let s5 = main_trace.stack_element(5, row); let s6_s9 = [ - main_trace.stack_element(6, i), - main_trace.stack_element(7, i), - main_trace.stack_element(8, i), - main_trace.stack_element(9, i), + main_trace.stack_element(6, row), + main_trace.stack_element(7, row), + main_trace.stack_element(8, row), + main_trace.stack_element(9, row), ]; let op_label = MP_VERIFY_LABEL; @@ -607,35 +612,35 @@ fn build_mpverify_request>( fn build_mrupdate_request>( main_trace: &MainTrace, alphas: &[E], - i: usize, + row: usize, ) -> E { - let helper_0 = main_trace.helper_0(i); + let helper_0 = main_trace.helper_register(0, row); let s0_s3 = [ - main_trace.stack_element(0, i), - main_trace.stack_element(1, i), - main_trace.stack_element(2, i), - main_trace.stack_element(3, i), + main_trace.stack_element(0, row), + main_trace.stack_element(1, row), + main_trace.stack_element(2, row), + main_trace.stack_element(3, row), ]; let s0_s3_nxt = [ - main_trace.stack_element(0, i + 1), - main_trace.stack_element(1, i + 1), - main_trace.stack_element(2, i + 1), - main_trace.stack_element(3, i + 1), + main_trace.stack_element(0, row + 1), + main_trace.stack_element(1, row + 1), + main_trace.stack_element(2, row + 1), + main_trace.stack_element(3, row + 1), ]; - let s4 = main_trace.stack_element(4, i); - let s5 = main_trace.stack_element(5, i); + let s4 = main_trace.stack_element(4, row); + let s5 = main_trace.stack_element(5, row); let s6_s9 = [ - main_trace.stack_element(6, i), - main_trace.stack_element(7, i), - main_trace.stack_element(8, i), - main_trace.stack_element(9, i), + main_trace.stack_element(6, row), + main_trace.stack_element(7, row), + main_trace.stack_element(8, row), + main_trace.stack_element(9, row), ]; let s10_s13 = [ - main_trace.stack_element(10, i), - main_trace.stack_element(11, i), - main_trace.stack_element(12, i), - main_trace.stack_element(13, i), + main_trace.stack_element(10, row), + main_trace.stack_element(11, row), + main_trace.stack_element(12, row), + main_trace.stack_element(13, row), ]; let op_label = MR_UPDATE_OLD_LABEL; @@ -716,7 +721,7 @@ fn build_mrupdate_request>( /// Builds the response from the hasher chiplet at row `i`. fn build_hasher_chiplet_responses( main_trace: &MainTrace, - i: usize, + row: usize, alphas: &[E], selector1: Felt, selector2: Felt, @@ -726,14 +731,14 @@ where E: FieldElement, { let mut multiplicand = E::ONE; - let selector0 = main_trace.chiplet_selector_0(i); + let selector0 = main_trace.chiplet_selector_0(row); let op_label = get_op_label(selector0, selector1, selector2, selector3); // f_bp, f_mp, f_mv or f_mu == 1 - if i % HASH_CYCLE_LEN == 0 { - let state = main_trace.chiplet_hasher_state(i); + if row % HASH_CYCLE_LEN == 0 { + let state = main_trace.chiplet_hasher_state(row); let alphas_state = &alphas[NUM_HEADER_ALPHAS..(NUM_HEADER_ALPHAS + STATE_WIDTH)]; - let node_index = main_trace.chiplet_node_index(i); + let node_index = main_trace.chiplet_node_index(row); let transition_label = op_label + Felt::from(16_u8); // f_bp == 1 @@ -741,7 +746,7 @@ where if selector1 == ONE && selector2 == ZERO && selector3 == ZERO { let header = alphas[0] + alphas[1].mul_base(transition_label) - + alphas[2].mul_base(Felt::from((i + 1) as u64)) + + alphas[2].mul_base(Felt::from((row + 1) as u64)) + alphas[3].mul_base(node_index); multiplicand = header + build_value(alphas_state, &state); @@ -752,7 +757,7 @@ where if selector1 == ONE && !(selector2 == ZERO && selector3 == ZERO) { let header = alphas[0] + alphas[1].mul_base(transition_label) - + alphas[2].mul_base(Felt::from((i + 1) as u64)) + + alphas[2].mul_base(Felt::from((row + 1) as u64)) + alphas[3].mul_base(node_index); let bit = node_index.as_int() & 1; @@ -764,10 +769,10 @@ where } // f_hout, f_sout, f_abp == 1 - if i % HASH_CYCLE_LEN == HASH_CYCLE_LEN - 1 { - let state = main_trace.chiplet_hasher_state(i); + if row % HASH_CYCLE_LEN == HASH_CYCLE_LEN - 1 { + let state = main_trace.chiplet_hasher_state(row); let alphas_state = &alphas[NUM_HEADER_ALPHAS..(NUM_HEADER_ALPHAS + STATE_WIDTH)]; - let node_index = main_trace.chiplet_node_index(i); + let node_index = main_trace.chiplet_node_index(row); let transition_label = op_label + Felt::from(32_u8); // f_hout == 1 @@ -775,7 +780,7 @@ where if selector1 == ZERO && selector2 == ZERO && selector3 == ZERO { let header = alphas[0] + alphas[1].mul_base(transition_label) - + alphas[2].mul_base(Felt::from((i + 1) as u64)) + + alphas[2].mul_base(Felt::from((row + 1) as u64)) + alphas[3].mul_base(node_index); multiplicand = header + build_value(&alphas_state[DIGEST_RANGE], &state[DIGEST_RANGE]); @@ -786,7 +791,7 @@ where if selector1 == ZERO && selector2 == ZERO && selector3 == ONE { let header = alphas[0] + alphas[1].mul_base(transition_label) - + alphas[2].mul_base(Felt::from((i + 1) as u64)) + + alphas[2].mul_base(Felt::from((row + 1) as u64)) + alphas[3].mul_base(node_index); multiplicand = header + build_value(alphas_state, &state); @@ -797,10 +802,10 @@ where if selector1 == ONE && selector2 == ZERO && selector3 == ZERO { let header = alphas[0] + alphas[1].mul_base(transition_label) - + alphas[2].mul_base(Felt::from((i + 1) as u64)) + + alphas[2].mul_base(Felt::from((row + 1) as u64)) + alphas[3].mul_base(node_index); - let state_nxt = main_trace.chiplet_hasher_state(i + 1); + let state_nxt = main_trace.chiplet_hasher_state(row + 1); // build the value from the difference of the hasher state's just before and right // after the absorption of new elements. @@ -817,19 +822,19 @@ where /// Builds the response from the bitwise chiplet at row `i`. fn build_bitwise_chiplet_responses( main_trace: &MainTrace, - i: usize, + row: usize, is_xor: Felt, alphas: &[E], ) -> E where E: FieldElement, { - if i % BITWISE_OP_CYCLE_LEN == BITWISE_OP_CYCLE_LEN - 1 { + if row % BITWISE_OP_CYCLE_LEN == BITWISE_OP_CYCLE_LEN - 1 { let op_label = get_op_label(ONE, ZERO, is_xor, ZERO); - let a = main_trace.chiplet_bitwise_a(i); - let b = main_trace.chiplet_bitwise_b(i); - let z = main_trace.chiplet_bitwise_z(i); + let a = main_trace.chiplet_bitwise_a(row); + let b = main_trace.chiplet_bitwise_b(row); + let z = main_trace.chiplet_bitwise_z(row); alphas[0] + alphas[1].mul_base(op_label) @@ -844,7 +849,7 @@ where /// Builds the response from the memory chiplet at row `i`. fn build_memory_chiplet_responses( main_trace: &MainTrace, - i: usize, + row: usize, is_read: Felt, alphas: &[E], ) -> E @@ -853,13 +858,13 @@ where { let op_label = get_op_label(ONE, ONE, ZERO, is_read); - let ctx = main_trace.chiplet_memory_ctx(i); - let clk = main_trace.chiplet_memory_clk(i); - let addr = main_trace.chiplet_memory_addr(i); - let value0 = main_trace.chiplet_memory_value_0(i); - let value1 = main_trace.chiplet_memory_value_1(i); - let value2 = main_trace.chiplet_memory_value_2(i); - let value3 = main_trace.chiplet_memory_value_3(i); + let ctx = main_trace.chiplet_memory_ctx(row); + let clk = main_trace.chiplet_memory_clk(row); + let addr = main_trace.chiplet_memory_addr(row); + let value0 = main_trace.chiplet_memory_value_0(row); + let value1 = main_trace.chiplet_memory_value_1(row); + let value2 = main_trace.chiplet_memory_value_2(row); + let value3 = main_trace.chiplet_memory_value_3(row); alphas[0] + alphas[1].mul_base(op_label) @@ -873,16 +878,16 @@ where } /// Builds the response from the kernel chiplet at row `i`. -fn build_kernel_chiplet_responses(main_trace: &MainTrace, i: usize, alphas: &[E]) -> E +fn build_kernel_chiplet_responses(main_trace: &MainTrace, row: usize, alphas: &[E]) -> E where E: FieldElement, { let op_label = KERNEL_PROC_LABEL; - let root0 = main_trace.chiplet_kernel_root_0(i); - let root1 = main_trace.chiplet_kernel_root_1(i); - let root2 = main_trace.chiplet_kernel_root_2(i); - let root3 = main_trace.chiplet_kernel_root_3(i); + 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); alphas[0] + alphas[1].mul_base(op_label) @@ -892,6 +897,9 @@ where + alphas[5].mul_base(root3) } +// HELPER FUNCTIONS +// ================================================================================================ + /// Reduces a slice of elements to a single field element in the field specified by E using a slice /// of alphas of matching length. This can be used to build the value for a single word or for an /// entire [HasherState]. @@ -922,3 +930,27 @@ fn addr_to_hash_cycle(addr: Felt) -> usize { fn addr_to_row_index(addr: Felt) -> usize { (addr.as_int() - 1) as usize } + +/// Computes a memory read or write request at `row` given randomness `alphas`, memory address +/// `addr` and value `value`. +fn compute_memory_request>( + main_trace: &MainTrace, + op_label: u8, + alphas: &[E], + row: usize, + addr: Felt, + value: Word, +) -> E { + let ctx = main_trace.ctx(row); + let clk = main_trace.clk(row); + + alphas[0] + + alphas[1].mul_base(Felt::from(op_label)) + + alphas[2].mul_base(ctx) + + alphas[3].mul_base(addr) + + alphas[4].mul_base(clk) + + alphas[5].mul_base(value[0]) + + alphas[6].mul_base(value[1]) + + alphas[7].mul_base(value[2]) + + alphas[8].mul_base(value[3]) +} diff --git a/processor/src/operations/comb_ops.rs b/processor/src/operations/comb_ops.rs index 4ed3172472..fda90f3337 100644 --- a/processor/src/operations/comb_ops.rs +++ b/processor/src/operations/comb_ops.rs @@ -1,10 +1,10 @@ -// RANDOM LINEAR COMBINATION OPERATIONS -// ================================================================================================ - use vm_core::{Felt, Operation, StarkField, ONE, ZERO}; use crate::{ExecutionError, Host, Process, QuadFelt}; +// RANDOM LINEAR COMBINATION OPERATIONS +// ================================================================================================ + impl Process where H: Host,