diff --git a/cpp/pil/avm/avm_binary.pil b/cpp/pil/avm/avm_binary.pil new file mode 100644 index 000000000..6ef9c3b4c --- /dev/null +++ b/cpp/pil/avm/avm_binary.pil @@ -0,0 +1,81 @@ + +include "avm_byte_lookup.pil"; +include "avm_main.pil"; + +namespace avm_binary(256); + + pol commit bin_clk; + + // Selector for Binary Operation + pol commit bin_sel; + bin_sel * (1 - bin_sel) = 0; + + // Byte recomposition column, the value in these columns are part of the equivalence + // check to main wherever Start is set to 1. + pol commit acc_ia; + pol commit acc_ib; + pol commit acc_ic; + + // This is the instruction tag {1,2,3,4,5} (restricted to not be a field) + // Operations over FF are not supported, it is assumed this exclusion is handled + // outside of this subtrace. + + // Constraints come from equiv to main_trace + pol commit in_tag; + + // Selectors for binary operations, correctness checked by permutation to the main trace. + // Op Id is restricted to be the same during the same computation (i.e. between Starts) + pol commit op_id; + #[OP_ID_REL] + (op_id' - op_id) * mem_tag_ctr = 0; + + // Little Endian bitwise decomposition of accumulators (which are processed top-down), + // constrained to be U8 given by the lookup to the avm_byte_lookup + pol commit bin_ia_bytes; + pol commit bin_ib_bytes; + pol commit bin_ic_bytes; + + pol commit start; // Identifies when we want to capture the output to the main trace. + + + // To support dynamically sized memory operands we use a counter against a lookup + // This decrementing counter goes from [MEM_TAG, 0] where MEM_TAG is the number of bytes in the + // corresponding integer. i.e. MEM_TAG is between 1 (U8) and 16(U128). + // Consistency can be achieved with a lookup table between the instr_tag and bytes_length + pol commit mem_tag_ctr; + #[MEM_TAG_REL] + (mem_tag_ctr' - mem_tag_ctr + 1) * mem_tag_ctr = 0; + + // Bin_sel is a boolean that is set to 1 if mem_tag_ctr != 0. + // This is checked by two relation conditions and utilising mem_tag_ctr_inv + pol commit mem_tag_ctr_inv; + + // bin_sel is set to 1 when mem_tag_ctr != 0, and 0 otherwise. + // we constrain it such that bin_sel = mem_tag_ctr * mem_tag_ctr_inv unless mem_tag_ctr = 0 the bin_sel = 0 + // In here we use the consolidated equality relation because it doesnt require us to enforce + // this additional relation: mem_tag_ctr_inv = 1 when mem_tag_ctr = 0. (allows default zero value in trace) + #[BIN_SEL_CTR_REL] + mem_tag_ctr * ((1 - bin_sel) * (1 - mem_tag_ctr_inv) + mem_tag_ctr_inv) - bin_sel = 0; + + // Forces accumulator to start at zero when mem_tag_ctr == 0 + (1 - bin_sel) * acc_ia = 0; + (1 - bin_sel) * acc_ib = 0; + (1 - bin_sel) * acc_ic = 0; + + #[LOOKUP_BYTE_LENGTHS] + start {in_tag, mem_tag_ctr} + in + avm_byte_lookup.bin_sel {avm_byte_lookup.table_in_tags, avm_byte_lookup.table_byte_lengths}; + + #[LOOKUP_BYTE_OPERATIONS] + bin_sel {op_id, bin_ia_bytes, bin_ib_bytes, bin_ic_bytes} + in + avm_byte_lookup.bin_sel {avm_byte_lookup.table_op_id, avm_byte_lookup.table_input_a, avm_byte_lookup.table_input_b, avm_byte_lookup.table_output}; + + #[ACC_REL_A] + (acc_ia - bin_ia_bytes - 256 * acc_ia') * mem_tag_ctr = 0; + #[ACC_REL_B] + (acc_ib - bin_ib_bytes - 256 * acc_ib') * mem_tag_ctr = 0; + #[ACC_REL_C] + (acc_ic - bin_ic_bytes - 256 * acc_ic') * mem_tag_ctr = 0; + diff --git a/cpp/pil/avm/avm_byte_lookup.pil b/cpp/pil/avm/avm_byte_lookup.pil new file mode 100644 index 000000000..d06135389 --- /dev/null +++ b/cpp/pil/avm/avm_byte_lookup.pil @@ -0,0 +1,16 @@ + +namespace avm_byte_lookup(256); + // These columns are commited for now, but will be migrated to constant/fixed when + // we support more *exotic* code generation options + pol commit table_op_id; // identifies if operation is AND/OR/XOR + pol commit table_input_a; // column of all 8-bit numbers + pol commit table_input_b; // column of all 8-bit numbers + pol commit table_output; // output = a AND/OR/XOR b + // Selector to indicate when to utilise the lookup table + // TODO: Support for 1-sided lookups may make this redundant. + pol commit bin_sel; + + // These two columns are a mapping between instruction tags and their byte lengths + // {U8: 1, U16: 2, ... , U128: 16} + pol commit table_in_tags; // Column of U8,U16,...,U128 + pol commit table_byte_lengths; // Columns of byte lengths 1,2,...,16; diff --git a/cpp/pil/avm/avm_main.pil b/cpp/pil/avm/avm_main.pil index 02b102fa4..ac13de747 100644 --- a/cpp/pil/avm/avm_main.pil +++ b/cpp/pil/avm/avm_main.pil @@ -1,6 +1,7 @@ include "avm_mem.pil"; include "avm_alu.pil"; +include "avm_binary.pil"; namespace avm_main(256); @@ -41,10 +42,19 @@ namespace avm_main(256); pol commit sel_op_not; // EQ pol commit sel_op_eq; + // AND + pol commit sel_op_and; + // OR + pol commit sel_op_or; + // XOR + pol commit sel_op_xor; // Helper selector to characterize an ALU chiplet selector pol commit alu_sel; + // Helper selector to characterize a Binary chiplet selector + pol commit bin_sel; + // Instruction memory tag (1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6: field) pol commit in_tag; @@ -102,6 +112,9 @@ namespace avm_main(256); sel_op_div * (1 - sel_op_div) = 0; sel_op_not * (1 - sel_op_not) = 0; sel_op_eq * (1 - sel_op_eq) = 0; + sel_op_and * (1 - sel_op_and) = 0; + sel_op_or * (1 - sel_op_or) = 0; + sel_op_xor * (1 - sel_op_xor) = 0; sel_internal_call * (1 - sel_internal_call) = 0; sel_internal_return * (1 - sel_internal_return) = 0; @@ -202,7 +215,7 @@ namespace avm_main(256); //===== CONTROL_FLOW_CONSISTENCY ============================================ pol INTERNAL_CALL_STACK_SELECTORS = (first + sel_internal_call + sel_internal_return + sel_halt); - pol OPCODE_SELECTORS = (sel_op_add + sel_op_sub + sel_op_div + sel_op_mul + sel_op_not + sel_op_eq); + pol OPCODE_SELECTORS = (sel_op_add + sel_op_sub + sel_op_div + sel_op_mul + sel_op_not + sel_op_eq + sel_op_and + sel_op_or + sel_op_xor); // Program counter must increment if not jumping or returning #[PC_INCREMENT] @@ -239,6 +252,26 @@ namespace avm_main(256); avm_alu.alu_op_add, avm_alu.alu_op_sub, avm_alu.alu_op_mul, avm_alu.alu_op_eq, avm_alu.alu_op_not, avm_alu.alu_in_tag}; + + // Based on the boolean selectors, we derive the binary op id to lookup in the table; + // TODO: Check if having 4 columns (op_id + 3 boolean selectors) is more optimal that just using the op_id + // but with a higher degree constraint: op_id * (op_id - 1) * (op_id - 2) + pol commit bin_op_id; + #[BIN_SEL_1] + bin_op_id = sel_op_or + 2 * sel_op_xor; // sel_op_and excluded since op_id = 0 for op_and + + // Only 1 of the binary selectors should be set (i.e. Mutual Exclusivity) + // Bin_sel is not explicitly constrained to be boolean, however this is enforced through + // the operation decomposition step during bytecode unpacking. + #[BIN_SEL_2] + bin_sel = sel_op_and + sel_op_or + sel_op_xor; + + #[PERM_MAIN_BIN] + bin_sel {ia, ib, ic, bin_op_id, in_tag} + is + avm_binary.start {avm_binary.acc_ia, avm_binary.acc_ib, avm_binary.acc_ic, + avm_binary.op_id, avm_binary.in_tag}; + #[PERM_MAIN_MEM_A] mem_op_a {clk, mem_idx_a, ia, rwa, in_tag, sel_mov} is @@ -267,4 +300,4 @@ namespace avm_main(256); #[PERM_MAIN_MEM_IND_C] ind_op_c {clk, ind_c, mem_idx_c} is - avm_mem.m_ind_op_c {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val}; \ No newline at end of file + avm_mem.m_ind_op_c {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val}; diff --git a/cpp/pil/avm/avm_mem.pil b/cpp/pil/avm/avm_mem.pil index 2f2af7297..f6d995b03 100644 --- a/cpp/pil/avm/avm_mem.pil +++ b/cpp/pil/avm/avm_mem.pil @@ -147,4 +147,4 @@ namespace avm_mem(256); // Finally, the following constraint guarantees that m_tag is correct for // the output. #[MOV_SAME_TAG] - m_sel_mov * m_tag_err = 0; // Equivalent to m_sel_mov * (m_in_tag - m_tag) = 0 \ No newline at end of file + m_sel_mov * m_tag_err = 0; // Equivalent to m_sel_mov * (m_in_tag - m_tag) = 0 diff --git a/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp b/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp index fc1970fc8..654dbdd83 100644 --- a/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp +++ b/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp @@ -7,77 +7,77 @@ namespace bb::Avm_vm { template struct Avm_aluRow { - FF avm_alu_alu_u16_r7_shift{}; - FF avm_alu_alu_u8_tag{}; - FF avm_alu_alu_u128_tag{}; - FF avm_alu_alu_ib{}; + FF avm_alu_alu_u8_r0{}; + FF avm_alu_alu_op_eq_diff_inv{}; + FF avm_alu_alu_op_eq{}; + FF avm_alu_alu_u16_r3{}; + FF avm_alu_alu_u64_r0{}; FF avm_alu_alu_u16_r4{}; - FF avm_alu_alu_u16_r0{}; + FF avm_alu_alu_u16_r3_shift{}; + FF avm_alu_alu_u16_r6_shift{}; + FF avm_alu_alu_u16_r0_shift{}; FF avm_alu_alu_u16_r1_shift{}; - FF avm_alu_alu_op_mul{}; - FF avm_alu_alu_u16_tag{}; - FF avm_alu_alu_u16_r2{}; FF avm_alu_alu_u16_r1{}; - FF avm_alu_alu_u16_r3{}; FF avm_alu_alu_in_tag{}; - FF avm_alu_alu_u8_r1{}; - FF avm_alu_alu_u16_r7{}; + FF avm_alu_alu_cf{}; + FF avm_alu_alu_op_not{}; FF avm_alu_alu_u16_r6{}; - FF avm_alu_alu_op_eq{}; - FF avm_alu_alu_u64_tag{}; + FF avm_alu_alu_ib{}; + FF avm_alu_alu_op_add{}; + FF avm_alu_alu_u128_tag{}; + FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_sel{}; + FF avm_alu_alu_u16_r7_shift{}; + FF avm_alu_alu_u16_r7{}; + FF avm_alu_alu_u16_r0{}; + FF avm_alu_alu_u32_tag{}; FF avm_alu_alu_ia{}; FF avm_alu_alu_ic{}; + FF avm_alu_alu_u8_tag{}; + FF avm_alu_alu_u8_r1{}; + FF avm_alu_alu_u16_r4_shift{}; FF avm_alu_alu_u16_r5_shift{}; - FF avm_alu_alu_op_eq_diff_inv{}; - FF avm_alu_alu_op_add{}; + FF avm_alu_alu_u16_r2{}; + FF avm_alu_alu_op_mul{}; FF avm_alu_alu_ff_tag{}; - FF avm_alu_alu_u16_r5{}; - FF avm_alu_alu_u32_tag{}; - FF avm_alu_alu_u16_r6_shift{}; + FF avm_alu_alu_u64_tag{}; FF avm_alu_alu_op_sub{}; - FF avm_alu_alu_u16_r0_shift{}; - FF avm_alu_alu_u16_r4_shift{}; - FF avm_alu_alu_u8_r0{}; - FF avm_alu_alu_op_not{}; - FF avm_alu_alu_u16_r2_shift{}; - FF avm_alu_alu_u16_r3_shift{}; - FF avm_alu_alu_u64_r0{}; - FF avm_alu_alu_sel{}; - FF avm_alu_alu_cf{}; + FF avm_alu_alu_u16_tag{}; + FF avm_alu_alu_u16_r5{}; }; inline std::string get_relation_label_avm_alu(int index) { switch (index) { - case 19: - return "ALU_RES_IS_BOOL"; - case 20: return "ALU_OP_EQ"; case 13: return "ALU_MUL_COMMON_2"; - case 11: - return "ALU_MULTIPLICATION_FF"; - - case 10: - return "ALU_ADD_SUB_2"; - case 16: return "ALU_MULTIPLICATION_OUT_U128"; case 18: return "ALU_OP_NOT"; + case 19: + return "ALU_RES_IS_BOOL"; + + case 11: + return "ALU_MULTIPLICATION_FF"; + + case 12: + return "ALU_MUL_COMMON_1"; + case 9: return "ALU_ADD_SUB_1"; case 17: return "ALU_FF_NOT_XOR"; - case 12: - return "ALU_MUL_COMMON_1"; + case 10: + return "ALU_ADD_SUB_2"; } return std::to_string(index); } diff --git a/cpp/src/barretenberg/relations/generated/avm/avm_binary.hpp b/cpp/src/barretenberg/relations/generated/avm/avm_binary.hpp new file mode 100644 index 000000000..4d5179c65 --- /dev/null +++ b/cpp/src/barretenberg/relations/generated/avm/avm_binary.hpp @@ -0,0 +1,157 @@ + +#pragma once +#include "../../relation_parameters.hpp" +#include "../../relation_types.hpp" +#include "./declare_views.hpp" + +namespace bb::Avm_vm { + +template struct Avm_binaryRow { + FF avm_binary_bin_sel{}; + FF avm_binary_acc_ib{}; + FF avm_binary_mem_tag_ctr{}; + FF avm_binary_bin_ic_bytes{}; + FF avm_binary_acc_ic_shift{}; + FF avm_binary_acc_ia{}; + FF avm_binary_op_id_shift{}; + FF avm_binary_acc_ia_shift{}; + FF avm_binary_op_id{}; + FF avm_binary_mem_tag_ctr_shift{}; + FF avm_binary_acc_ic{}; + FF avm_binary_bin_ia_bytes{}; + FF avm_binary_bin_ib_bytes{}; + FF avm_binary_mem_tag_ctr_inv{}; + FF avm_binary_acc_ib_shift{}; +}; + +inline std::string get_relation_label_avm_binary(int index) +{ + switch (index) { + case 1: + return "OP_ID_REL"; + + case 7: + return "ACC_REL_A"; + + case 8: + return "ACC_REL_B"; + + case 9: + return "ACC_REL_C"; + + case 3: + return "BIN_SEL_CTR_REL"; + + case 2: + return "MEM_TAG_REL"; + } + return std::to_string(index); +} + +template class avm_binaryImpl { + public: + using FF = FF_; + + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 4, 3, 3, 3, 4, 4, 4, + }; + + template + void static accumulate(ContainerOverSubrelations& evals, + const AllEntities& new_term, + [[maybe_unused]] const RelationParameters&, + [[maybe_unused]] const FF& scaling_factor) + { + + // Contribution 0 + { + Avm_DECLARE_VIEWS(0); + + auto tmp = (avm_binary_bin_sel * (-avm_binary_bin_sel + FF(1))); + tmp *= scaling_factor; + std::get<0>(evals) += tmp; + } + // Contribution 1 + { + Avm_DECLARE_VIEWS(1); + + auto tmp = ((avm_binary_op_id_shift - avm_binary_op_id) * avm_binary_mem_tag_ctr); + tmp *= scaling_factor; + std::get<1>(evals) += tmp; + } + // Contribution 2 + { + Avm_DECLARE_VIEWS(2); + + auto tmp = (((avm_binary_mem_tag_ctr_shift - avm_binary_mem_tag_ctr) + FF(1)) * avm_binary_mem_tag_ctr); + tmp *= scaling_factor; + std::get<2>(evals) += tmp; + } + // Contribution 3 + { + Avm_DECLARE_VIEWS(3); + + auto tmp = + ((avm_binary_mem_tag_ctr * (((-avm_binary_bin_sel + FF(1)) * (-avm_binary_mem_tag_ctr_inv + FF(1))) + + avm_binary_mem_tag_ctr_inv)) - + avm_binary_bin_sel); + tmp *= scaling_factor; + std::get<3>(evals) += tmp; + } + // Contribution 4 + { + Avm_DECLARE_VIEWS(4); + + auto tmp = ((-avm_binary_bin_sel + FF(1)) * avm_binary_acc_ia); + tmp *= scaling_factor; + std::get<4>(evals) += tmp; + } + // Contribution 5 + { + Avm_DECLARE_VIEWS(5); + + auto tmp = ((-avm_binary_bin_sel + FF(1)) * avm_binary_acc_ib); + tmp *= scaling_factor; + std::get<5>(evals) += tmp; + } + // Contribution 6 + { + Avm_DECLARE_VIEWS(6); + + auto tmp = ((-avm_binary_bin_sel + FF(1)) * avm_binary_acc_ic); + tmp *= scaling_factor; + std::get<6>(evals) += tmp; + } + // Contribution 7 + { + Avm_DECLARE_VIEWS(7); + + auto tmp = (((avm_binary_acc_ia - avm_binary_bin_ia_bytes) - (avm_binary_acc_ia_shift * FF(256))) * + avm_binary_mem_tag_ctr); + tmp *= scaling_factor; + std::get<7>(evals) += tmp; + } + // Contribution 8 + { + Avm_DECLARE_VIEWS(8); + + auto tmp = (((avm_binary_acc_ib - avm_binary_bin_ib_bytes) - (avm_binary_acc_ib_shift * FF(256))) * + avm_binary_mem_tag_ctr); + tmp *= scaling_factor; + std::get<8>(evals) += tmp; + } + // Contribution 9 + { + Avm_DECLARE_VIEWS(9); + + auto tmp = (((avm_binary_acc_ic - avm_binary_bin_ic_bytes) - (avm_binary_acc_ic_shift * FF(256))) * + avm_binary_mem_tag_ctr); + tmp *= scaling_factor; + std::get<9>(evals) += tmp; + } + } +}; + +template using avm_binary = Relation>; + +} // namespace bb::Avm_vm \ No newline at end of file diff --git a/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index 713d12a89..316e839ed 100644 --- a/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -7,71 +7,82 @@ namespace bb::Avm_vm { template struct Avm_mainRow { - FF avm_main_ind_op_b{}; - FF avm_main_mem_idx_b{}; - FF avm_main_mem_idx_a{}; - FF avm_main_internal_return_ptr{}; - FF avm_main_sel_op_not{}; - FF avm_main_sel_op_mul{}; - FF avm_main_sel_op_add{}; - FF avm_main_sel_internal_call{}; - FF avm_main_mem_op_c{}; FF avm_main_internal_return_ptr_shift{}; + FF avm_main_sel_internal_return{}; + FF avm_main_sel_op_sub{}; + FF avm_main_ind_op_b{}; + FF avm_main_mem_op_a{}; + FF avm_main_op_err{}; + FF avm_main_sel_op_and{}; FF avm_main_mem_op_b{}; - FF avm_main_sel_halt{}; - FF avm_main_first{}; + FF avm_main_rwb{}; + FF avm_main_pc{}; + FF avm_main_bin_op_id{}; + FF avm_main_sel_op_xor{}; FF avm_main_rwa{}; - FF avm_main_ia{}; - FF avm_main_ib{}; + FF avm_main_rwc{}; + FF avm_main_ind_op_a{}; + FF avm_main_sel_mov{}; FF avm_main_sel_jump{}; - FF avm_main_sel_op_sub{}; - FF avm_main_alu_sel{}; FF avm_main_inv{}; - FF avm_main_pc_shift{}; - FF avm_main_ic{}; - FF avm_main_sel_internal_return{}; + FF avm_main_ia{}; FF avm_main_ind_op_c{}; - FF avm_main_tag_err{}; - FF avm_main_op_err{}; - FF avm_main_ind_op_a{}; - FF avm_main_pc{}; - FF avm_main_sel_mov{}; - FF avm_main_rwb{}; - FF avm_main_mem_op_a{}; - FF avm_main_rwc{}; + FF avm_main_internal_return_ptr{}; + FF avm_main_sel_internal_call{}; FF avm_main_sel_op_eq{}; + FF avm_main_tag_err{}; + FF avm_main_mem_idx_a{}; + FF avm_main_alu_sel{}; + FF avm_main_sel_op_or{}; + FF avm_main_sel_op_add{}; + FF avm_main_sel_op_mul{}; + FF avm_main_first{}; + FF avm_main_ib{}; + FF avm_main_bin_sel{}; + FF avm_main_pc_shift{}; + FF avm_main_ic{}; + FF avm_main_mem_op_c{}; + FF avm_main_mem_idx_b{}; FF avm_main_sel_op_div{}; + FF avm_main_sel_op_not{}; + FF avm_main_sel_halt{}; }; inline std::string get_relation_label_avm_main(int index) { switch (index) { - case 27: - return "RETURN_POINTER_INCREMENT"; - - case 23: - return "SUBOP_DIVISION_ZERO_ERR1"; + case 28: + return "SUBOP_ERROR_RELEVANT_OP"; - case 38: - return "PC_INCREMENT"; + case 25: + return "SUBOP_DIVISION_FF"; - case 24: + case 27: return "SUBOP_DIVISION_ZERO_ERR2"; - case 40: + case 42: + return "INTERNAL_RETURN_POINTER_CONSISTENCY"; + + case 43: return "MOV_SAME_VALUE"; - case 33: - return "RETURN_POINTER_DECREMENT"; + case 26: + return "SUBOP_DIVISION_ZERO_ERR1"; - case 22: - return "SUBOP_DIVISION_FF"; + case 46: + return "BIN_SEL_2"; - case 39: - return "INTERNAL_RETURN_POINTER_CONSISTENCY"; + case 45: + return "BIN_SEL_1"; - case 25: - return "SUBOP_ERROR_RELEVANT_OP"; + case 30: + return "RETURN_POINTER_INCREMENT"; + + case 41: + return "PC_INCREMENT"; + + case 36: + return "RETURN_POINTER_DECREMENT"; } return std::to_string(index); } @@ -80,9 +91,9 @@ template class avm_mainImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 2, }; template @@ -144,7 +155,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(6); - auto tmp = (avm_main_sel_internal_call * (-avm_main_sel_internal_call + FF(1))); + auto tmp = (avm_main_sel_op_and * (-avm_main_sel_op_and + FF(1))); tmp *= scaling_factor; std::get<6>(evals) += tmp; } @@ -152,7 +163,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(7); - auto tmp = (avm_main_sel_internal_return * (-avm_main_sel_internal_return + FF(1))); + auto tmp = (avm_main_sel_op_or * (-avm_main_sel_op_or + FF(1))); tmp *= scaling_factor; std::get<7>(evals) += tmp; } @@ -160,7 +171,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(8); - auto tmp = (avm_main_sel_jump * (-avm_main_sel_jump + FF(1))); + auto tmp = (avm_main_sel_op_xor * (-avm_main_sel_op_xor + FF(1))); tmp *= scaling_factor; std::get<8>(evals) += tmp; } @@ -168,7 +179,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(9); - auto tmp = (avm_main_sel_halt * (-avm_main_sel_halt + FF(1))); + auto tmp = (avm_main_sel_internal_call * (-avm_main_sel_internal_call + FF(1))); tmp *= scaling_factor; std::get<9>(evals) += tmp; } @@ -176,7 +187,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(10); - auto tmp = (avm_main_sel_mov * (-avm_main_sel_mov + FF(1))); + auto tmp = (avm_main_sel_internal_return * (-avm_main_sel_internal_return + FF(1))); tmp *= scaling_factor; std::get<10>(evals) += tmp; } @@ -184,7 +195,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(11); - auto tmp = (avm_main_op_err * (-avm_main_op_err + FF(1))); + auto tmp = (avm_main_sel_jump * (-avm_main_sel_jump + FF(1))); tmp *= scaling_factor; std::get<11>(evals) += tmp; } @@ -192,7 +203,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(12); - auto tmp = (avm_main_tag_err * (-avm_main_tag_err + FF(1))); + auto tmp = (avm_main_sel_halt * (-avm_main_sel_halt + FF(1))); tmp *= scaling_factor; std::get<12>(evals) += tmp; } @@ -200,7 +211,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(13); - auto tmp = (avm_main_mem_op_a * (-avm_main_mem_op_a + FF(1))); + auto tmp = (avm_main_sel_mov * (-avm_main_sel_mov + FF(1))); tmp *= scaling_factor; std::get<13>(evals) += tmp; } @@ -208,7 +219,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(14); - auto tmp = (avm_main_mem_op_b * (-avm_main_mem_op_b + FF(1))); + auto tmp = (avm_main_op_err * (-avm_main_op_err + FF(1))); tmp *= scaling_factor; std::get<14>(evals) += tmp; } @@ -216,7 +227,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(15); - auto tmp = (avm_main_mem_op_c * (-avm_main_mem_op_c + FF(1))); + auto tmp = (avm_main_tag_err * (-avm_main_tag_err + FF(1))); tmp *= scaling_factor; std::get<15>(evals) += tmp; } @@ -224,7 +235,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(16); - auto tmp = (avm_main_rwa * (-avm_main_rwa + FF(1))); + auto tmp = (avm_main_mem_op_a * (-avm_main_mem_op_a + FF(1))); tmp *= scaling_factor; std::get<16>(evals) += tmp; } @@ -232,7 +243,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(17); - auto tmp = (avm_main_rwb * (-avm_main_rwb + FF(1))); + auto tmp = (avm_main_mem_op_b * (-avm_main_mem_op_b + FF(1))); tmp *= scaling_factor; std::get<17>(evals) += tmp; } @@ -240,7 +251,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(18); - auto tmp = (avm_main_rwc * (-avm_main_rwc + FF(1))); + auto tmp = (avm_main_mem_op_c * (-avm_main_mem_op_c + FF(1))); tmp *= scaling_factor; std::get<18>(evals) += tmp; } @@ -248,7 +259,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(19); - auto tmp = (avm_main_ind_op_a * (-avm_main_ind_op_a + FF(1))); + auto tmp = (avm_main_rwa * (-avm_main_rwa + FF(1))); tmp *= scaling_factor; std::get<19>(evals) += tmp; } @@ -256,7 +267,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(20); - auto tmp = (avm_main_ind_op_b * (-avm_main_ind_op_b + FF(1))); + auto tmp = (avm_main_rwb * (-avm_main_rwb + FF(1))); tmp *= scaling_factor; std::get<20>(evals) += tmp; } @@ -264,7 +275,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(21); - auto tmp = (avm_main_ind_op_c * (-avm_main_ind_op_c + FF(1))); + auto tmp = (avm_main_rwc * (-avm_main_rwc + FF(1))); tmp *= scaling_factor; std::get<21>(evals) += tmp; } @@ -272,8 +283,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(22); - auto tmp = - ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); + auto tmp = (avm_main_ind_op_a * (-avm_main_ind_op_a + FF(1))); tmp *= scaling_factor; std::get<22>(evals) += tmp; } @@ -281,7 +291,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(23); - auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); + auto tmp = (avm_main_ind_op_b * (-avm_main_ind_op_b + FF(1))); tmp *= scaling_factor; std::get<23>(evals) += tmp; } @@ -289,7 +299,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(24); - auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); + auto tmp = (avm_main_ind_op_c * (-avm_main_ind_op_c + FF(1))); tmp *= scaling_factor; std::get<24>(evals) += tmp; } @@ -297,7 +307,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(25); - auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); + auto tmp = + ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); tmp *= scaling_factor; std::get<25>(evals) += tmp; } @@ -305,7 +316,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(26); - auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); tmp *= scaling_factor; std::get<26>(evals) += tmp; } @@ -313,8 +324,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(27); - auto tmp = (avm_main_sel_internal_call * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); + auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); tmp *= scaling_factor; std::get<27>(evals) += tmp; } @@ -322,7 +332,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(28); - auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); + auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); tmp *= scaling_factor; std::get<28>(evals) += tmp; } @@ -330,7 +340,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(29); - auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<29>(evals) += tmp; } @@ -338,7 +348,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(30); - auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); + auto tmp = (avm_main_sel_internal_call * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); tmp *= scaling_factor; std::get<30>(evals) += tmp; } @@ -346,7 +357,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(31); - auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); + auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); tmp *= scaling_factor; std::get<31>(evals) += tmp; } @@ -354,7 +365,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(32); - auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); + auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<32>(evals) += tmp; } @@ -362,8 +373,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(33); - auto tmp = (avm_main_sel_internal_return * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); + auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); tmp *= scaling_factor; std::get<33>(evals) += tmp; } @@ -371,7 +381,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(34); - auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); + auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); tmp *= scaling_factor; std::get<34>(evals) += tmp; } @@ -379,7 +389,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(35); - auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); tmp *= scaling_factor; std::get<35>(evals) += tmp; } @@ -387,7 +397,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(36); - auto tmp = (avm_main_sel_internal_return * avm_main_rwa); + auto tmp = (avm_main_sel_internal_return * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); tmp *= scaling_factor; std::get<36>(evals) += tmp; } @@ -395,7 +406,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(37); - auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); + auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); tmp *= scaling_factor; std::get<37>(evals) += tmp; } @@ -403,11 +414,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(38); - auto tmp = ((((-avm_main_first + FF(1)) * (-avm_main_sel_halt + FF(1))) * - (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_div) + avm_main_sel_op_mul) + - avm_main_sel_op_not) + - avm_main_sel_op_eq)) * - (avm_main_pc_shift - (avm_main_pc + FF(1)))); + auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<38>(evals) += tmp; } @@ -415,10 +422,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(39); - auto tmp = ((-(((avm_main_first + avm_main_sel_internal_call) + avm_main_sel_internal_return) + - avm_main_sel_halt) + - FF(1)) * - (avm_main_internal_return_ptr_shift - avm_main_internal_return_ptr)); + auto tmp = (avm_main_sel_internal_return * avm_main_rwa); tmp *= scaling_factor; std::get<39>(evals) += tmp; } @@ -426,7 +430,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(40); - auto tmp = (avm_main_sel_mov * (avm_main_ia - avm_main_ic)); + auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); tmp *= scaling_factor; std::get<40>(evals) += tmp; } @@ -434,12 +438,63 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(41); + auto tmp = + ((((-avm_main_first + FF(1)) * (-avm_main_sel_halt + FF(1))) * + ((((((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_div) + avm_main_sel_op_mul) + + avm_main_sel_op_not) + + avm_main_sel_op_eq) + + avm_main_sel_op_and) + + avm_main_sel_op_or) + + avm_main_sel_op_xor)) * + (avm_main_pc_shift - (avm_main_pc + FF(1)))); + tmp *= scaling_factor; + std::get<41>(evals) += tmp; + } + // Contribution 42 + { + Avm_DECLARE_VIEWS(42); + + auto tmp = ((-(((avm_main_first + avm_main_sel_internal_call) + avm_main_sel_internal_return) + + avm_main_sel_halt) + + FF(1)) * + (avm_main_internal_return_ptr_shift - avm_main_internal_return_ptr)); + tmp *= scaling_factor; + std::get<42>(evals) += tmp; + } + // Contribution 43 + { + Avm_DECLARE_VIEWS(43); + + auto tmp = (avm_main_sel_mov * (avm_main_ia - avm_main_ic)); + tmp *= scaling_factor; + std::get<43>(evals) += tmp; + } + // Contribution 44 + { + Avm_DECLARE_VIEWS(44); + auto tmp = (avm_main_alu_sel - (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + avm_main_sel_op_not) + avm_main_sel_op_eq) * (-avm_main_tag_err + FF(1)))); tmp *= scaling_factor; - std::get<41>(evals) += tmp; + std::get<44>(evals) += tmp; + } + // Contribution 45 + { + Avm_DECLARE_VIEWS(45); + + auto tmp = (avm_main_bin_op_id - (avm_main_sel_op_or + (avm_main_sel_op_xor * FF(2)))); + tmp *= scaling_factor; + std::get<45>(evals) += tmp; + } + // Contribution 46 + { + Avm_DECLARE_VIEWS(46); + + auto tmp = (avm_main_bin_sel - ((avm_main_sel_op_and + avm_main_sel_op_or) + avm_main_sel_op_xor)); + tmp *= scaling_factor; + std::get<46>(evals) += tmp; } } }; diff --git a/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp b/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp index 7863ebbbc..29f83221e 100644 --- a/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp +++ b/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp @@ -7,27 +7,27 @@ namespace bb::Avm_vm { template struct Avm_memRow { - FF avm_mem_m_one_min_inv{}; - FF avm_mem_m_sel_mov{}; - FF avm_mem_m_ind_op_c{}; - FF avm_mem_m_ind_op_b{}; FF avm_mem_m_op_b{}; - FF avm_mem_m_sub_clk{}; - FF avm_mem_m_addr{}; - FF avm_mem_m_op_c{}; - FF avm_mem_m_last{}; - FF avm_mem_m_addr_shift{}; - FF avm_mem_m_val_shift{}; - FF avm_mem_m_op_a{}; FF avm_mem_m_tag_shift{}; - FF avm_mem_m_rw_shift{}; + FF avm_mem_m_rw{}; FF avm_mem_m_ind_op_a{}; - FF avm_mem_m_tag_err{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_ind_op_b{}; + FF avm_mem_m_in_tag{}; + FF avm_mem_m_sel_mov{}; + FF avm_mem_m_one_min_inv{}; + FF avm_mem_m_addr_shift{}; + FF avm_mem_m_last{}; + FF avm_mem_m_tag{}; + FF avm_mem_m_op_c{}; + FF avm_mem_m_rw_shift{}; + FF avm_mem_m_ind_op_c{}; FF avm_mem_m_val{}; FF avm_mem_m_lastAccess{}; - FF avm_mem_m_tag{}; - FF avm_mem_m_rw{}; - FF avm_mem_m_in_tag{}; + FF avm_mem_m_tag_err{}; + FF avm_mem_m_addr{}; + FF avm_mem_m_sub_clk{}; + FF avm_mem_m_op_a{}; }; inline std::string get_relation_label_avm_mem(int index) @@ -36,23 +36,23 @@ inline std::string get_relation_label_avm_mem(int index) case 12: return "MEM_LAST_ACCESS_DELIMITER"; + case 15: + return "MEM_ZERO_INIT"; + + case 13: + return "MEM_READ_WRITE_VAL_CONSISTENCY"; + case 16: return "MEM_IN_TAG_CONSISTENCY_1"; + case 14: + return "MEM_READ_WRITE_TAG_CONSISTENCY"; + case 17: return "MEM_IN_TAG_CONSISTENCY_2"; case 24: return "MOV_SAME_TAG"; - - case 15: - return "MEM_ZERO_INIT"; - - case 14: - return "MEM_READ_WRITE_TAG_CONSISTENCY"; - - case 13: - return "MEM_READ_WRITE_VAL_CONSISTENCY"; } return std::to_string(index); } diff --git a/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp b/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp index 3b840e954..3afa82ed4 100644 --- a/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp +++ b/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp @@ -53,6 +53,26 @@ [[maybe_unused]] auto avm_alu_alu_u64_r0 = View(new_term.avm_alu_alu_u64_r0); \ [[maybe_unused]] auto avm_alu_alu_cf = View(new_term.avm_alu_alu_cf); \ [[maybe_unused]] auto avm_alu_alu_op_eq_diff_inv = View(new_term.avm_alu_alu_op_eq_diff_inv); \ + [[maybe_unused]] auto avm_byte_lookup_table_op_id = View(new_term.avm_byte_lookup_table_op_id); \ + [[maybe_unused]] auto avm_byte_lookup_table_input_a = View(new_term.avm_byte_lookup_table_input_a); \ + [[maybe_unused]] auto avm_byte_lookup_table_input_b = View(new_term.avm_byte_lookup_table_input_b); \ + [[maybe_unused]] auto avm_byte_lookup_table_output = View(new_term.avm_byte_lookup_table_output); \ + [[maybe_unused]] auto avm_byte_lookup_bin_sel = View(new_term.avm_byte_lookup_bin_sel); \ + [[maybe_unused]] auto avm_byte_lookup_table_in_tags = View(new_term.avm_byte_lookup_table_in_tags); \ + [[maybe_unused]] auto avm_byte_lookup_table_byte_lengths = View(new_term.avm_byte_lookup_table_byte_lengths); \ + [[maybe_unused]] auto avm_binary_bin_clk = View(new_term.avm_binary_bin_clk); \ + [[maybe_unused]] auto avm_binary_bin_sel = View(new_term.avm_binary_bin_sel); \ + [[maybe_unused]] auto avm_binary_acc_ia = View(new_term.avm_binary_acc_ia); \ + [[maybe_unused]] auto avm_binary_acc_ib = View(new_term.avm_binary_acc_ib); \ + [[maybe_unused]] auto avm_binary_acc_ic = View(new_term.avm_binary_acc_ic); \ + [[maybe_unused]] auto avm_binary_in_tag = View(new_term.avm_binary_in_tag); \ + [[maybe_unused]] auto avm_binary_op_id = View(new_term.avm_binary_op_id); \ + [[maybe_unused]] auto avm_binary_bin_ia_bytes = View(new_term.avm_binary_bin_ia_bytes); \ + [[maybe_unused]] auto avm_binary_bin_ib_bytes = View(new_term.avm_binary_bin_ib_bytes); \ + [[maybe_unused]] auto avm_binary_bin_ic_bytes = View(new_term.avm_binary_bin_ic_bytes); \ + [[maybe_unused]] auto avm_binary_start = View(new_term.avm_binary_start); \ + [[maybe_unused]] auto avm_binary_mem_tag_ctr = View(new_term.avm_binary_mem_tag_ctr); \ + [[maybe_unused]] auto avm_binary_mem_tag_ctr_inv = View(new_term.avm_binary_mem_tag_ctr_inv); \ [[maybe_unused]] auto avm_main_pc = View(new_term.avm_main_pc); \ [[maybe_unused]] auto avm_main_internal_return_ptr = View(new_term.avm_main_internal_return_ptr); \ [[maybe_unused]] auto avm_main_sel_internal_call = View(new_term.avm_main_sel_internal_call); \ @@ -66,7 +86,11 @@ [[maybe_unused]] auto avm_main_sel_op_div = View(new_term.avm_main_sel_op_div); \ [[maybe_unused]] auto avm_main_sel_op_not = View(new_term.avm_main_sel_op_not); \ [[maybe_unused]] auto avm_main_sel_op_eq = View(new_term.avm_main_sel_op_eq); \ + [[maybe_unused]] auto avm_main_sel_op_and = View(new_term.avm_main_sel_op_and); \ + [[maybe_unused]] auto avm_main_sel_op_or = View(new_term.avm_main_sel_op_or); \ + [[maybe_unused]] auto avm_main_sel_op_xor = View(new_term.avm_main_sel_op_xor); \ [[maybe_unused]] auto avm_main_alu_sel = View(new_term.avm_main_alu_sel); \ + [[maybe_unused]] auto avm_main_bin_sel = View(new_term.avm_main_bin_sel); \ [[maybe_unused]] auto avm_main_in_tag = View(new_term.avm_main_in_tag); \ [[maybe_unused]] auto avm_main_op_err = View(new_term.avm_main_op_err); \ [[maybe_unused]] auto avm_main_tag_err = View(new_term.avm_main_tag_err); \ @@ -90,28 +114,39 @@ [[maybe_unused]] auto avm_main_mem_idx_b = View(new_term.avm_main_mem_idx_b); \ [[maybe_unused]] auto avm_main_mem_idx_c = View(new_term.avm_main_mem_idx_c); \ [[maybe_unused]] auto avm_main_last = View(new_term.avm_main_last); \ + [[maybe_unused]] auto avm_main_bin_op_id = View(new_term.avm_main_bin_op_id); \ [[maybe_unused]] auto perm_main_alu = View(new_term.perm_main_alu); \ + [[maybe_unused]] auto perm_main_bin = View(new_term.perm_main_bin); \ [[maybe_unused]] auto perm_main_mem_a = View(new_term.perm_main_mem_a); \ [[maybe_unused]] auto perm_main_mem_b = View(new_term.perm_main_mem_b); \ [[maybe_unused]] auto perm_main_mem_c = View(new_term.perm_main_mem_c); \ [[maybe_unused]] auto perm_main_mem_ind_a = View(new_term.perm_main_mem_ind_a); \ [[maybe_unused]] auto perm_main_mem_ind_b = View(new_term.perm_main_mem_ind_b); \ [[maybe_unused]] auto perm_main_mem_ind_c = View(new_term.perm_main_mem_ind_c); \ + [[maybe_unused]] auto lookup_byte_lengths = View(new_term.lookup_byte_lengths); \ + [[maybe_unused]] auto lookup_byte_operations = View(new_term.lookup_byte_operations); \ [[maybe_unused]] auto incl_main_tag_err = View(new_term.incl_main_tag_err); \ [[maybe_unused]] auto incl_mem_tag_err = View(new_term.incl_mem_tag_err); \ + [[maybe_unused]] auto lookup_byte_lengths_counts = View(new_term.lookup_byte_lengths_counts); \ + [[maybe_unused]] auto lookup_byte_operations_counts = View(new_term.lookup_byte_operations_counts); \ [[maybe_unused]] auto incl_main_tag_err_counts = View(new_term.incl_main_tag_err_counts); \ [[maybe_unused]] auto incl_mem_tag_err_counts = View(new_term.incl_mem_tag_err_counts); \ - [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ - [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); \ - [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ - [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ - [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ - [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift); \ + [[maybe_unused]] auto avm_binary_acc_ic_shift = View(new_term.avm_binary_acc_ic_shift); \ + [[maybe_unused]] auto avm_binary_op_id_shift = View(new_term.avm_binary_op_id_shift); \ + [[maybe_unused]] auto avm_binary_acc_ia_shift = View(new_term.avm_binary_acc_ia_shift); \ + [[maybe_unused]] auto avm_binary_mem_tag_ctr_shift = View(new_term.avm_binary_mem_tag_ctr_shift); \ + [[maybe_unused]] auto avm_binary_acc_ib_shift = View(new_term.avm_binary_acc_ib_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift); + [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift); \ + [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ + [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); \ + [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ + [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ + [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ + [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); diff --git a/cpp/src/barretenberg/relations/generated/avm/lookup_byte_lengths.hpp b/cpp/src/barretenberg/relations/generated/avm/lookup_byte_lengths.hpp new file mode 100644 index 000000000..4c5a6bd0d --- /dev/null +++ b/cpp/src/barretenberg/relations/generated/avm/lookup_byte_lengths.hpp @@ -0,0 +1,171 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_byte_lengths_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 2; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_binary_start == 1 || in.avm_byte_lookup_bin_sel == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_binary_start); + const auto is_table_entry = View(in.avm_byte_lookup_bin_sel); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_byte_lengths, + in.lookup_byte_lengths_counts, + in.avm_binary_start, + in.avm_byte_lookup_bin_sel, + in.avm_binary_in_tag, + in.avm_binary_mem_tag_ctr, + in.avm_byte_lookup_table_in_tags, + in.avm_byte_lookup_table_byte_lengths); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_byte_lengths, + in.lookup_byte_lengths_counts, + in.avm_binary_start, + in.avm_byte_lookup_bin_sel, + in.avm_binary_in_tag, + in.avm_binary_mem_tag_ctr, + in.avm_byte_lookup_table_in_tags, + in.avm_byte_lookup_table_byte_lengths); + } +}; + +template +using lookup_byte_lengths_relation = GenericLookupRelation; +template using lookup_byte_lengths = GenericLookup; + +} // namespace bb diff --git a/cpp/src/barretenberg/relations/generated/avm/lookup_byte_operations.hpp b/cpp/src/barretenberg/relations/generated/avm/lookup_byte_operations.hpp new file mode 100644 index 000000000..cc9a2fdf8 --- /dev/null +++ b/cpp/src/barretenberg/relations/generated/avm/lookup_byte_operations.hpp @@ -0,0 +1,179 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_byte_operations_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 4; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_binary_bin_sel == 1 || in.avm_byte_lookup_bin_sel == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_binary_bin_sel); + const auto is_table_entry = View(in.avm_byte_lookup_bin_sel); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_byte_operations, + in.lookup_byte_operations_counts, + in.avm_binary_bin_sel, + in.avm_byte_lookup_bin_sel, + in.avm_binary_op_id, + in.avm_binary_bin_ia_bytes, + in.avm_binary_bin_ib_bytes, + in.avm_binary_bin_ic_bytes, + in.avm_byte_lookup_table_op_id, + in.avm_byte_lookup_table_input_a, + in.avm_byte_lookup_table_input_b, + in.avm_byte_lookup_table_output); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_byte_operations, + in.lookup_byte_operations_counts, + in.avm_binary_bin_sel, + in.avm_byte_lookup_bin_sel, + in.avm_binary_op_id, + in.avm_binary_bin_ia_bytes, + in.avm_binary_bin_ib_bytes, + in.avm_binary_bin_ic_bytes, + in.avm_byte_lookup_table_op_id, + in.avm_byte_lookup_table_input_a, + in.avm_byte_lookup_table_input_b, + in.avm_byte_lookup_table_output); + } +}; + +template +using lookup_byte_operations_relation = GenericLookupRelation; +template using lookup_byte_operations = GenericLookup; + +} // namespace bb diff --git a/cpp/src/barretenberg/relations/generated/avm/perm_main_bin.hpp b/cpp/src/barretenberg/relations/generated/avm/perm_main_bin.hpp new file mode 100644 index 000000000..1c68236d8 --- /dev/null +++ b/cpp/src/barretenberg/relations/generated/avm/perm_main_bin.hpp @@ -0,0 +1,106 @@ + + +#pragma once + +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include +#include + +namespace bb { + +class perm_main_bin_permutation_settings { + public: + // This constant defines how many columns are bundled together to form each set. + constexpr static size_t COLUMNS_PER_SET = 5; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the + * value needs to be set to zero. + * + * @details If this is true then permutation takes place in this row + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_main_bin_sel == 1 || in.avm_binary_start == 1); + } + + /** + * @brief Get all the entities for the permutation when we don't need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_bin, + in.avm_main_bin_sel, + in.avm_main_bin_sel, + in.avm_binary_start, + in.avm_main_ia, + in.avm_main_ib, + in.avm_main_ic, + in.avm_main_bin_op_id, + in.avm_main_in_tag, + in.avm_binary_acc_ia, + in.avm_binary_acc_ib, + in.avm_binary_acc_ic, + in.avm_binary_op_id, + in.avm_binary_in_tag); + } + + /** + * @brief Get all the entities for the permutation when need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_bin, + in.avm_main_bin_sel, + in.avm_main_bin_sel, + in.avm_binary_start, + in.avm_main_ia, + in.avm_main_ib, + in.avm_main_ic, + in.avm_main_bin_op_id, + in.avm_main_in_tag, + in.avm_binary_acc_ia, + in.avm_binary_acc_ib, + in.avm_binary_acc_ic, + in.avm_binary_op_id, + in.avm_binary_in_tag); + } +}; + +template +using perm_main_bin_relation = GenericPermutationRelation; +template using perm_main_bin = GenericPermutation; + +} // namespace bb diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_binary_trace.cpp b/cpp/src/barretenberg/vm/avm_trace/avm_binary_trace.cpp new file mode 100644 index 000000000..79a301ee8 --- /dev/null +++ b/cpp/src/barretenberg/vm/avm_trace/avm_binary_trace.cpp @@ -0,0 +1,174 @@ + +#include "avm_binary_trace.hpp" +#include "barretenberg/numeric/uint128/uint128.hpp" +#include "barretenberg/vm/avm_trace/avm_common.hpp" +#include +#include +#include +#include +#include + +namespace bb::avm_trace { + +AvmBinaryTraceBuilder::AvmBinaryTraceBuilder() +{ + binary_trace.reserve(AVM_TRACE_SIZE); +} + +std::vector AvmBinaryTraceBuilder::finalize() +{ + return std::move(binary_trace); +} + +void AvmBinaryTraceBuilder::reset() +{ + binary_trace.clear(); +} + +/** + * @brief Helper function to correctly decompose and pad inputs + * @param val The value to decompose + * @param num_bytes The number of bytes given the instr_tag. + * @return LE encoded bytes with an extra zero padding (final length is num_bytes + 1). + */ +std::vector bytes_decompose_le(uint128_t const& val) +{ + // This uses a Network Byte Order (Big-Endian) and since a uint128_t is used + // this is guaranteed to be of length 16 (zero-padded if necessary). + std::vector bytes = to_buffer(val); + // Since the trace expects LE. + std::reverse(bytes.begin(), bytes.end()); + // To simplify the loop in witness generation we need an extra zero at index num_bytes + 1. + // Since the array is already padded to length 16, we still need to add one more 0 for the instance + // where we are operating on a U128 + bytes.push_back(0); + return bytes; +} + +/** + * @brief Build and Insert and entry into the binary trace table depending on op_id + * @param a Left operand of the bitwise operation + * @param b Right operand of the bitwise operation + * @param in_tag Instruction tag + * @param clk Clock referring to the operation in the main trace. + * @param op_id which bitwise operation {0: AND, 1: OR, 2: XOR } this entry corresponds to. + */ +void AvmBinaryTraceBuilder::entry_builder( + uint128_t const& a, uint128_t const& b, uint128_t const& c, AvmMemoryTag instr_tag, uint32_t clk, uint8_t op_id) +{ + // Given the instruction tag, calculate the number of bytes to decompose values into + // The number of rows for this entry will be number of bytes + 1 + size_t num_bytes = 1 << (static_cast(instr_tag) - 1); + + // Big Endian encoded + std::vector a_bytes = bytes_decompose_le(a); + std::vector b_bytes = bytes_decompose_le(b); + std::vector c_bytes = bytes_decompose_le(c); + + uint128_t acc_ia = a; + uint128_t acc_ib = b; + uint128_t acc_ic = c; + + // We have num_bytes + 1 rows to add to the binary trace; + for (size_t i = 0; i <= num_bytes; i++) { + binary_trace.push_back(AvmBinaryTraceBuilder::BinaryTraceEntry{ + .binary_clk = clk, + .bin_sel = i != num_bytes, + .op_id = op_id, + .in_tag = static_cast(instr_tag), + .mem_tag_ctr = static_cast(num_bytes - i), + .mem_tag_ctr_inv = i == num_bytes ? FF(0) : FF(num_bytes - i).invert(), + .start = i == 0, + .acc_ia = FF(uint256_t::from_uint128(acc_ia)), + .acc_ib = FF(uint256_t::from_uint128(acc_ib)), + .acc_ic = FF(uint256_t::from_uint128(acc_ic)), + .bin_ia_bytes = a_bytes[i], + .bin_ib_bytes = b_bytes[i], + .bin_ic_bytes = c_bytes[i], + }); + // We only perform a lookup when bin_sel = 1, i.e. when we still have bytes to process + if (i != num_bytes) { + auto lookup_index = static_cast((op_id << 16) + (a_bytes[i] << 8) + b_bytes[i]); + byte_operation_counter[lookup_index]++; + } + acc_ia = (acc_ia - a_bytes[i]) >> 8; + acc_ib = (acc_ib - b_bytes[i]) >> 8; + acc_ic = (acc_ic - c_bytes[i]) >> 8; + } + // There is 1 latch per call, therefore byte_length check increments + byte_length_counter[static_cast(instr_tag)]++; +} + +/** + * @brief Build Binary trace and return the result of bitwise AND operation. + * + * @param a Left operand of the AND + * @param b Right operand of the AND + * @param in_tag Instruction tag defining the number of bits for AND + * @param clk Clock referring to the operation in the main trace. + * + * @return FF The result of bitwise AND casted to a Field element. + */ +FF AvmBinaryTraceBuilder::op_and(FF const& a, FF const& b, AvmMemoryTag instr_tag, uint32_t clk) +{ + if (instr_tag == AvmMemoryTag::FF || instr_tag == AvmMemoryTag::U0) { + return FF::zero(); + } + // Cast to bits and perform AND operation + auto a_uint128 = uint128_t(a); + auto b_uint128 = uint128_t(b); + uint128_t c_uint128 = a_uint128 & b_uint128; + + entry_builder(a_uint128, b_uint128, c_uint128, instr_tag, clk, 0); + return uint256_t::from_uint128(c_uint128); +} + +/** + * @brief Build Binary trace and return the result of bitwise OR operation. + * + * @param a Left operand of the OR + * @param b Right operand of the OR + * @param in_tag Instruction tag defining the number of bits for OR + * @param clk Clock referring to the operation in the main trace. + * + * @return FF The result of bitwise OR casted to a Field element. + */ +FF AvmBinaryTraceBuilder::op_or(FF const& a, FF const& b, AvmMemoryTag instr_tag, uint32_t clk) +{ + if (instr_tag == AvmMemoryTag::FF || instr_tag == AvmMemoryTag::U0) { + return FF::zero(); + } + // Cast to bits and perform OR operation + auto a_uint128 = uint128_t(a); + auto b_uint128 = uint128_t(b); + uint128_t c_uint128 = a_uint128 | b_uint128; + + entry_builder(a_uint128, b_uint128, c_uint128, instr_tag, clk, 1); + return uint256_t::from_uint128(c_uint128); +} + +/** + * @brief Build Binary trace and return the result of bitwise XOR operation. + * + * @param a Left operand of the XOR + * @param b Right operand of the XOR + * @param in_tag Instruction tag defining the number of bits for XOR + * @param clk Clock referring to the operation in the main trace. + * + * @return FF The result of bitwise XOR casted to a Field element. + */ +FF AvmBinaryTraceBuilder::op_xor(FF const& a, FF const& b, AvmMemoryTag instr_tag, uint32_t clk) +{ + if (instr_tag == AvmMemoryTag::FF || instr_tag == AvmMemoryTag::U0) { + return FF::zero(); + } + // Cast to bits and perform XOR operation + auto a_uint128 = uint128_t(a); + auto b_uint128 = uint128_t(b); + uint128_t c_uint128 = a_uint128 ^ b_uint128; + + entry_builder(a_uint128, b_uint128, c_uint128, instr_tag, clk, 2); + return uint256_t::from_uint128(c_uint128); +} + +} // namespace bb::avm_trace diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_binary_trace.hpp b/cpp/src/barretenberg/vm/avm_trace/avm_binary_trace.hpp new file mode 100644 index 000000000..78de178b3 --- /dev/null +++ b/cpp/src/barretenberg/vm/avm_trace/avm_binary_trace.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "avm_common.hpp" +#include "barretenberg/numeric/uint128/uint128.hpp" +#include + +namespace bb::avm_trace { +class AvmBinaryTraceBuilder { + public: + struct BinaryTraceEntry { + uint32_t binary_clk = 0; + bool bin_sel = 0; + uint8_t op_id = 0; + uint8_t in_tag = 0; + uint8_t mem_tag_ctr = 0; + FF mem_tag_ctr_inv = 0; + + uint256_t factor = 0; + bool start = false; + + FF acc_ia = FF(0); + FF acc_ib = FF(0); + FF acc_ic = FF(0); + uint8_t bin_ia_bytes = 0; + uint8_t bin_ib_bytes = 0; + uint8_t bin_ic_bytes = 0; + }; + + std::unordered_map byte_operation_counter; + std::unordered_map byte_length_counter; + + AvmBinaryTraceBuilder(); + void reset(); + // Finalize the trace + std::vector finalize(); + + FF op_and(FF const& a, FF const& b, AvmMemoryTag instr_tag, uint32_t clk); + FF op_or(FF const& a, FF const& b, AvmMemoryTag instr_tag, uint32_t clk); + FF op_xor(FF const& a, FF const& b, AvmMemoryTag instr_tag, uint32_t clk); + + private: + std::vector binary_trace; + // Helper Function to build binary trace entries + void entry_builder(uint128_t const& a, + uint128_t const& b, + uint128_t const& c, + AvmMemoryTag instr_tag, + uint32_t clk, + uint8_t op_id); +}; +} // namespace bb::avm_trace diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp b/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp index 2d3e9e9ec..04ed5dc05 100644 --- a/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp +++ b/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp @@ -1,5 +1,6 @@ #pragma once +#include "barretenberg/relations/generated/avm/avm_binary.hpp" #include "barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp" #include "barretenberg/vm/generated/avm_circuit_builder.hpp" #include @@ -11,7 +12,7 @@ using FF = Flavor::FF; using Row = bb::AvmFullRow; // Number of rows -static const size_t AVM_TRACE_SIZE = 256; +static const size_t AVM_TRACE_SIZE = 1 << 18; enum class IntermRegister : uint32_t { IA = 0, IB = 1, IC = 2 }; enum class IndirectRegister : uint32_t { IND_A = 0, IND_B = 1, IND_C = 2 }; diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp b/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp index 657ae07eb..549f68dd4 100644 --- a/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp +++ b/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp @@ -30,6 +30,9 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = { OpCode::EQ, three_operand_format }, // Compute - Bitwise { OpCode::NOT, { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT32, OperandType::UINT32 } }, + { OpCode::AND, three_operand_format }, + { OpCode::OR, three_operand_format }, + { OpCode::XOR, three_operand_format }, // Execution Environment - Calldata { OpCode::CALLDATACOPY, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, // Machine State - Internal Control Flow diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index 2ac526225..c14fb217f 100644 --- a/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -135,6 +135,29 @@ std::vector Execution::gen_trace(std::vector const& instructio std::get(inst.operands.at(4)), std::get(inst.operands.at(1))); break; + + case OpCode::AND: + trace_builder.op_and(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); + break; + case OpCode::OR: + trace_builder.op_or(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); + break; + + case OpCode::XOR: + trace_builder.op_xor(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); + break; // Execution Environment - Calldata case OpCode::CALLDATACOPY: trace_builder.calldata_copy(std::get(inst.operands.at(0)), diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp b/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp index 2a2784ee7..27a1ac9c6 100644 --- a/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp +++ b/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp @@ -79,7 +79,6 @@ void log_avm_trace(std::vector const& trace, size_t beg, size_t end, bool e info("sel_op_not: ", trace.at(i).avm_main_sel_op_not); info("sel_op_sel_alu: ", trace.at(i).avm_main_alu_sel); } - info("\n"); } } diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index 57e21c331..24ec44192 100644 --- a/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -1,9 +1,11 @@ +#include #include #include #include #include #include #include +#include #include #include #include @@ -33,6 +35,7 @@ void AvmTraceBuilder::reset() main_trace.clear(); mem_trace_builder.reset(); alu_trace_builder.reset(); + bin_trace_builder.reset(); } AvmTraceBuilder::IndirectThreeResolution AvmTraceBuilder::resolve_ind_three( @@ -417,7 +420,6 @@ void AvmTraceBuilder::op_eq( auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); tag_match = read_a.tag_match && read_b.tag_match; - // c = a == b ? 1 : 0 FF a = read_a.val; FF b = read_b.val; @@ -455,6 +457,153 @@ void AvmTraceBuilder::op_eq( }); } +void AvmTraceBuilder::op_and( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + + // Reading from memory and loading into ia resp. ib. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; + + FF a = tag_match ? read_a.val : FF(0); + FF b = tag_match ? read_b.val : FF(0); + + FF c = tag_match ? bin_trace_builder.op_and(a, b, in_tag, clk) : FF(0); + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); + + main_trace.push_back(Row{ + .avm_main_clk = clk, + .avm_main_pc = FF(pc++), + .avm_main_internal_return_ptr = FF(internal_return_ptr), + .avm_main_sel_op_and = FF(1), + .avm_main_bin_sel = FF(1), + .avm_main_in_tag = FF(static_cast(in_tag)), + .avm_main_tag_err = FF(static_cast(!tag_match)), + .avm_main_ia = a, + .avm_main_ib = b, + .avm_main_ic = c, + .avm_main_mem_op_a = FF(1), + .avm_main_mem_op_b = FF(1), + .avm_main_mem_op_c = FF(1), + .avm_main_rwc = FF(1), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), + .avm_main_bin_op_id = FF(0), + }); +} + +void AvmTraceBuilder::op_or( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + + // Reading from memory and loading into ia resp. ib. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; + + FF a = tag_match ? read_a.val : FF(0); + FF b = tag_match ? read_b.val : FF(0); + + FF c = tag_match ? bin_trace_builder.op_or(a, b, in_tag, clk) : FF(0); + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); + + main_trace.push_back(Row{ + .avm_main_clk = clk, + .avm_main_pc = FF(pc++), + .avm_main_internal_return_ptr = FF(internal_return_ptr), + .avm_main_sel_op_or = FF(1), + .avm_main_bin_sel = FF(1), + .avm_main_in_tag = FF(static_cast(in_tag)), + .avm_main_tag_err = FF(static_cast(!tag_match)), + .avm_main_ia = a, + .avm_main_ib = b, + .avm_main_ic = c, + .avm_main_mem_op_a = FF(1), + .avm_main_mem_op_b = FF(1), + .avm_main_mem_op_c = FF(1), + .avm_main_rwc = FF(1), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), + .avm_main_bin_op_id = FF(1), + }); +} + +void AvmTraceBuilder::op_xor( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + + // Reading from memory and loading into ia resp. ib. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; + + FF a = tag_match ? read_a.val : FF(0); + FF b = tag_match ? read_b.val : FF(0); + + FF c = tag_match ? bin_trace_builder.op_xor(a, b, in_tag, clk) : FF(0); + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); + + main_trace.push_back(Row{ + .avm_main_clk = clk, + .avm_main_pc = FF(pc++), + .avm_main_internal_return_ptr = FF(internal_return_ptr), + .avm_main_sel_op_xor = FF(1), + .avm_main_bin_sel = FF(1), + .avm_main_in_tag = FF(static_cast(in_tag)), + .avm_main_tag_err = FF(static_cast(!tag_match)), + .avm_main_ia = a, + .avm_main_ib = b, + .avm_main_ic = c, + .avm_main_mem_op_a = FF(1), + .avm_main_mem_op_b = FF(1), + .avm_main_mem_op_c = FF(1), + .avm_main_rwc = FF(1), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), + .avm_main_bin_op_id = FF(2), + }); +} + // TODO: Finish SET opcode implementation. This is a partial implementation // facilitating testing of arithmetic operations over non finite field types. // We add an entry in the memory trace and a simplified one in the main trace @@ -873,7 +1022,8 @@ void AvmTraceBuilder::internal_call(uint32_t jmp_dest) * - Set the next program counter to the return location * - Decrement the return stack pointer * - * TODO(https://github.com/AztecProtocol/aztec-packages/issues/3740): This function MUST come after a call instruction. + * TODO(https://github.com/AztecProtocol/aztec-packages/issues/3740): This function MUST come after a call + * instruction. */ void AvmTraceBuilder::internal_return() { @@ -930,9 +1080,11 @@ std::vector AvmTraceBuilder::finalize() { auto mem_trace = mem_trace_builder.finalize(); auto alu_trace = alu_trace_builder.finalize(); + auto bin_trace = bin_trace_builder.finalize(); size_t mem_trace_size = mem_trace.size(); size_t main_trace_size = main_trace.size(); size_t alu_trace_size = alu_trace.size(); + size_t bin_trace_size = bin_trace.size(); // Get tag_err counts from the mem_trace_builder finalise_mem_trace_lookup_counts(); @@ -944,11 +1096,17 @@ std::vector AvmTraceBuilder::finalize() assert(main_trace_size < AVM_TRACE_SIZE); assert(alu_trace_size < AVM_TRACE_SIZE); - // Fill the rest with zeros. - size_t zero_rows_num = AVM_TRACE_SIZE - main_trace_size - 1; - while (zero_rows_num-- > 0) { - main_trace.push_back({}); - } + // Main Trace needs to be at least as big as the biggest subtrace. + // If the bin_trace_size has entries, we need the main_trace to be as big as our byte lookup table (3 * 2**16 + // long) + size_t lookup_table = bin_trace_size > 0 ? 3 * (1 << 16) : 0; + std::vector trace_sizes = { mem_trace_size, main_trace_size, alu_trace_size, lookup_table }; + auto trace_size = std::max_element(trace_sizes.begin(), trace_sizes.end()); + + // We only need to pad with zeroes to the size to the largest trace here, pow_2 padding is handled in the + // subgroup_size check in bb + // Resize the main_trace to accomodate a potential lookup, filling with default empty rows. + main_trace.resize(*trace_size, {}); main_trace.at(main_trace_size - 1).avm_main_last = FF(1); @@ -1067,6 +1225,64 @@ std::vector AvmTraceBuilder::finalize() } } + // Add Binary Trace table + for (size_t i = 0; i < bin_trace_size; i++) { + auto const& src = bin_trace.at(i); + auto& dest = main_trace.at(i); + dest.avm_binary_bin_clk = src.binary_clk; + dest.avm_binary_bin_sel = static_cast(src.bin_sel); + dest.avm_binary_acc_ia = src.acc_ia; + dest.avm_binary_acc_ib = src.acc_ib; + dest.avm_binary_acc_ic = src.acc_ic; + dest.avm_binary_in_tag = src.in_tag; + dest.avm_binary_op_id = src.op_id; + dest.avm_binary_bin_ia_bytes = src.bin_ia_bytes; + dest.avm_binary_bin_ib_bytes = src.bin_ib_bytes; + dest.avm_binary_bin_ic_bytes = src.bin_ic_bytes; + dest.avm_binary_start = FF(static_cast(src.start)); + dest.avm_binary_mem_tag_ctr = src.mem_tag_ctr; + dest.avm_binary_mem_tag_ctr_inv = src.mem_tag_ctr_inv; + } + + // Only generate precomputed byte tables if we are actually going to use them in this main trace. + if (bin_trace_size > 0) { + // Generate Lookup Table of all combinations of 2, 8-bit numbers and op_id. + for (size_t op_id = 0; op_id < 3; op_id++) { + for (size_t input_a = 0; input_a <= UINT8_MAX; input_a++) { + for (size_t input_b = 0; input_b <= UINT8_MAX; input_b++) { + auto a = static_cast(input_a); + auto b = static_cast(input_b); + + // Derive a unique row index given op_id, a, and b. + auto main_trace_index = static_cast((op_id << 16) + (input_a << 8) + b); + + main_trace.at(main_trace_index).avm_byte_lookup_bin_sel = FF(1); + main_trace.at(main_trace_index).avm_byte_lookup_table_op_id = op_id; + main_trace.at(main_trace_index).avm_byte_lookup_table_input_a = a; + main_trace.at(main_trace_index).avm_byte_lookup_table_input_b = b; + // Add the counter value stored throughout the execution + main_trace.at(main_trace_index).lookup_byte_operations_counts = + bin_trace_builder.byte_operation_counter[main_trace_index]; + if (op_id == 0) { + main_trace.at(main_trace_index).avm_byte_lookup_table_output = a & b; + } else if (op_id == 1) { + main_trace.at(main_trace_index).avm_byte_lookup_table_output = a | b; + } else { + main_trace.at(main_trace_index).avm_byte_lookup_table_output = a ^ b; + } + } + } + } + // Generate ByteLength Lookup table of instruction tags to the number of bytes + // {U8: 1, U16: 2, U32: 4, U64: 8, U128: 16} + for (uint8_t avm_in_tag = 0; avm_in_tag < 5; avm_in_tag++) { + // The +1 here is because the instruction tags we care about (i.e excl U0 and FF) has the range [1,5] + main_trace.at(avm_in_tag).avm_byte_lookup_table_in_tags = avm_in_tag + 1; + main_trace.at(avm_in_tag).avm_byte_lookup_table_byte_lengths = static_cast(pow(2, avm_in_tag)); + main_trace.at(avm_in_tag).lookup_byte_lengths_counts = + bin_trace_builder.byte_length_counter[avm_in_tag + 1]; + } + } // Adding extra row for the shifted values at the top of the execution trace. Row first_row = Row{ .avm_main_first = FF(1), .avm_mem_m_lastAccess = FF(1) }; main_trace.insert(main_trace.begin(), first_row); diff --git a/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index 8c62d03a4..db65d015d 100644 --- a/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -3,6 +3,7 @@ #include #include "avm_alu_trace.hpp" +#include "avm_binary_trace.hpp" #include "avm_common.hpp" #include "avm_instructions.hpp" #include "avm_mem_trace.hpp" @@ -46,6 +47,15 @@ class AvmTraceBuilder { // Equality with direct or indirect memory access. void op_eq(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Bitwise and with direct or indirect memory access. + void op_and(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + + // Bitwise or with direct or indirect memory access. + void op_or(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + + // Bitwise xor with direct or indirect memory access. + void op_xor(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Set a constant from bytecode with direct memory access. void set(uint128_t val, uint32_t dst_offset, AvmMemoryTag in_tag); @@ -95,6 +105,7 @@ class AvmTraceBuilder { std::vector main_trace; AvmMemTraceBuilder mem_trace_builder; AvmAluTraceBuilder alu_trace_builder; + AvmBinaryTraceBuilder bin_trace_builder; void finalise_mem_trace_lookup_counts(); diff --git a/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp b/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp index ee78ecf56..db1f2cee1 100644 --- a/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp +++ b/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp @@ -12,11 +12,15 @@ #include "barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp" #include "barretenberg/relations/generated/avm/avm_alu.hpp" +#include "barretenberg/relations/generated/avm/avm_binary.hpp" #include "barretenberg/relations/generated/avm/avm_main.hpp" #include "barretenberg/relations/generated/avm/avm_mem.hpp" #include "barretenberg/relations/generated/avm/incl_main_tag_err.hpp" #include "barretenberg/relations/generated/avm/incl_mem_tag_err.hpp" +#include "barretenberg/relations/generated/avm/lookup_byte_lengths.hpp" +#include "barretenberg/relations/generated/avm/lookup_byte_operations.hpp" #include "barretenberg/relations/generated/avm/perm_main_alu.hpp" +#include "barretenberg/relations/generated/avm/perm_main_bin.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_a.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_b.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_c.hpp" @@ -79,6 +83,26 @@ template struct AvmFullRow { FF avm_alu_alu_u64_r0{}; FF avm_alu_alu_cf{}; FF avm_alu_alu_op_eq_diff_inv{}; + FF avm_byte_lookup_table_op_id{}; + FF avm_byte_lookup_table_input_a{}; + FF avm_byte_lookup_table_input_b{}; + FF avm_byte_lookup_table_output{}; + FF avm_byte_lookup_bin_sel{}; + FF avm_byte_lookup_table_in_tags{}; + FF avm_byte_lookup_table_byte_lengths{}; + FF avm_binary_bin_clk{}; + FF avm_binary_bin_sel{}; + FF avm_binary_acc_ia{}; + FF avm_binary_acc_ib{}; + FF avm_binary_acc_ic{}; + FF avm_binary_in_tag{}; + FF avm_binary_op_id{}; + FF avm_binary_bin_ia_bytes{}; + FF avm_binary_bin_ib_bytes{}; + FF avm_binary_bin_ic_bytes{}; + FF avm_binary_start{}; + FF avm_binary_mem_tag_ctr{}; + FF avm_binary_mem_tag_ctr_inv{}; FF avm_main_pc{}; FF avm_main_internal_return_ptr{}; FF avm_main_sel_internal_call{}; @@ -92,7 +116,11 @@ template struct AvmFullRow { FF avm_main_sel_op_div{}; FF avm_main_sel_op_not{}; FF avm_main_sel_op_eq{}; + FF avm_main_sel_op_and{}; + FF avm_main_sel_op_or{}; + FF avm_main_sel_op_xor{}; FF avm_main_alu_sel{}; + FF avm_main_bin_sel{}; FF avm_main_in_tag{}; FF avm_main_op_err{}; FF avm_main_tag_err{}; @@ -116,31 +144,42 @@ template struct AvmFullRow { FF avm_main_mem_idx_b{}; FF avm_main_mem_idx_c{}; FF avm_main_last{}; + FF avm_main_bin_op_id{}; FF perm_main_alu{}; + FF perm_main_bin{}; FF perm_main_mem_a{}; FF perm_main_mem_b{}; FF perm_main_mem_c{}; FF perm_main_mem_ind_a{}; FF perm_main_mem_ind_b{}; FF perm_main_mem_ind_c{}; + FF lookup_byte_lengths{}; + FF lookup_byte_operations{}; FF incl_main_tag_err{}; FF incl_mem_tag_err{}; + FF lookup_byte_lengths_counts{}; + FF lookup_byte_operations_counts{}; FF incl_main_tag_err_counts{}; FF incl_mem_tag_err_counts{}; + FF avm_binary_acc_ic_shift{}; + FF avm_binary_op_id_shift{}; + FF avm_binary_acc_ia_shift{}; + FF avm_binary_mem_tag_ctr_shift{}; + FF avm_binary_acc_ib_shift{}; + FF avm_alu_alu_u16_r3_shift{}; + FF avm_alu_alu_u16_r6_shift{}; + FF avm_alu_alu_u16_r0_shift{}; + FF avm_alu_alu_u16_r1_shift{}; + FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_u16_r7_shift{}; + FF avm_alu_alu_u16_r4_shift{}; + FF avm_alu_alu_u16_r5_shift{}; FF avm_main_internal_return_ptr_shift{}; FF avm_main_pc_shift{}; - FF avm_mem_m_addr_shift{}; - FF avm_mem_m_val_shift{}; FF avm_mem_m_tag_shift{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_addr_shift{}; FF avm_mem_m_rw_shift{}; - FF avm_alu_alu_u16_r7_shift{}; - FF avm_alu_alu_u16_r1_shift{}; - FF avm_alu_alu_u16_r5_shift{}; - FF avm_alu_alu_u16_r6_shift{}; - FF avm_alu_alu_u16_r0_shift{}; - FF avm_alu_alu_u16_r4_shift{}; - FF avm_alu_alu_u16_r2_shift{}; - FF avm_alu_alu_u16_r3_shift{}; }; class AvmCircuitBuilder { @@ -153,8 +192,8 @@ class AvmCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 113; - static constexpr size_t num_polys = 99; + static constexpr size_t num_fixed_columns = 148; + static constexpr size_t num_polys = 129; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -221,6 +260,26 @@ class AvmCircuitBuilder { polys.avm_alu_alu_u64_r0[i] = rows[i].avm_alu_alu_u64_r0; polys.avm_alu_alu_cf[i] = rows[i].avm_alu_alu_cf; polys.avm_alu_alu_op_eq_diff_inv[i] = rows[i].avm_alu_alu_op_eq_diff_inv; + polys.avm_byte_lookup_table_op_id[i] = rows[i].avm_byte_lookup_table_op_id; + polys.avm_byte_lookup_table_input_a[i] = rows[i].avm_byte_lookup_table_input_a; + polys.avm_byte_lookup_table_input_b[i] = rows[i].avm_byte_lookup_table_input_b; + polys.avm_byte_lookup_table_output[i] = rows[i].avm_byte_lookup_table_output; + polys.avm_byte_lookup_bin_sel[i] = rows[i].avm_byte_lookup_bin_sel; + polys.avm_byte_lookup_table_in_tags[i] = rows[i].avm_byte_lookup_table_in_tags; + polys.avm_byte_lookup_table_byte_lengths[i] = rows[i].avm_byte_lookup_table_byte_lengths; + polys.avm_binary_bin_clk[i] = rows[i].avm_binary_bin_clk; + polys.avm_binary_bin_sel[i] = rows[i].avm_binary_bin_sel; + polys.avm_binary_acc_ia[i] = rows[i].avm_binary_acc_ia; + polys.avm_binary_acc_ib[i] = rows[i].avm_binary_acc_ib; + polys.avm_binary_acc_ic[i] = rows[i].avm_binary_acc_ic; + polys.avm_binary_in_tag[i] = rows[i].avm_binary_in_tag; + polys.avm_binary_op_id[i] = rows[i].avm_binary_op_id; + polys.avm_binary_bin_ia_bytes[i] = rows[i].avm_binary_bin_ia_bytes; + polys.avm_binary_bin_ib_bytes[i] = rows[i].avm_binary_bin_ib_bytes; + polys.avm_binary_bin_ic_bytes[i] = rows[i].avm_binary_bin_ic_bytes; + polys.avm_binary_start[i] = rows[i].avm_binary_start; + polys.avm_binary_mem_tag_ctr[i] = rows[i].avm_binary_mem_tag_ctr; + polys.avm_binary_mem_tag_ctr_inv[i] = rows[i].avm_binary_mem_tag_ctr_inv; polys.avm_main_pc[i] = rows[i].avm_main_pc; polys.avm_main_internal_return_ptr[i] = rows[i].avm_main_internal_return_ptr; polys.avm_main_sel_internal_call[i] = rows[i].avm_main_sel_internal_call; @@ -234,7 +293,11 @@ class AvmCircuitBuilder { polys.avm_main_sel_op_div[i] = rows[i].avm_main_sel_op_div; polys.avm_main_sel_op_not[i] = rows[i].avm_main_sel_op_not; polys.avm_main_sel_op_eq[i] = rows[i].avm_main_sel_op_eq; + polys.avm_main_sel_op_and[i] = rows[i].avm_main_sel_op_and; + polys.avm_main_sel_op_or[i] = rows[i].avm_main_sel_op_or; + polys.avm_main_sel_op_xor[i] = rows[i].avm_main_sel_op_xor; polys.avm_main_alu_sel[i] = rows[i].avm_main_alu_sel; + polys.avm_main_bin_sel[i] = rows[i].avm_main_bin_sel; polys.avm_main_in_tag[i] = rows[i].avm_main_in_tag; polys.avm_main_op_err[i] = rows[i].avm_main_op_err; polys.avm_main_tag_err[i] = rows[i].avm_main_tag_err; @@ -258,33 +321,44 @@ class AvmCircuitBuilder { polys.avm_main_mem_idx_b[i] = rows[i].avm_main_mem_idx_b; polys.avm_main_mem_idx_c[i] = rows[i].avm_main_mem_idx_c; polys.avm_main_last[i] = rows[i].avm_main_last; + polys.avm_main_bin_op_id[i] = rows[i].avm_main_bin_op_id; polys.perm_main_alu[i] = rows[i].perm_main_alu; + polys.perm_main_bin[i] = rows[i].perm_main_bin; polys.perm_main_mem_a[i] = rows[i].perm_main_mem_a; polys.perm_main_mem_b[i] = rows[i].perm_main_mem_b; polys.perm_main_mem_c[i] = rows[i].perm_main_mem_c; polys.perm_main_mem_ind_a[i] = rows[i].perm_main_mem_ind_a; polys.perm_main_mem_ind_b[i] = rows[i].perm_main_mem_ind_b; polys.perm_main_mem_ind_c[i] = rows[i].perm_main_mem_ind_c; + polys.lookup_byte_lengths[i] = rows[i].lookup_byte_lengths; + polys.lookup_byte_operations[i] = rows[i].lookup_byte_operations; polys.incl_main_tag_err[i] = rows[i].incl_main_tag_err; polys.incl_mem_tag_err[i] = rows[i].incl_mem_tag_err; + polys.lookup_byte_lengths_counts[i] = rows[i].lookup_byte_lengths_counts; + polys.lookup_byte_operations_counts[i] = rows[i].lookup_byte_operations_counts; polys.incl_main_tag_err_counts[i] = rows[i].incl_main_tag_err_counts; polys.incl_mem_tag_err_counts[i] = rows[i].incl_mem_tag_err_counts; } + polys.avm_binary_acc_ic_shift = Polynomial(polys.avm_binary_acc_ic.shifted()); + polys.avm_binary_op_id_shift = Polynomial(polys.avm_binary_op_id.shifted()); + polys.avm_binary_acc_ia_shift = Polynomial(polys.avm_binary_acc_ia.shifted()); + polys.avm_binary_mem_tag_ctr_shift = Polynomial(polys.avm_binary_mem_tag_ctr.shifted()); + polys.avm_binary_acc_ib_shift = Polynomial(polys.avm_binary_acc_ib.shifted()); + polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted()); + polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); + polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted()); + polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); + polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); + polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted()); + polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); + polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted()); polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted()); polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); - polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); - polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); + polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); + polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); - polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted()); - polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); - polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted()); - polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); - polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted()); - polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); - polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); - polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted()); return polys; } @@ -356,6 +430,14 @@ class AvmCircuitBuilder { return true; }; + if (!evaluate_relation.template operator()>("avm_binary", + Avm_vm::get_relation_label_avm_binary)) { + return false; + } + if (!evaluate_relation.template operator()>("avm_alu", + Avm_vm::get_relation_label_avm_alu)) { + return false; + } if (!evaluate_relation.template operator()>("avm_main", Avm_vm::get_relation_label_avm_main)) { return false; @@ -364,14 +446,13 @@ class AvmCircuitBuilder { Avm_vm::get_relation_label_avm_mem)) { return false; } - if (!evaluate_relation.template operator()>("avm_alu", - Avm_vm::get_relation_label_avm_alu)) { - return false; - } if (!evaluate_logderivative.template operator()>("PERM_MAIN_ALU")) { return false; } + if (!evaluate_logderivative.template operator()>("PERM_MAIN_BIN")) { + return false; + } if (!evaluate_logderivative.template operator()>("PERM_MAIN_MEM_A")) { return false; } @@ -390,6 +471,13 @@ class AvmCircuitBuilder { if (!evaluate_logderivative.template operator()>("PERM_MAIN_MEM_IND_C")) { return false; } + if (!evaluate_logderivative.template operator()>("LOOKUP_BYTE_LENGTHS")) { + return false; + } + if (!evaluate_logderivative.template operator()>( + "LOOKUP_BYTE_OPERATIONS")) { + return false; + } if (!evaluate_logderivative.template operator()>("INCL_MAIN_TAG_ERR")) { return false; } diff --git a/cpp/src/barretenberg/vm/generated/avm_flavor.hpp b/cpp/src/barretenberg/vm/generated/avm_flavor.hpp index 2d5393cdf..81f872a6b 100644 --- a/cpp/src/barretenberg/vm/generated/avm_flavor.hpp +++ b/cpp/src/barretenberg/vm/generated/avm_flavor.hpp @@ -14,9 +14,11 @@ #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/relations/generated/avm/avm_alu.hpp" +#include "barretenberg/relations/generated/avm/avm_binary.hpp" #include "barretenberg/relations/generated/avm/avm_main.hpp" #include "barretenberg/relations/generated/avm/avm_mem.hpp" #include "barretenberg/relations/generated/avm/perm_main_alu.hpp" +#include "barretenberg/relations/generated/avm/perm_main_bin.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_a.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_b.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_c.hpp" @@ -44,16 +46,18 @@ class AvmFlavor { using RelationSeparator = FF; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 97; + static constexpr size_t NUM_WITNESS_ENTITIES = 127; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 113; + static constexpr size_t NUM_ALL_ENTITIES = 148; - using Relations = std::tuple, - Avm_vm::avm_mem, + using Relations = std::tuple, Avm_vm::avm_alu, + Avm_vm::avm_main, + Avm_vm::avm_mem, perm_main_alu_relation, + perm_main_bin_relation, perm_main_mem_a_relation, perm_main_mem_b_relation, perm_main_mem_c_relation, @@ -142,6 +146,26 @@ class AvmFlavor { avm_alu_alu_u64_r0, avm_alu_alu_cf, avm_alu_alu_op_eq_diff_inv, + avm_byte_lookup_table_op_id, + avm_byte_lookup_table_input_a, + avm_byte_lookup_table_input_b, + avm_byte_lookup_table_output, + avm_byte_lookup_bin_sel, + avm_byte_lookup_table_in_tags, + avm_byte_lookup_table_byte_lengths, + avm_binary_bin_clk, + avm_binary_bin_sel, + avm_binary_acc_ia, + avm_binary_acc_ib, + avm_binary_acc_ic, + avm_binary_in_tag, + avm_binary_op_id, + avm_binary_bin_ia_bytes, + avm_binary_bin_ib_bytes, + avm_binary_bin_ic_bytes, + avm_binary_start, + avm_binary_mem_tag_ctr, + avm_binary_mem_tag_ctr_inv, avm_main_pc, avm_main_internal_return_ptr, avm_main_sel_internal_call, @@ -155,7 +179,11 @@ class AvmFlavor { avm_main_sel_op_div, avm_main_sel_op_not, avm_main_sel_op_eq, + avm_main_sel_op_and, + avm_main_sel_op_or, + avm_main_sel_op_xor, avm_main_alu_sel, + avm_main_bin_sel, avm_main_in_tag, avm_main_op_err, avm_main_tag_err, @@ -179,15 +207,21 @@ class AvmFlavor { avm_main_mem_idx_b, avm_main_mem_idx_c, avm_main_last, + avm_main_bin_op_id, perm_main_alu, + perm_main_bin, perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, perm_main_mem_ind_a, perm_main_mem_ind_b, perm_main_mem_ind_c, + lookup_byte_lengths, + lookup_byte_operations, incl_main_tag_err, incl_mem_tag_err, + lookup_byte_lengths_counts, + lookup_byte_operations_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts) @@ -242,6 +276,26 @@ class AvmFlavor { avm_alu_alu_u64_r0, avm_alu_alu_cf, avm_alu_alu_op_eq_diff_inv, + avm_byte_lookup_table_op_id, + avm_byte_lookup_table_input_a, + avm_byte_lookup_table_input_b, + avm_byte_lookup_table_output, + avm_byte_lookup_bin_sel, + avm_byte_lookup_table_in_tags, + avm_byte_lookup_table_byte_lengths, + avm_binary_bin_clk, + avm_binary_bin_sel, + avm_binary_acc_ia, + avm_binary_acc_ib, + avm_binary_acc_ic, + avm_binary_in_tag, + avm_binary_op_id, + avm_binary_bin_ia_bytes, + avm_binary_bin_ib_bytes, + avm_binary_bin_ic_bytes, + avm_binary_start, + avm_binary_mem_tag_ctr, + avm_binary_mem_tag_ctr_inv, avm_main_pc, avm_main_internal_return_ptr, avm_main_sel_internal_call, @@ -255,7 +309,11 @@ class AvmFlavor { avm_main_sel_op_div, avm_main_sel_op_not, avm_main_sel_op_eq, + avm_main_sel_op_and, + avm_main_sel_op_or, + avm_main_sel_op_xor, avm_main_alu_sel, + avm_main_bin_sel, avm_main_in_tag, avm_main_op_err, avm_main_tag_err, @@ -279,15 +337,21 @@ class AvmFlavor { avm_main_mem_idx_b, avm_main_mem_idx_c, avm_main_last, + avm_main_bin_op_id, perm_main_alu, + perm_main_bin, perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, perm_main_mem_ind_a, perm_main_mem_ind_b, perm_main_mem_ind_c, + lookup_byte_lengths, + lookup_byte_operations, incl_main_tag_err, incl_mem_tag_err, + lookup_byte_lengths_counts, + lookup_byte_operations_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts }; }; @@ -348,6 +412,26 @@ class AvmFlavor { avm_alu_alu_u64_r0, avm_alu_alu_cf, avm_alu_alu_op_eq_diff_inv, + avm_byte_lookup_table_op_id, + avm_byte_lookup_table_input_a, + avm_byte_lookup_table_input_b, + avm_byte_lookup_table_output, + avm_byte_lookup_bin_sel, + avm_byte_lookup_table_in_tags, + avm_byte_lookup_table_byte_lengths, + avm_binary_bin_clk, + avm_binary_bin_sel, + avm_binary_acc_ia, + avm_binary_acc_ib, + avm_binary_acc_ic, + avm_binary_in_tag, + avm_binary_op_id, + avm_binary_bin_ia_bytes, + avm_binary_bin_ib_bytes, + avm_binary_bin_ic_bytes, + avm_binary_start, + avm_binary_mem_tag_ctr, + avm_binary_mem_tag_ctr_inv, avm_main_pc, avm_main_internal_return_ptr, avm_main_sel_internal_call, @@ -361,7 +445,11 @@ class AvmFlavor { avm_main_sel_op_div, avm_main_sel_op_not, avm_main_sel_op_eq, + avm_main_sel_op_and, + avm_main_sel_op_or, + avm_main_sel_op_xor, avm_main_alu_sel, + avm_main_bin_sel, avm_main_in_tag, avm_main_op_err, avm_main_tag_err, @@ -385,31 +473,42 @@ class AvmFlavor { avm_main_mem_idx_b, avm_main_mem_idx_c, avm_main_last, + avm_main_bin_op_id, perm_main_alu, + perm_main_bin, perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, perm_main_mem_ind_a, perm_main_mem_ind_b, perm_main_mem_ind_c, + lookup_byte_lengths, + lookup_byte_operations, incl_main_tag_err, incl_mem_tag_err, + lookup_byte_lengths_counts, + lookup_byte_operations_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts, - avm_main_internal_return_ptr_shift, - avm_main_pc_shift, - avm_mem_m_addr_shift, - avm_mem_m_val_shift, - avm_mem_m_tag_shift, - avm_mem_m_rw_shift, - avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r5_shift, + avm_binary_acc_ic_shift, + avm_binary_op_id_shift, + avm_binary_acc_ia_shift, + avm_binary_mem_tag_ctr_shift, + avm_binary_acc_ib_shift, + avm_alu_alu_u16_r3_shift, avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r3_shift) + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r5_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift, + avm_mem_m_tag_shift, + avm_mem_m_val_shift, + avm_mem_m_addr_shift, + avm_mem_m_rw_shift) RefVector get_wires() { @@ -464,6 +563,26 @@ class AvmFlavor { avm_alu_alu_u64_r0, avm_alu_alu_cf, avm_alu_alu_op_eq_diff_inv, + avm_byte_lookup_table_op_id, + avm_byte_lookup_table_input_a, + avm_byte_lookup_table_input_b, + avm_byte_lookup_table_output, + avm_byte_lookup_bin_sel, + avm_byte_lookup_table_in_tags, + avm_byte_lookup_table_byte_lengths, + avm_binary_bin_clk, + avm_binary_bin_sel, + avm_binary_acc_ia, + avm_binary_acc_ib, + avm_binary_acc_ic, + avm_binary_in_tag, + avm_binary_op_id, + avm_binary_bin_ia_bytes, + avm_binary_bin_ib_bytes, + avm_binary_bin_ic_bytes, + avm_binary_start, + avm_binary_mem_tag_ctr, + avm_binary_mem_tag_ctr_inv, avm_main_pc, avm_main_internal_return_ptr, avm_main_sel_internal_call, @@ -477,7 +596,11 @@ class AvmFlavor { avm_main_sel_op_div, avm_main_sel_op_not, avm_main_sel_op_eq, + avm_main_sel_op_and, + avm_main_sel_op_or, + avm_main_sel_op_xor, avm_main_alu_sel, + avm_main_bin_sel, avm_main_in_tag, avm_main_op_err, avm_main_tag_err, @@ -501,31 +624,42 @@ class AvmFlavor { avm_main_mem_idx_b, avm_main_mem_idx_c, avm_main_last, + avm_main_bin_op_id, perm_main_alu, + perm_main_bin, perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, perm_main_mem_ind_a, perm_main_mem_ind_b, perm_main_mem_ind_c, + lookup_byte_lengths, + lookup_byte_operations, incl_main_tag_err, incl_mem_tag_err, + lookup_byte_lengths_counts, + lookup_byte_operations_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts, - avm_main_internal_return_ptr_shift, - avm_main_pc_shift, - avm_mem_m_addr_shift, - avm_mem_m_val_shift, - avm_mem_m_tag_shift, - avm_mem_m_rw_shift, - avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r5_shift, + avm_binary_acc_ic_shift, + avm_binary_op_id_shift, + avm_binary_acc_ia_shift, + avm_binary_mem_tag_ctr_shift, + avm_binary_acc_ib_shift, + avm_alu_alu_u16_r3_shift, avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r3_shift }; + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r5_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift, + avm_mem_m_tag_shift, + avm_mem_m_val_shift, + avm_mem_m_addr_shift, + avm_mem_m_rw_shift }; }; RefVector get_unshifted() { @@ -580,6 +714,26 @@ class AvmFlavor { avm_alu_alu_u64_r0, avm_alu_alu_cf, avm_alu_alu_op_eq_diff_inv, + avm_byte_lookup_table_op_id, + avm_byte_lookup_table_input_a, + avm_byte_lookup_table_input_b, + avm_byte_lookup_table_output, + avm_byte_lookup_bin_sel, + avm_byte_lookup_table_in_tags, + avm_byte_lookup_table_byte_lengths, + avm_binary_bin_clk, + avm_binary_bin_sel, + avm_binary_acc_ia, + avm_binary_acc_ib, + avm_binary_acc_ic, + avm_binary_in_tag, + avm_binary_op_id, + avm_binary_bin_ia_bytes, + avm_binary_bin_ib_bytes, + avm_binary_bin_ic_bytes, + avm_binary_start, + avm_binary_mem_tag_ctr, + avm_binary_mem_tag_ctr_inv, avm_main_pc, avm_main_internal_return_ptr, avm_main_sel_internal_call, @@ -593,7 +747,11 @@ class AvmFlavor { avm_main_sel_op_div, avm_main_sel_op_not, avm_main_sel_op_eq, + avm_main_sel_op_and, + avm_main_sel_op_or, + avm_main_sel_op_xor, avm_main_alu_sel, + avm_main_bin_sel, avm_main_in_tag, avm_main_op_err, avm_main_tag_err, @@ -617,51 +775,49 @@ class AvmFlavor { avm_main_mem_idx_b, avm_main_mem_idx_c, avm_main_last, + avm_main_bin_op_id, perm_main_alu, + perm_main_bin, perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, perm_main_mem_ind_a, perm_main_mem_ind_b, perm_main_mem_ind_c, + lookup_byte_lengths, + lookup_byte_operations, incl_main_tag_err, incl_mem_tag_err, + lookup_byte_lengths_counts, + lookup_byte_operations_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts }; }; RefVector get_to_be_shifted() { - return { avm_main_internal_return_ptr, - avm_main_pc, - avm_mem_m_addr, - avm_mem_m_val, - avm_mem_m_tag, - avm_mem_m_rw, - avm_alu_alu_u16_r7, - avm_alu_alu_u16_r1, - avm_alu_alu_u16_r5, - avm_alu_alu_u16_r6, - avm_alu_alu_u16_r0, - avm_alu_alu_u16_r4, - avm_alu_alu_u16_r2, - avm_alu_alu_u16_r3 }; + return { avm_binary_acc_ic, avm_binary_op_id, + avm_binary_acc_ia, avm_binary_mem_tag_ctr, + avm_binary_acc_ib, avm_alu_alu_u16_r3, + avm_alu_alu_u16_r6, avm_alu_alu_u16_r0, + avm_alu_alu_u16_r1, avm_alu_alu_u16_r2, + avm_alu_alu_u16_r7, avm_alu_alu_u16_r4, + avm_alu_alu_u16_r5, avm_main_internal_return_ptr, + avm_main_pc, avm_mem_m_tag, + avm_mem_m_val, avm_mem_m_addr, + avm_mem_m_rw }; }; RefVector get_shifted() { - return { avm_main_internal_return_ptr_shift, - avm_main_pc_shift, - avm_mem_m_addr_shift, - avm_mem_m_val_shift, - avm_mem_m_tag_shift, - avm_mem_m_rw_shift, - avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r5_shift, - avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r4_shift, - avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r3_shift }; + return { avm_binary_acc_ic_shift, avm_binary_op_id_shift, + avm_binary_acc_ia_shift, avm_binary_mem_tag_ctr_shift, + avm_binary_acc_ib_shift, avm_alu_alu_u16_r3_shift, + avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r2_shift, + avm_alu_alu_u16_r7_shift, avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r5_shift, avm_main_internal_return_ptr_shift, + avm_main_pc_shift, avm_mem_m_tag_shift, + avm_mem_m_val_shift, avm_mem_m_addr_shift, + avm_mem_m_rw_shift }; }; }; @@ -674,20 +830,16 @@ class AvmFlavor { RefVector get_to_be_shifted() { - return { avm_main_internal_return_ptr, - avm_main_pc, - avm_mem_m_addr, - avm_mem_m_val, - avm_mem_m_tag, - avm_mem_m_rw, - avm_alu_alu_u16_r7, - avm_alu_alu_u16_r1, - avm_alu_alu_u16_r5, - avm_alu_alu_u16_r6, - avm_alu_alu_u16_r0, - avm_alu_alu_u16_r4, - avm_alu_alu_u16_r2, - avm_alu_alu_u16_r3 }; + return { avm_binary_acc_ic, avm_binary_op_id, + avm_binary_acc_ia, avm_binary_mem_tag_ctr, + avm_binary_acc_ib, avm_alu_alu_u16_r3, + avm_alu_alu_u16_r6, avm_alu_alu_u16_r0, + avm_alu_alu_u16_r1, avm_alu_alu_u16_r2, + avm_alu_alu_u16_r7, avm_alu_alu_u16_r4, + avm_alu_alu_u16_r5, avm_main_internal_return_ptr, + avm_main_pc, avm_mem_m_tag, + avm_mem_m_val, avm_mem_m_addr, + avm_mem_m_rw }; }; // The plookup wires that store plookup read data. @@ -815,6 +967,26 @@ class AvmFlavor { Base::avm_alu_alu_u64_r0 = "AVM_ALU_ALU_U64_R0"; Base::avm_alu_alu_cf = "AVM_ALU_ALU_CF"; Base::avm_alu_alu_op_eq_diff_inv = "AVM_ALU_ALU_OP_EQ_DIFF_INV"; + Base::avm_byte_lookup_table_op_id = "AVM_BYTE_LOOKUP_TABLE_OP_ID"; + Base::avm_byte_lookup_table_input_a = "AVM_BYTE_LOOKUP_TABLE_INPUT_A"; + Base::avm_byte_lookup_table_input_b = "AVM_BYTE_LOOKUP_TABLE_INPUT_B"; + Base::avm_byte_lookup_table_output = "AVM_BYTE_LOOKUP_TABLE_OUTPUT"; + Base::avm_byte_lookup_bin_sel = "AVM_BYTE_LOOKUP_BIN_SEL"; + Base::avm_byte_lookup_table_in_tags = "AVM_BYTE_LOOKUP_TABLE_IN_TAGS"; + Base::avm_byte_lookup_table_byte_lengths = "AVM_BYTE_LOOKUP_TABLE_BYTE_LENGTHS"; + Base::avm_binary_bin_clk = "AVM_BINARY_BIN_CLK"; + Base::avm_binary_bin_sel = "AVM_BINARY_BIN_SEL"; + Base::avm_binary_acc_ia = "AVM_BINARY_ACC_IA"; + Base::avm_binary_acc_ib = "AVM_BINARY_ACC_IB"; + Base::avm_binary_acc_ic = "AVM_BINARY_ACC_IC"; + Base::avm_binary_in_tag = "AVM_BINARY_IN_TAG"; + Base::avm_binary_op_id = "AVM_BINARY_OP_ID"; + Base::avm_binary_bin_ia_bytes = "AVM_BINARY_BIN_IA_BYTES"; + Base::avm_binary_bin_ib_bytes = "AVM_BINARY_BIN_IB_BYTES"; + Base::avm_binary_bin_ic_bytes = "AVM_BINARY_BIN_IC_BYTES"; + Base::avm_binary_start = "AVM_BINARY_START"; + Base::avm_binary_mem_tag_ctr = "AVM_BINARY_MEM_TAG_CTR"; + Base::avm_binary_mem_tag_ctr_inv = "AVM_BINARY_MEM_TAG_CTR_INV"; Base::avm_main_pc = "AVM_MAIN_PC"; Base::avm_main_internal_return_ptr = "AVM_MAIN_INTERNAL_RETURN_PTR"; Base::avm_main_sel_internal_call = "AVM_MAIN_SEL_INTERNAL_CALL"; @@ -828,7 +1000,11 @@ class AvmFlavor { Base::avm_main_sel_op_div = "AVM_MAIN_SEL_OP_DIV"; Base::avm_main_sel_op_not = "AVM_MAIN_SEL_OP_NOT"; Base::avm_main_sel_op_eq = "AVM_MAIN_SEL_OP_EQ"; + Base::avm_main_sel_op_and = "AVM_MAIN_SEL_OP_AND"; + Base::avm_main_sel_op_or = "AVM_MAIN_SEL_OP_OR"; + Base::avm_main_sel_op_xor = "AVM_MAIN_SEL_OP_XOR"; Base::avm_main_alu_sel = "AVM_MAIN_ALU_SEL"; + Base::avm_main_bin_sel = "AVM_MAIN_BIN_SEL"; Base::avm_main_in_tag = "AVM_MAIN_IN_TAG"; Base::avm_main_op_err = "AVM_MAIN_OP_ERR"; Base::avm_main_tag_err = "AVM_MAIN_TAG_ERR"; @@ -852,15 +1028,21 @@ class AvmFlavor { Base::avm_main_mem_idx_b = "AVM_MAIN_MEM_IDX_B"; Base::avm_main_mem_idx_c = "AVM_MAIN_MEM_IDX_C"; Base::avm_main_last = "AVM_MAIN_LAST"; + Base::avm_main_bin_op_id = "AVM_MAIN_BIN_OP_ID"; Base::perm_main_alu = "PERM_MAIN_ALU"; + Base::perm_main_bin = "PERM_MAIN_BIN"; Base::perm_main_mem_a = "PERM_MAIN_MEM_A"; Base::perm_main_mem_b = "PERM_MAIN_MEM_B"; Base::perm_main_mem_c = "PERM_MAIN_MEM_C"; Base::perm_main_mem_ind_a = "PERM_MAIN_MEM_IND_A"; Base::perm_main_mem_ind_b = "PERM_MAIN_MEM_IND_B"; Base::perm_main_mem_ind_c = "PERM_MAIN_MEM_IND_C"; + Base::lookup_byte_lengths = "LOOKUP_BYTE_LENGTHS"; + Base::lookup_byte_operations = "LOOKUP_BYTE_OPERATIONS"; Base::incl_main_tag_err = "INCL_MAIN_TAG_ERR"; Base::incl_mem_tag_err = "INCL_MEM_TAG_ERR"; + Base::lookup_byte_lengths_counts = "LOOKUP_BYTE_LENGTHS_COUNTS"; + Base::lookup_byte_operations_counts = "LOOKUP_BYTE_OPERATIONS_COUNTS"; Base::incl_main_tag_err_counts = "INCL_MAIN_TAG_ERR_COUNTS"; Base::incl_mem_tag_err_counts = "INCL_MEM_TAG_ERR_COUNTS"; }; @@ -931,6 +1113,26 @@ class AvmFlavor { Commitment avm_alu_alu_u64_r0; Commitment avm_alu_alu_cf; Commitment avm_alu_alu_op_eq_diff_inv; + Commitment avm_byte_lookup_table_op_id; + Commitment avm_byte_lookup_table_input_a; + Commitment avm_byte_lookup_table_input_b; + Commitment avm_byte_lookup_table_output; + Commitment avm_byte_lookup_bin_sel; + Commitment avm_byte_lookup_table_in_tags; + Commitment avm_byte_lookup_table_byte_lengths; + Commitment avm_binary_bin_clk; + Commitment avm_binary_bin_sel; + Commitment avm_binary_acc_ia; + Commitment avm_binary_acc_ib; + Commitment avm_binary_acc_ic; + Commitment avm_binary_in_tag; + Commitment avm_binary_op_id; + Commitment avm_binary_bin_ia_bytes; + Commitment avm_binary_bin_ib_bytes; + Commitment avm_binary_bin_ic_bytes; + Commitment avm_binary_start; + Commitment avm_binary_mem_tag_ctr; + Commitment avm_binary_mem_tag_ctr_inv; Commitment avm_main_pc; Commitment avm_main_internal_return_ptr; Commitment avm_main_sel_internal_call; @@ -944,7 +1146,11 @@ class AvmFlavor { Commitment avm_main_sel_op_div; Commitment avm_main_sel_op_not; Commitment avm_main_sel_op_eq; + Commitment avm_main_sel_op_and; + Commitment avm_main_sel_op_or; + Commitment avm_main_sel_op_xor; Commitment avm_main_alu_sel; + Commitment avm_main_bin_sel; Commitment avm_main_in_tag; Commitment avm_main_op_err; Commitment avm_main_tag_err; @@ -968,15 +1174,21 @@ class AvmFlavor { Commitment avm_main_mem_idx_b; Commitment avm_main_mem_idx_c; Commitment avm_main_last; + Commitment avm_main_bin_op_id; Commitment perm_main_alu; + Commitment perm_main_bin; Commitment perm_main_mem_a; Commitment perm_main_mem_b; Commitment perm_main_mem_c; Commitment perm_main_mem_ind_a; Commitment perm_main_mem_ind_b; Commitment perm_main_mem_ind_c; + Commitment lookup_byte_lengths; + Commitment lookup_byte_operations; Commitment incl_main_tag_err; Commitment incl_mem_tag_err; + Commitment lookup_byte_lengths_counts; + Commitment lookup_byte_operations_counts; Commitment incl_main_tag_err_counts; Commitment incl_mem_tag_err_counts; @@ -1047,6 +1259,27 @@ class AvmFlavor { avm_alu_alu_u64_r0 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_cf = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_op_eq_diff_inv = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_byte_lookup_table_op_id = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_byte_lookup_table_input_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_byte_lookup_table_input_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_byte_lookup_table_output = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_byte_lookup_bin_sel = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_byte_lookup_table_in_tags = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_byte_lookup_table_byte_lengths = + deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_bin_clk = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_bin_sel = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_acc_ia = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_acc_ib = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_acc_ic = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_in_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_op_id = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_bin_ia_bytes = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_bin_ib_bytes = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_bin_ic_bytes = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_start = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_mem_tag_ctr = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_binary_mem_tag_ctr_inv = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_pc = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_internal_return_ptr = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_internal_call = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -1060,7 +1293,11 @@ class AvmFlavor { avm_main_sel_op_div = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_op_not = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_op_eq = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_sel_op_and = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_sel_op_or = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_sel_op_xor = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_alu_sel = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_bin_sel = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_in_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_op_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -1084,15 +1321,21 @@ class AvmFlavor { avm_main_mem_idx_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_mem_idx_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_last = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_bin_op_id = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_alu = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + perm_main_bin = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_ind_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_ind_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_ind_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_byte_lengths = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_byte_operations = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_main_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_mem_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_byte_lengths_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_byte_operations_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_main_tag_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_mem_tag_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -1167,6 +1410,26 @@ class AvmFlavor { serialize_to_buffer(avm_alu_alu_u64_r0, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_cf, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_op_eq_diff_inv, Transcript::proof_data); + serialize_to_buffer(avm_byte_lookup_table_op_id, Transcript::proof_data); + serialize_to_buffer(avm_byte_lookup_table_input_a, Transcript::proof_data); + serialize_to_buffer(avm_byte_lookup_table_input_b, Transcript::proof_data); + serialize_to_buffer(avm_byte_lookup_table_output, Transcript::proof_data); + serialize_to_buffer(avm_byte_lookup_bin_sel, Transcript::proof_data); + serialize_to_buffer(avm_byte_lookup_table_in_tags, Transcript::proof_data); + serialize_to_buffer(avm_byte_lookup_table_byte_lengths, Transcript::proof_data); + serialize_to_buffer(avm_binary_bin_clk, Transcript::proof_data); + serialize_to_buffer(avm_binary_bin_sel, Transcript::proof_data); + serialize_to_buffer(avm_binary_acc_ia, Transcript::proof_data); + serialize_to_buffer(avm_binary_acc_ib, Transcript::proof_data); + serialize_to_buffer(avm_binary_acc_ic, Transcript::proof_data); + serialize_to_buffer(avm_binary_in_tag, Transcript::proof_data); + serialize_to_buffer(avm_binary_op_id, Transcript::proof_data); + serialize_to_buffer(avm_binary_bin_ia_bytes, Transcript::proof_data); + serialize_to_buffer(avm_binary_bin_ib_bytes, Transcript::proof_data); + serialize_to_buffer(avm_binary_bin_ic_bytes, Transcript::proof_data); + serialize_to_buffer(avm_binary_start, Transcript::proof_data); + serialize_to_buffer(avm_binary_mem_tag_ctr, Transcript::proof_data); + serialize_to_buffer(avm_binary_mem_tag_ctr_inv, Transcript::proof_data); serialize_to_buffer(avm_main_pc, Transcript::proof_data); serialize_to_buffer(avm_main_internal_return_ptr, Transcript::proof_data); serialize_to_buffer(avm_main_sel_internal_call, Transcript::proof_data); @@ -1180,7 +1443,11 @@ class AvmFlavor { serialize_to_buffer(avm_main_sel_op_div, Transcript::proof_data); serialize_to_buffer(avm_main_sel_op_not, Transcript::proof_data); serialize_to_buffer(avm_main_sel_op_eq, Transcript::proof_data); + serialize_to_buffer(avm_main_sel_op_and, Transcript::proof_data); + serialize_to_buffer(avm_main_sel_op_or, Transcript::proof_data); + serialize_to_buffer(avm_main_sel_op_xor, Transcript::proof_data); serialize_to_buffer(avm_main_alu_sel, Transcript::proof_data); + serialize_to_buffer(avm_main_bin_sel, Transcript::proof_data); serialize_to_buffer(avm_main_in_tag, Transcript::proof_data); serialize_to_buffer(avm_main_op_err, Transcript::proof_data); serialize_to_buffer(avm_main_tag_err, Transcript::proof_data); @@ -1204,15 +1471,21 @@ class AvmFlavor { serialize_to_buffer(avm_main_mem_idx_b, Transcript::proof_data); serialize_to_buffer(avm_main_mem_idx_c, Transcript::proof_data); serialize_to_buffer(avm_main_last, Transcript::proof_data); + serialize_to_buffer(avm_main_bin_op_id, Transcript::proof_data); serialize_to_buffer(perm_main_alu, Transcript::proof_data); + serialize_to_buffer(perm_main_bin, Transcript::proof_data); serialize_to_buffer(perm_main_mem_a, Transcript::proof_data); serialize_to_buffer(perm_main_mem_b, Transcript::proof_data); serialize_to_buffer(perm_main_mem_c, Transcript::proof_data); serialize_to_buffer(perm_main_mem_ind_a, Transcript::proof_data); serialize_to_buffer(perm_main_mem_ind_b, Transcript::proof_data); serialize_to_buffer(perm_main_mem_ind_c, Transcript::proof_data); + serialize_to_buffer(lookup_byte_lengths, Transcript::proof_data); + serialize_to_buffer(lookup_byte_operations, Transcript::proof_data); serialize_to_buffer(incl_main_tag_err, Transcript::proof_data); serialize_to_buffer(incl_mem_tag_err, Transcript::proof_data); + serialize_to_buffer(lookup_byte_lengths_counts, Transcript::proof_data); + serialize_to_buffer(lookup_byte_operations_counts, Transcript::proof_data); serialize_to_buffer(incl_main_tag_err_counts, Transcript::proof_data); serialize_to_buffer(incl_mem_tag_err_counts, Transcript::proof_data); diff --git a/cpp/src/barretenberg/vm/generated/avm_prover.hpp b/cpp/src/barretenberg/vm/generated/avm_prover.hpp index e5463dc4a..1e15b341e 100644 --- a/cpp/src/barretenberg/vm/generated/avm_prover.hpp +++ b/cpp/src/barretenberg/vm/generated/avm_prover.hpp @@ -6,6 +6,7 @@ #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/sumcheck/sumcheck_output.hpp" #include "barretenberg/transcript/transcript.hpp" + #include "barretenberg/vm/generated/avm_flavor.hpp" namespace bb { diff --git a/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/cpp/src/barretenberg/vm/generated/avm_verifier.cpp index 87e34d817..0f651bc29 100644 --- a/cpp/src/barretenberg/vm/generated/avm_verifier.cpp +++ b/cpp/src/barretenberg/vm/generated/avm_verifier.cpp @@ -136,6 +136,46 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.avm_alu_alu_cf = transcript->template receive_from_prover(commitment_labels.avm_alu_alu_cf); commitments.avm_alu_alu_op_eq_diff_inv = transcript->template receive_from_prover(commitment_labels.avm_alu_alu_op_eq_diff_inv); + commitments.avm_byte_lookup_table_op_id = + transcript->template receive_from_prover(commitment_labels.avm_byte_lookup_table_op_id); + commitments.avm_byte_lookup_table_input_a = + transcript->template receive_from_prover(commitment_labels.avm_byte_lookup_table_input_a); + commitments.avm_byte_lookup_table_input_b = + transcript->template receive_from_prover(commitment_labels.avm_byte_lookup_table_input_b); + commitments.avm_byte_lookup_table_output = + transcript->template receive_from_prover(commitment_labels.avm_byte_lookup_table_output); + commitments.avm_byte_lookup_bin_sel = + transcript->template receive_from_prover(commitment_labels.avm_byte_lookup_bin_sel); + commitments.avm_byte_lookup_table_in_tags = + transcript->template receive_from_prover(commitment_labels.avm_byte_lookup_table_in_tags); + commitments.avm_byte_lookup_table_byte_lengths = + transcript->template receive_from_prover(commitment_labels.avm_byte_lookup_table_byte_lengths); + commitments.avm_binary_bin_clk = + transcript->template receive_from_prover(commitment_labels.avm_binary_bin_clk); + commitments.avm_binary_bin_sel = + transcript->template receive_from_prover(commitment_labels.avm_binary_bin_sel); + commitments.avm_binary_acc_ia = + transcript->template receive_from_prover(commitment_labels.avm_binary_acc_ia); + commitments.avm_binary_acc_ib = + transcript->template receive_from_prover(commitment_labels.avm_binary_acc_ib); + commitments.avm_binary_acc_ic = + transcript->template receive_from_prover(commitment_labels.avm_binary_acc_ic); + commitments.avm_binary_in_tag = + transcript->template receive_from_prover(commitment_labels.avm_binary_in_tag); + commitments.avm_binary_op_id = + transcript->template receive_from_prover(commitment_labels.avm_binary_op_id); + commitments.avm_binary_bin_ia_bytes = + transcript->template receive_from_prover(commitment_labels.avm_binary_bin_ia_bytes); + commitments.avm_binary_bin_ib_bytes = + transcript->template receive_from_prover(commitment_labels.avm_binary_bin_ib_bytes); + commitments.avm_binary_bin_ic_bytes = + transcript->template receive_from_prover(commitment_labels.avm_binary_bin_ic_bytes); + commitments.avm_binary_start = + transcript->template receive_from_prover(commitment_labels.avm_binary_start); + commitments.avm_binary_mem_tag_ctr = + transcript->template receive_from_prover(commitment_labels.avm_binary_mem_tag_ctr); + commitments.avm_binary_mem_tag_ctr_inv = + transcript->template receive_from_prover(commitment_labels.avm_binary_mem_tag_ctr_inv); commitments.avm_main_pc = transcript->template receive_from_prover(commitment_labels.avm_main_pc); commitments.avm_main_internal_return_ptr = transcript->template receive_from_prover(commitment_labels.avm_main_internal_return_ptr); @@ -161,8 +201,16 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_not); commitments.avm_main_sel_op_eq = transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_eq); + commitments.avm_main_sel_op_and = + transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_and); + commitments.avm_main_sel_op_or = + transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_or); + commitments.avm_main_sel_op_xor = + transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_xor); commitments.avm_main_alu_sel = transcript->template receive_from_prover(commitment_labels.avm_main_alu_sel); + commitments.avm_main_bin_sel = + transcript->template receive_from_prover(commitment_labels.avm_main_bin_sel); commitments.avm_main_in_tag = transcript->template receive_from_prover(commitment_labels.avm_main_in_tag); commitments.avm_main_op_err = @@ -198,7 +246,10 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.avm_main_mem_idx_c = transcript->template receive_from_prover(commitment_labels.avm_main_mem_idx_c); commitments.avm_main_last = transcript->template receive_from_prover(commitment_labels.avm_main_last); + commitments.avm_main_bin_op_id = + transcript->template receive_from_prover(commitment_labels.avm_main_bin_op_id); commitments.perm_main_alu = transcript->template receive_from_prover(commitment_labels.perm_main_alu); + commitments.perm_main_bin = transcript->template receive_from_prover(commitment_labels.perm_main_bin); commitments.perm_main_mem_a = transcript->template receive_from_prover(commitment_labels.perm_main_mem_a); commitments.perm_main_mem_b = @@ -211,10 +262,18 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.perm_main_mem_ind_b); commitments.perm_main_mem_ind_c = transcript->template receive_from_prover(commitment_labels.perm_main_mem_ind_c); + commitments.lookup_byte_lengths = + transcript->template receive_from_prover(commitment_labels.lookup_byte_lengths); + commitments.lookup_byte_operations = + transcript->template receive_from_prover(commitment_labels.lookup_byte_operations); commitments.incl_main_tag_err = transcript->template receive_from_prover(commitment_labels.incl_main_tag_err); commitments.incl_mem_tag_err = transcript->template receive_from_prover(commitment_labels.incl_mem_tag_err); + commitments.lookup_byte_lengths_counts = + transcript->template receive_from_prover(commitment_labels.lookup_byte_lengths_counts); + commitments.lookup_byte_operations_counts = + transcript->template receive_from_prover(commitment_labels.lookup_byte_operations_counts); commitments.incl_main_tag_err_counts = transcript->template receive_from_prover(commitment_labels.incl_main_tag_err_counts); commitments.incl_mem_tag_err_counts = diff --git a/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp b/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp index 0fb368cb1..3399e5736 100644 --- a/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp +++ b/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp @@ -1,7 +1,13 @@ #include "avm_common.test.hpp" #include "barretenberg/numeric/uint128/uint128.hpp" +#include "barretenberg/vm/tests/helpers.test.hpp" +#include "gtest/gtest.h" #include +#include #include +#include +#include +#include #include namespace tests_avm { @@ -9,12 +15,12 @@ using namespace bb::avm_trace; namespace { -Row common_validate_op_not(std::vector const& trace, - FF const& a, - FF const& c, - FF const& addr_a, - FF const& addr_c, - avm_trace::AvmMemoryTag const tag) +void common_validate_op_not(std::vector const& trace, + FF const& a, + FF const& c, + FF const& addr_a, + FF const& addr_c, + avm_trace::AvmMemoryTag const tag) { // Find the first row enabling the not selector @@ -51,8 +57,90 @@ Row common_validate_op_not(std::vector const& trace, // Check that not selector is set. EXPECT_EQ(row->avm_main_sel_op_not, FF(1)); EXPECT_EQ(alu_row->avm_alu_alu_op_not, FF(1)); + switch (tag) { + // Handle the different mem_tags here since this is part of a + // parameterised test + case AvmMemoryTag::U0: + FAIL() << "Unintialized Mem Tags Disallowed"; + break; + case AvmMemoryTag::U8: + EXPECT_EQ(alu_row->avm_alu_alu_u8_tag, FF(1)); + break; + case AvmMemoryTag::U16: + EXPECT_EQ(alu_row->avm_alu_alu_u16_tag, FF(1)); + break; + case AvmMemoryTag::U32: + EXPECT_EQ(alu_row->avm_alu_alu_u32_tag, FF(1)); + break; + case AvmMemoryTag::U64: + EXPECT_EQ(alu_row->avm_alu_alu_u64_tag, FF(1)); + break; + case AvmMemoryTag::U128: + EXPECT_EQ(alu_row->avm_alu_alu_u128_tag, FF(1)); + break; + case AvmMemoryTag::FF: + FAIL() << "FF Mem Tags Disallowed for bitwise"; + break; + } +} + +void common_validate_bit_op(std::vector const& trace, + uint8_t op_id, + FF const& a, + FF const& b, + FF const& c, + FF const& addr_a, + FF const& addr_b, + FF const& addr_c, + avm_trace::AvmMemoryTag const tag) +{ + + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_xor == FF(1); }); + if (op_id == 0) { + row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_and == FF(1); }); + } else if (op_id == 1) { + row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_or == FF(1); }); + } + + // Use the row in the main trace to find the same operation in the alu trace. + FF clk = row->avm_main_clk; + auto bin_row_start = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.avm_binary_bin_clk == clk && r.avm_binary_start == FF(1); + }); + + // Check that both rows were found + ASSERT_TRUE(bin_row_start != trace.end()); + ASSERT_TRUE(row != trace.end()); + + // Check that the correct result is stored at the expected memory location. + EXPECT_EQ(row->avm_main_ic, c); + EXPECT_EQ(row->avm_main_mem_idx_c, addr_c); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + EXPECT_EQ(row->avm_main_rwc, FF(1)); + + // Check that ia register is correctly set with memory load operations. + EXPECT_EQ(row->avm_main_ia, a); + EXPECT_EQ(row->avm_main_mem_idx_a, addr_a); + EXPECT_EQ(row->avm_main_mem_op_a, FF(1)); + EXPECT_EQ(row->avm_main_rwa, FF(0)); + + // Check that ia register is correctly set with memory load operations. + EXPECT_EQ(row->avm_main_ib, b); + EXPECT_EQ(row->avm_main_mem_idx_b, addr_b); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + EXPECT_EQ(row->avm_main_rwb, FF(0)); + + // Check the instruction tag + EXPECT_EQ(row->avm_main_in_tag, FF(static_cast(tag))); + + // Check that start row is the same as what is copied into the main trace + EXPECT_EQ(bin_row_start->avm_binary_acc_ia, a); + EXPECT_EQ(bin_row_start->avm_binary_acc_ib, b); + EXPECT_EQ(bin_row_start->avm_binary_acc_ic, c); - return *alu_row; + EXPECT_EQ(bin_row_start->avm_binary_op_id, op_id); + EXPECT_EQ(bin_row_start->avm_binary_bin_sel, FF(1)); + EXPECT_EQ(bin_row_start->avm_binary_in_tag, static_cast(tag)); } std::vector gen_mutated_trace_not(FF const& a, FF const& c_mutated, avm_trace::AvmMemoryTag tag) @@ -68,6 +156,96 @@ std::vector gen_mutated_trace_not(FF const& a, FF const& c_mutated, avm_tra return trace; } + +// These are the potential failures we handle for the negative tests involving the binary trace. +enum BIT_FAILURES { + BitDecomposition, + MemTagCtr, + IncorrectAcc, + InconsistentOpId, + ByteLookupError, + ByteLengthError, + IncorrectBinSelector, +}; +std::vector gen_mutated_trace_bit(std::vector trace, + std::function&& select_row, + FF const& c_mutated, + BIT_FAILURES fail_mode) +{ + auto main_trace_row = std::ranges::find_if(trace.begin(), trace.end(), select_row); + auto main_clk = main_trace_row->avm_main_clk; + // The corresponding row in the binary trace as well as the row where start = 1 + auto binary_row = std::ranges::find_if( + trace.begin(), trace.end(), [main_clk](Row r) { return r.avm_binary_bin_clk == main_clk; }); + // The corresponding row in the binary trace where the computation ends. + auto last_row = std::ranges::find_if(trace.begin(), trace.end(), [main_clk](Row r) { + return r.avm_binary_bin_clk == main_clk && r.avm_binary_mem_tag_ctr == FF(0); + }); + switch (fail_mode) { + case BitDecomposition: { + // Incrementing the bytes should indicate an incorrect decomposition + // The lookups are checked later so this will throw an error about decomposition + binary_row->avm_binary_bin_ic_bytes++; + break; + } + case MemTagCtr: { + // Increment instead of decrementing + binary_row->avm_binary_mem_tag_ctr++; + break; + } + case IncorrectAcc: { + // The lookups are checked later so this will throw an error about accumulation + binary_row->avm_binary_acc_ic++; + break; + } + case InconsistentOpId: { + // We don't update the first index as that is checked by the permutation check. + // So we update the next op_id to be incorrect. + auto first_index = static_cast(std::distance(trace.begin(), binary_row)); + trace.at(first_index + 1).avm_binary_op_id++; + break; + } + case ByteLookupError: { + // Update the trace to be the mutated value, which also (conveniently) + // fits into a byte so we can also update the ic_byte decomposition. + // We intentionally select the mutated value to be 0-bytes everywhere else so we dont need to + // update anything there or in the corresponding accumulators. + mutate_ic_in_trace(trace, std::move(select_row), c_mutated, false); + binary_row->avm_binary_acc_ic = c_mutated; + binary_row->avm_binary_bin_ic_bytes = static_cast(uint128_t{ c_mutated }); + break; + } + case ByteLengthError: { + // To trigger this error, we need to start the mem_tag ctr to be incorrect (one less than is should be) + // However, to avoid the MEM_REL_TAG error from happening instead, we need to ensure we update the mem_tag + // of all rows between the start = 1 and mem_tag = 0; + auto last_index = static_cast(std::distance(trace.begin(), last_row)); + auto first_index = static_cast(std::distance(trace.begin(), binary_row)); + for (size_t i = first_index; i <= last_index; i++) { + FF ctr = trace.at(i).avm_binary_mem_tag_ctr; + if (ctr == FF::one()) { + // If the tag is currently 1, it will be set to 0 which means we need to set bin_sel to 0. + trace.at(i).avm_binary_bin_sel = FF(0); + trace.at(i).avm_binary_mem_tag_ctr = FF(0); + trace.at(i).avm_binary_mem_tag_ctr_inv = FF(0); + } else if (ctr == FF::zero()) { + // Leave as zero instead of underflowing + trace.at(i).avm_binary_mem_tag_ctr = FF(0); + } else { + // Replace the values with the next row's values + trace.at(i).avm_binary_mem_tag_ctr = trace.at(i + 1).avm_binary_mem_tag_ctr; + trace.at(i).avm_binary_mem_tag_ctr_inv = trace.at(i + 1).avm_binary_mem_tag_ctr_inv; + trace.at(i).avm_binary_bin_sel = trace.at(i + 1).avm_binary_bin_sel; + } + } + break; + } + case IncorrectBinSelector: + binary_row->avm_binary_bin_sel = FF(0); + break; + } + return trace; +} } // namespace class AvmBitwiseTests : public ::testing::Test { @@ -79,18 +257,79 @@ class AvmBitwiseTests : public ::testing::Test { void SetUp() override { srs::init_crs_factory("../srs_db/ignition"); }; }; -class AvmBitwiseTestsU8 : public AvmBitwiseTests {}; -class AvmBitwiseTestsU16 : public AvmBitwiseTests {}; -class AvmBitwiseTestsU32 : public AvmBitwiseTests {}; -class AvmBitwiseTestsU64 : public AvmBitwiseTests {}; -class AvmBitwiseTestsU128 : public AvmBitwiseTests {}; +/****************************************************************************** + * + * Helpers to set up Test Params + * + ******************************************************************************/ -class AvmBitwiseNegativeTestsFF : public AvmBitwiseTests {}; -class AvmBitwiseNegativeTestsU8 : public AvmBitwiseTests {}; -class AvmBitwiseNegativeTestsU16 : public AvmBitwiseTests {}; -class AvmBitwiseNegativeTestsU32 : public AvmBitwiseTests {}; -class AvmBitwiseNegativeTestsU64 : public AvmBitwiseTests {}; -class AvmBitwiseNegativeTestsU128 : public AvmBitwiseTests {}; +using ThreeOpParamRow = std::tuple, AvmMemoryTag>; +using TwoOpParamRow = std::tuple, AvmMemoryTag>; +std::vector mem_tags{ + { AvmMemoryTag::U8, AvmMemoryTag::U16, AvmMemoryTag::U32, AvmMemoryTag::U64, AvmMemoryTag::U128 } +}; + +std::vector> positive_op_not_test_values = { { { 1, 254 }, + { 512, 65'023 }, + { 131'072, 4'294'836'223LLU }, + { 0x100000000LLU, 0xfffffffeffffffffLLU }, + { uint128_t{ 0x4000000000000 } << 64, + (uint128_t{ 0xfffbffffffffffff } << 64) + + uint128_t{ 0xffffffffffffffff } } } }; + +// This is essentially a zip while we wait for C++23 +std::vector gen_two_op_params(std::vector> operands, + std::vector mem_tags) +{ + std::vector params; + for (size_t i = 0; i < 5; i++) { + params.emplace_back(operands[i], mem_tags[i]); + } + return params; +} + +std::vector> positive_op_and_test_values = { + { { 1, 1, 1 }, + { 5323, 321, 65 }, + { 13793, 10590617LLU, 4481 }, + { 0x7bff744e3cdf79LLU, 0x14ccccccccb6LLU, 0x14444c0ccc30LLU }, + { (uint128_t{ 0xb900000000000001 } << 64), + (uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, + (uint128_t{ 0x1000000000000000 } << 64) } } +}; + +std::vector> positive_op_or_test_values = { + { { 1, 1, 1 }, + { 5323, 321, 0x15cb }, + { 13793, 10590617LLU, 0xa1bdf9 }, + { 0x7bff744e3cdf79LLU, 0x14ccccccccb6LLU, 0x7bfffccefcdfffLLU }, + { (uint128_t{ 0xb900000000000000 } << 64), + (uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, + (uint128_t{ 0xb906021301080000 } << 64) + uint128_t{ 0x0001080876844827 } } } +}; +std::vector> positive_op_xor_test_values = { + { { 1, 1, 0 }, + { 5323, 321, 0x158a }, + { 13793, 10590617LLU, 0xa1ac78 }, + { 0x7bff744e3cdf79LLU, 0x14ccccccccb6LLU, 0x7bebb882f013cf }, + { (uint128_t{ 0xb900000000000001 } << 64), + (uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, + (uint128_t{ 0xa906021301080001 } << 64) + uint128_t{ 0x0001080876844827 } } } +}; +std::vector gen_three_op_params(std::vector> operands, + std::vector mem_tags) +{ + std::vector params; + for (size_t i = 0; i < 5; i++) { + params.emplace_back(operands[i], mem_tags[i]); + } + return params; +} + +class AvmBitwiseTestsNot : public AvmBitwiseTests, public testing::WithParamInterface {}; +class AvmBitwiseTestsAnd : public AvmBitwiseTests, public testing::WithParamInterface {}; +class AvmBitwiseTestsOr : public AvmBitwiseTests, public testing::WithParamInterface {}; +class AvmBitwiseTestsXor : public AvmBitwiseTests, public testing::WithParamInterface {}; /****************************************************************************** * @@ -101,79 +340,90 @@ class AvmBitwiseNegativeTestsU128 : public AvmBitwiseTests {}; ******************************************************************************/ /****************************************************************************** - * Positive Tests - U8 + * Positive Tests ******************************************************************************/ - -TEST_F(AvmBitwiseTestsU8, BitwiseNot) +TEST_P(AvmBitwiseTestsNot, ParamTest) { - trace_builder.set(1, 0, AvmMemoryTag::U8); // Memory Layout: [1,0,0,...] - trace_builder.op_not(0, 0, 1, AvmMemoryTag::U8); // [1,254,0,0,....] + const auto [operands, mem_tag] = GetParam(); + const auto [a, output] = operands; + trace_builder.set(a, 0, mem_tag); + trace_builder.op_not(0, 0, 1, mem_tag); // [1,254,0,0,....] trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); - - auto alu_row = common_validate_op_not(trace, FF(1), FF(254), FF(0), FF(1), AvmMemoryTag::U8); - - EXPECT_EQ(alu_row.avm_alu_alu_u8_tag, FF(1)); + FF ff_a = FF(uint256_t::from_uint128(a)); + FF ff_output = FF(uint256_t::from_uint128(output)); + common_validate_op_not(trace, ff_a, ff_output, FF(0), FF(1), mem_tag); validate_trace_proof(std::move(trace)); } -TEST_F(AvmBitwiseTestsU16, BitwiseNot) -{ - trace_builder.set(512, 0, AvmMemoryTag::U16); // Memory Layout: [512,0,0,...] - trace_builder.op_not(0, 0, 1, AvmMemoryTag::U16); // [512,65023,0,0,0,....] - trace_builder.return_op(0, 0, 0); - auto trace = trace_builder.finalize(); - - auto alu_row = common_validate_op_not(trace, FF(512), FF(65'023), FF(0), FF(1), AvmMemoryTag::U16); - - EXPECT_EQ(alu_row.avm_alu_alu_u16_tag, FF(1)); - validate_trace_proof(std::move(trace)); -} +INSTANTIATE_TEST_SUITE_P(AvmBitwiseTests, + AvmBitwiseTestsNot, + testing::ValuesIn(gen_two_op_params(positive_op_not_test_values, mem_tags))); -TEST_F(AvmBitwiseTestsU32, BitwiseNot) +TEST_P(AvmBitwiseTestsAnd, AllAndTest) { - trace_builder.set(131'072, 0, AvmMemoryTag::U32); // Memory Layout: [131072,0,0,...] - trace_builder.op_not(0, 0, 1, AvmMemoryTag::U32); // [131072,4294836223,,0,0,....] - trace_builder.return_op(0, 0, 0); - auto trace = trace_builder.finalize(); - - auto alu_row = common_validate_op_not(trace, FF(131'072), FF(4'294'836'223LLU), FF(0), FF(1), AvmMemoryTag::U32); + const auto [operands, mem_tag] = GetParam(); + const auto [a, b, output] = operands; + trace_builder.set(a, 0, mem_tag); + trace_builder.set(b, 1, mem_tag); + trace_builder.op_and(0, 0, 1, 2, mem_tag); + trace_builder.return_op(0, 2, 1); - EXPECT_EQ(alu_row.avm_alu_alu_u32_tag, FF(1)); + auto trace = trace_builder.finalize(); + FF ff_a = FF(uint256_t::from_uint128(a)); + FF ff_b = FF(uint256_t::from_uint128(b)); + FF ff_output = FF(uint256_t::from_uint128(output)); + // EXPECT_EQ(1, 2) << "a ^ b " << (a ^ b) << '\n'; + common_validate_bit_op(trace, 0, ff_a, ff_b, ff_output, FF(0), FF(1), FF(2), mem_tag); validate_trace_proof(std::move(trace)); } +INSTANTIATE_TEST_SUITE_P(AvmBitwiseTests, + AvmBitwiseTestsAnd, + testing::ValuesIn(gen_three_op_params(positive_op_and_test_values, mem_tags))); -TEST_F(AvmBitwiseTestsU64, BitwiseNot) +TEST_P(AvmBitwiseTestsOr, AllOrTest) { - trace_builder.set(0x100000000LLU, 0, AvmMemoryTag::U64); // Memory Layout: [8589934592,0,0,...] - trace_builder.op_not(0, 0, 1, AvmMemoryTag::U64); // [8589934592,18446744069414584319,0,0,....] - trace_builder.return_op(0, 0, 0); + const auto [operands, mem_tag] = GetParam(); + const auto [a, b, output] = operands; + trace_builder.set(a, 0, mem_tag); + trace_builder.set(b, 1, mem_tag); + trace_builder.op_or(0, 0, 1, 2, mem_tag); + trace_builder.return_op(0, 2, 1); auto trace = trace_builder.finalize(); - auto alu_row = - common_validate_op_not(trace, FF(0x100000000LLU), FF(0xfffffffeffffffffLLU), FF(0), FF(1), AvmMemoryTag::U64); + FF ff_a = FF(uint256_t::from_uint128(a)); + FF ff_b = FF(uint256_t::from_uint128(b)); + FF ff_output = FF(uint256_t::from_uint128(output)); - EXPECT_EQ(alu_row.avm_alu_alu_u64_tag, FF(1)); + common_validate_bit_op(trace, 1, ff_a, ff_b, ff_output, FF(0), FF(1), FF(2), mem_tag); validate_trace_proof(std::move(trace)); } +INSTANTIATE_TEST_SUITE_P(AvmBitwiseTests, + AvmBitwiseTestsOr, + testing::ValuesIn(gen_three_op_params(positive_op_or_test_values, mem_tags))); -TEST_F(AvmBitwiseTestsU128, BitwiseNot) +TEST_P(AvmBitwiseTestsXor, AllXorTest) { - - uint128_t const a = uint128_t{ 0x4000000000000 } << 64; - trace_builder.set(a, 0, AvmMemoryTag::U128); - trace_builder.op_not(0, 0, 1, AvmMemoryTag::U128); - trace_builder.return_op(0, 0, 0); + const auto [operands, mem_tag] = GetParam(); + const auto [a, b, output] = operands; + trace_builder.set(a, 0, mem_tag); + trace_builder.set(b, 1, mem_tag); + trace_builder.op_xor(0, 0, 1, 2, mem_tag); + trace_builder.return_op(0, 2, 1); auto trace = trace_builder.finalize(); - uint128_t const res = (uint128_t{ 0xfffbffffffffffff } << 64) + uint128_t{ 0xffffffffffffffff }; - auto alu_row = common_validate_op_not( - trace, FF(uint256_t::from_uint128(a)), FF(uint256_t::from_uint128(res)), FF(0), FF(1), AvmMemoryTag::U128); + FF ff_a = FF(uint256_t::from_uint128(a)); + FF ff_b = FF(uint256_t::from_uint128(b)); + FF ff_output = FF(uint256_t::from_uint128(output)); - EXPECT_EQ(alu_row.avm_alu_alu_u128_tag, FF(1)); + common_validate_bit_op(trace, 2, ff_a, ff_b, ff_output, FF(0), FF(1), FF(2), mem_tag); validate_trace_proof(std::move(trace)); } +INSTANTIATE_TEST_SUITE_P(AvmBitwiseTests, + AvmBitwiseTestsXor, + testing::ValuesIn(gen_three_op_params(positive_op_xor_test_values, mem_tags))); + /****************************************************************************** * * NEGATIVE TESTS - Finite Field Type @@ -181,10 +431,100 @@ TEST_F(AvmBitwiseTestsU128, BitwiseNot) ****************************************************************************** * See Avm_arithmetic.cpp for explanation of negative tests ******************************************************************************/ +using EXPECTED_ERRORS = std::tuple; + +class AvmBitwiseNegativeTestsAnd : public AvmBitwiseTests, + public testing::WithParamInterface> {}; +class AvmBitwiseNegativeTestsOr : public AvmBitwiseTests, + public testing::WithParamInterface> {}; +class AvmBitwiseNegativeTestsXor : public AvmBitwiseTests, + public testing::WithParamInterface> {}; +class AvmBitwiseNegativeTestsFF : public AvmBitwiseTests {}; +class AvmBitwiseNegativeTestsU8 : public AvmBitwiseTests {}; +class AvmBitwiseNegativeTestsU16 : public AvmBitwiseTests {}; +class AvmBitwiseNegativeTestsU32 : public AvmBitwiseTests {}; +class AvmBitwiseNegativeTestsU64 : public AvmBitwiseTests {}; +class AvmBitwiseNegativeTestsU128 : public AvmBitwiseTests {}; +std::vector> bit_failures = { + { "ACC_REL_C", BIT_FAILURES::IncorrectAcc }, + { "ACC_REL_C", BIT_FAILURES::BitDecomposition }, + { "MEM_TAG_REL", BIT_FAILURES::MemTagCtr }, + { "LOOKUP_BYTE_LENGTHS", BIT_FAILURES::ByteLengthError }, + { "LOOKUP_BYTE_OPERATIONS", BIT_FAILURES::ByteLookupError }, + { "OP_ID_REL", BIT_FAILURES::InconsistentOpId }, + { "BIN_SEL_CTR_REL", BIT_FAILURES::IncorrectBinSelector }, +}; +// For the negative test the output is set to be incorrect so that we can test the byte lookups. +// Picking "simple" inputs such as zero also makes it easier when check the byte length lookups as we dont +// need to worry about copying the accmulated a & b registers into the main trace. +std::vector neg_test_and = { { { 0, 0, 1 }, AvmMemoryTag::U32 } }; +std::vector neg_test_or = { { { 0, 0, 1 }, AvmMemoryTag::U32 } }; +std::vector neg_test_xor = { { { 0, 0, 1 }, AvmMemoryTag::U32 } }; /****************************************************************************** * Negative Tests - FF ******************************************************************************/ +TEST_P(AvmBitwiseNegativeTestsAnd, AllNegativeTests) +{ + const auto [failure, params] = GetParam(); + const auto [failure_string, failure_mode] = failure; + const auto [operands, mem_tag] = params; + const auto [a, b, output] = operands; + auto trace_builder = avm_trace::AvmTraceBuilder(); + trace_builder.set(uint128_t{ a }, 0, mem_tag); + trace_builder.set(uint128_t{ b }, 1, mem_tag); + trace_builder.op_and(0, 0, 1, 2, mem_tag); + trace_builder.halt(); + auto trace = trace_builder.finalize(); + FF ff_output = FF(uint256_t::from_uint128(output)); + std::function&& select_row = [](Row r) { return r.avm_main_sel_op_and == FF(1); }; + trace = gen_mutated_trace_bit(trace, std::move(select_row), ff_output, failure_mode); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), failure_string); +} +INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, + AvmBitwiseNegativeTestsAnd, + testing::Combine(testing::ValuesIn(bit_failures), testing::ValuesIn(neg_test_and))); + +TEST_P(AvmBitwiseNegativeTestsOr, AllNegativeTests) +{ + const auto [failure, params] = GetParam(); + const auto [failure_string, failure_mode] = failure; + const auto [operands, mem_tag] = params; + const auto [a, b, output] = operands; + auto trace_builder = avm_trace::AvmTraceBuilder(); + trace_builder.set(uint128_t{ a }, 0, mem_tag); + trace_builder.set(uint128_t{ b }, 1, mem_tag); + trace_builder.op_or(0, 0, 1, 2, mem_tag); + trace_builder.halt(); + auto trace = trace_builder.finalize(); + FF ff_output = FF(uint256_t::from_uint128(output)); + std::function&& select_row = [](Row r) { return r.avm_main_sel_op_or == FF(1); }; + trace = gen_mutated_trace_bit(trace, std::move(select_row), ff_output, failure_mode); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), failure_string); +} +INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, + AvmBitwiseNegativeTestsOr, + testing::Combine(testing::ValuesIn(bit_failures), testing::ValuesIn(neg_test_or))); +TEST_P(AvmBitwiseNegativeTestsXor, AllNegativeTests) +{ + const auto [failure, params] = GetParam(); + const auto [failure_string, failure_mode] = failure; + const auto [operands, mem_tag] = params; + const auto [a, b, output] = operands; + auto trace_builder = avm_trace::AvmTraceBuilder(); + trace_builder.set(uint128_t{ a }, 0, mem_tag); + trace_builder.set(uint128_t{ b }, 1, mem_tag); + trace_builder.op_xor(0, 0, 1, 2, mem_tag); + trace_builder.halt(); + auto trace = trace_builder.finalize(); + FF ff_output = FF(uint256_t::from_uint128(output)); + std::function&& select_row = [](Row r) { return r.avm_main_sel_op_xor == FF(1); }; + trace = gen_mutated_trace_bit(trace, std::move(select_row), ff_output, failure_mode); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), failure_string) +} +INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, + AvmBitwiseNegativeTestsXor, + testing::Combine(testing::ValuesIn(bit_failures), testing::ValuesIn(neg_test_xor))); TEST_F(AvmBitwiseNegativeTestsFF, UndefinedOverFF) {