diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index f7f6089020f1..d3cedc565a6b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -441,7 +441,7 @@ template class ZeroMorphVerifier_ { using Curve = typename PCS::Curve; using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; - using VerifierAccumulator = PCS::VerifierAccumulator; + using VerifierAccumulator = typename PCS::VerifierAccumulator; public: /** diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index a27536a08f82..f1c95d0e9278 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -101,38 +101,44 @@ std::vector Execution::gen_trace(std::vector const& instructio // Compute // Compute - Arithmetic case OpCode::ADD: - trace_builder.op_add(std::get(inst.operands.at(2)), + trace_builder.op_add(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::SUB: - trace_builder.op_sub(std::get(inst.operands.at(2)), + trace_builder.op_sub(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::MUL: - trace_builder.op_mul(std::get(inst.operands.at(2)), + trace_builder.op_mul(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::DIV: - trace_builder.op_div(std::get(inst.operands.at(2)), + trace_builder.op_div(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; // Compute - Bitwise case OpCode::NOT: - trace_builder.op_not(std::get(inst.operands.at(2)), + trace_builder.op_not(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), 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(1)), + trace_builder.calldata_copy(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), calldata); @@ -185,8 +191,9 @@ std::vector Execution::gen_trace(std::vector const& instructio break; // Control Flow - Contract Calls case OpCode::RETURN: - // Skip indirect at index 0 - trace_builder.return_op(std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); + trace_builder.return_op(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), + std::get(inst.operands.at(2))); break; default: break; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp index 60e47489a4e9..2a2784ee7319 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp @@ -84,4 +84,13 @@ void log_avm_trace(std::vector const& trace, size_t beg, size_t end, bool e } } +bool is_operand_indirect(uint8_t ind_value, uint8_t operand_idx) +{ + if (operand_idx > 7) { + return false; + } + + return static_cast((ind_value & (1 << operand_idx)) >> operand_idx); +} + } // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp index a9e08ecd5cc4..2808f02dd4e3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp @@ -6,4 +6,6 @@ namespace bb::avm_trace { void log_avm_trace(std::vector const& trace, size_t beg, size_t end, bool enable_selectors = false); +bool is_operand_indirect(uint8_t ind_value, uint8_t operand_idx); + } // namespace bb::avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index 805cae56f9e5..57e21c331cd8 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -8,9 +8,10 @@ #include #include +#include "avm_common.hpp" +#include "avm_helper.hpp" +#include "avm_mem_trace.hpp" #include "avm_trace.hpp" -#include "barretenberg/vm/avm_trace/avm_common.hpp" -#include "barretenberg/vm/avm_trace/avm_mem_trace.hpp" namespace bb::avm_trace { @@ -34,22 +35,70 @@ void AvmTraceBuilder::reset() alu_trace_builder.reset(); } +AvmTraceBuilder::IndirectThreeResolution AvmTraceBuilder::resolve_ind_three( + uint32_t clk, uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset) +{ + bool indirect_flag_a = is_operand_indirect(indirect, 0); + bool indirect_flag_b = is_operand_indirect(indirect, 1); + bool indirect_flag_c = is_operand_indirect(indirect, 2); + + uint32_t direct_a_offset = a_offset; + uint32_t direct_b_offset = b_offset; + uint32_t direct_dst_offset = dst_offset; + + bool tag_match = true; + + if (indirect_flag_a) { + auto read_ind_a = mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, a_offset); + direct_a_offset = uint32_t(read_ind_a.val); + tag_match = tag_match && read_ind_a.tag_match; + } + + if (indirect_flag_b) { + auto read_ind_b = mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_B, b_offset); + direct_b_offset = uint32_t(read_ind_b.val); + tag_match = tag_match && read_ind_b.tag_match; + } + + if (indirect_flag_c) { + auto read_ind_c = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_C, dst_offset); + direct_dst_offset = uint32_t(read_ind_c.val); + tag_match = tag_match && read_ind_c.tag_match; + } + + return IndirectThreeResolution{ + .tag_match = tag_match, + .direct_a_offset = direct_a_offset, + .direct_b_offset = direct_b_offset, + .direct_dst_offset = direct_dst_offset, + .indirect_flag_a = indirect_flag_a, + .indirect_flag_b = indirect_flag_b, + .indirect_flag_c = indirect_flag_c, + }; +} + /** - * @brief Addition with direct memory access. + * @brief Addition with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the addition. * @param b_offset An index in memory pointing to the second operand of the addition. * @param dst_offset An index in memory pointing to the output of the addition. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_add( + 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, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + 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; // a + b = c FF a = read_a.val; @@ -61,7 +110,7 @@ void AvmTraceBuilder::op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ FF c = tag_match ? alu_trace_builder.op_add(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, dst_offset, c, in_tag); + 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, @@ -77,28 +126,39 @@ void AvmTraceBuilder::op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .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), }); -}; +} /** - * @brief Subtraction with direct memory access. + * @brief Subtraction with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the subtraction. * @param b_offset An index in memory pointing to the second operand of the subtraction. * @param dst_offset An index in memory pointing to the output of the subtraction. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_sub( + 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, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + 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; // a - b = c FF a = read_a.val; @@ -110,7 +170,7 @@ void AvmTraceBuilder::op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ FF c = tag_match ? alu_trace_builder.op_sub(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, dst_offset, c, in_tag); + 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, @@ -126,28 +186,39 @@ void AvmTraceBuilder::op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .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), }); -}; +} /** - * @brief Multiplication with direct memory access. + * @brief Multiplication with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the multiplication. * @param b_offset An index in memory pointing to the second operand of the multiplication. * @param dst_offset An index in memory pointing to the output of the multiplication. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_mul( + 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, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + 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; // a * b = c FF a = read_a.val; @@ -159,7 +230,7 @@ void AvmTraceBuilder::op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ FF c = tag_match ? alu_trace_builder.op_mul(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, dst_offset, c, in_tag); + 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, @@ -175,28 +246,39 @@ void AvmTraceBuilder::op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .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), }); } /** TODO: Implement for non finite field types - * @brief Division with direct memory access. + * @brief Division with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the division. * @param b_offset An index in memory pointing to the second operand of the division. * @param dst_offset An index in memory pointing to the output of the division. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_div( + 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, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + 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; // a * b^(-1) = c FF a = read_a.val; @@ -217,7 +299,7 @@ void AvmTraceBuilder::op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ } // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + 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, @@ -235,36 +317,63 @@ void AvmTraceBuilder::op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .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), }); } /** - * @brief Bitwise not with direct memory access. + * @brief Bitwise not with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the only operand of Not. * @param dst_offset An index in memory pointing to the output of Not. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_not(uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_not(uint8_t indirect, uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag) { auto clk = static_cast(main_trace.size()); + bool tag_match = true; + uint32_t direct_a_offset = a_offset; + uint32_t direct_dst_offset = dst_offset; - // Reading from memory and loading into ia. - auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, a_offset, in_tag); + bool indirect_a_flag = is_operand_indirect(indirect, 0); + bool indirect_c_flag = is_operand_indirect(indirect, 1); + + if (indirect_a_flag) { + auto read_ind_a = mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, a_offset); + tag_match = read_ind_a.tag_match; + direct_a_offset = uint32_t(read_ind_a.val); + } + if (indirect_c_flag) { + auto read_ind_c = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_C, dst_offset); + tag_match = tag_match && read_ind_c.tag_match; + direct_dst_offset = uint32_t(read_ind_c.val); + } + + // Reading from memory and loading into ia. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, direct_a_offset, in_tag); + tag_match = read_a.tag_match && tag_match; // ~a = c FF a = read_a.val; // In case of a memory tag error, we do not perform the computation. // Therefore, we do not create any entry in ALU table and store the value 0 as // output (c) in memory. - FF c = read_a.tag_match ? alu_trace_builder.op_not(a, in_tag, clk) : FF(0); + FF c = tag_match ? alu_trace_builder.op_not(a, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, direct_dst_offset, c, in_tag); + main_trace.push_back(Row{ .avm_main_clk = clk, .avm_main_pc = FF(pc++), @@ -277,27 +386,36 @@ void AvmTraceBuilder::op_not(uint32_t a_offset, uint32_t dst_offset, AvmMemoryTa .avm_main_mem_op_a = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_ind_a = indirect_a_flag ? FF(a_offset) : FF(0), + .avm_main_ind_c = indirect_c_flag ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(indirect_a_flag)), + .avm_main_ind_op_c = FF(static_cast(indirect_c_flag)), + .avm_main_mem_idx_a = FF(direct_a_offset), + .avm_main_mem_idx_c = FF(direct_dst_offset), }); -}; +} /** - * @brief Equality with direct memory access. + * @brief Equality with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the equality. * @param b_offset An index in memory pointing to the second operand of the equality. * @param dst_offset An index in memory pointing to the output of the equality. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_eq( + 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, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + 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; // c = a == b ? 1 : 0 FF a = read_a.val; @@ -309,7 +427,7 @@ void AvmTraceBuilder::op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_o FF c = tag_match ? alu_trace_builder.op_eq(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, dst_offset, c, in_tag); + 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, @@ -325,9 +443,15 @@ void AvmTraceBuilder::op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_o .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .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), }); } @@ -378,8 +502,8 @@ void AvmTraceBuilder::op_mov(uint8_t indirect, uint32_t src_offset, uint32_t dst uint32_t direct_src_offset = src_offset; uint32_t direct_dst_offset = dst_offset; - bool indirect_src_flag = static_cast(indirect & 0x01); - bool indirect_dst_flag = static_cast((indirect & 0x02) >> 1); + bool indirect_src_flag = is_operand_indirect(indirect, 0); + bool indirect_dst_flag = is_operand_indirect(indirect, 1); if (indirect_src_flag) { auto read_ind_a = @@ -424,28 +548,27 @@ void AvmTraceBuilder::op_mov(uint8_t indirect, uint32_t src_offset, uint32_t dst /** * @brief CALLDATACOPY opcode with direct memory access, i.e., - * M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + * direct: M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + * indirect: M[M[dst_offset]:M[dst_offset]+copy_size] = calldata[cd_offset:cd_offset+copy_size] * Simplified version with exclusively memory store operations and - * values from M_calldata passed by an array and loaded into + * values from calldata passed by an array and loaded into * intermediate registers. * Assume that caller passes call_data_mem which is large enough so that * no out-of-bound memory issues occur. - * TODO: Implement the indirect memory version (maybe not required) * TODO: taking care of intermediate register values consistency and propagating their * values to the next row when not overwritten. * TODO: error handling if dst_offset + copy_size > 2^32 which would lead to * out-of-bound memory write. Similarly, if cd_offset + copy_size is larger * than call_data_mem.size() * + * @param indirect A byte encoding information about indirect/direct memory access. * @param cd_offset The starting index of the region in calldata to be copied. * @param copy_size The number of finite field elements to be copied into memory. * @param dst_offset The starting index of memory where calldata will be copied to. * @param call_data_mem The vector containing calldata. */ -void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, - uint32_t copy_size, - uint32_t dst_offset, - std::vector const& call_data_mem) +void AvmTraceBuilder::calldata_copy( + uint8_t indirect, uint32_t cd_offset, uint32_t copy_size, uint32_t dst_offset, std::vector const& call_data_mem) { // We parallelize storing memory operations in chunk of 3, i.e., 1 per intermediate register. // The variable pos is an index pointing to the first storing operation (pertaining to intermediate @@ -455,6 +578,7 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, // cd_offset + pos + 2: Ic memory store operation uint32_t pos = 0; + uint32_t direct_dst_offset = dst_offset; // Will be overwritten in indirect mode. while (pos < copy_size) { FF ib(0); @@ -469,16 +593,28 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, FF ia = call_data_mem.at(cd_offset + pos); uint32_t mem_op_a(1); - uint32_t mem_idx_a = dst_offset + pos; uint32_t rwa = 1; + bool indirect_flag = false; + bool tag_match = true; + + if (pos == 0 && is_operand_indirect(indirect, 0)) { + indirect_flag = true; + auto ind_read = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, dst_offset); + direct_dst_offset = uint32_t(ind_read.val); + tag_match = ind_read.tag_match; + } + + uint32_t mem_idx_a = direct_dst_offset + pos; + // Storing from Ia mem_trace_builder.write_into_memory(clk, IntermRegister::IA, mem_idx_a, ia, AvmMemoryTag::FF); if (copy_size - pos > 1) { ib = call_data_mem.at(cd_offset + pos + 1); mem_op_b = 1; - mem_idx_b = dst_offset + pos + 1; + mem_idx_b = direct_dst_offset + pos + 1; rwb = 1; // Storing from Ib @@ -488,7 +624,7 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, if (copy_size - pos > 2) { ic = call_data_mem.at(cd_offset + pos + 2); mem_op_c = 1; - mem_idx_c = dst_offset + pos + 2; + mem_idx_c = direct_dst_offset + pos + 2; rwc = 1; // Storing from Ic @@ -500,6 +636,7 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, .avm_main_pc = FF(pc++), .avm_main_internal_return_ptr = FF(internal_return_ptr), .avm_main_in_tag = FF(static_cast(AvmMemoryTag::FF)), + .avm_main_tag_err = FF(static_cast(!tag_match)), .avm_main_ia = ia, .avm_main_ib = ib, .avm_main_ic = ic, @@ -509,6 +646,8 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, .avm_main_rwa = FF(rwa), .avm_main_rwb = FF(rwb), .avm_main_rwc = FF(rwc), + .avm_main_ind_a = indirect_flag ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(indirect_flag), .avm_main_mem_idx_a = FF(mem_idx_a), .avm_main_mem_idx_b = FF(mem_idx_b), .avm_main_mem_idx_c = FF(mem_idx_c), @@ -523,20 +662,21 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, } /** - * @brief RETURN opcode with direct memory access, i.e., - * return(M[ret_offset:ret_offset+ret_size]) + * @brief RETURN opcode with direct and indirect memory access, i.e., + * direct: return(M[ret_offset:ret_offset+ret_size]) + * indirect: return(M[M[ret_offset]:M[ret_offset]+ret_size]) * Simplified version with exclusively memory load operations into * intermediate registers and then values are copied to the returned vector. - * TODO: Implement the indirect memory version (maybe not required) * TODO: taking care of flagging this row as the last one? Special STOP flag? * TODO: error handling if ret_offset + ret_size > 2^32 which would lead to * out-of-bound memory read. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param ret_offset The starting index of the memory region to be returned. * @param ret_size The number of elements to be returned. * @return The returned memory region as a std::vector. */ -std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_size) +std::vector AvmTraceBuilder::return_op(uint8_t indirect, uint32_t ret_offset, uint32_t ret_size) { if (ret_size == 0) { halt(); @@ -549,9 +689,11 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz // ret_offset + pos: Ia memory load operation // ret_offset + pos + 1: Ib memory load operation // ret_offset + pos + 2: Ic memory load operation + // In indirect mode, ret_offset is first resolved by the first indirect load. uint32_t pos = 0; std::vector returnMem; + uint32_t direct_ret_offset = ret_offset; // Will be overwritten in indirect mode. while (pos < ret_size) { FF ib(0); @@ -563,18 +705,29 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz auto clk = static_cast(main_trace.size()); uint32_t mem_op_a(1); - uint32_t mem_idx_a = ret_offset + pos; + bool indirect_flag = false; + bool tag_match = true; + + if (pos == 0 && is_operand_indirect(indirect, 0)) { + indirect_flag = true; + auto ind_read = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, ret_offset); + direct_ret_offset = uint32_t(ind_read.val); + tag_match = ind_read.tag_match; + } + + uint32_t mem_idx_a = direct_ret_offset + pos; // Reading and loading to Ia auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, mem_idx_a, AvmMemoryTag::FF); - bool tag_match = read_a.tag_match; + tag_match = tag_match && read_a.tag_match; FF ia = read_a.val; returnMem.push_back(ia); if (ret_size - pos > 1) { mem_op_b = 1; - mem_idx_b = ret_offset + pos + 1; + mem_idx_b = direct_ret_offset + pos + 1; // Reading and loading to Ib auto read_b = @@ -586,7 +739,7 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz if (ret_size - pos > 2) { mem_op_c = 1; - mem_idx_c = ret_offset + pos + 2; + mem_idx_c = direct_ret_offset + pos + 2; // Reading and loading to Ic auto read_c = @@ -609,6 +762,8 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz .avm_main_mem_op_a = FF(mem_op_a), .avm_main_mem_op_b = FF(mem_op_b), .avm_main_mem_op_c = FF(mem_op_c), + .avm_main_ind_a = indirect_flag ? FF(ret_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(indirect_flag)), .avm_main_mem_idx_a = FF(mem_idx_a), .avm_main_mem_idx_b = FF(mem_idx_b), .avm_main_mem_idx_c = FF(mem_idx_c), diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index e0bdb4e9ed1f..8c62d03a470d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -28,23 +28,23 @@ class AvmTraceBuilder { uint32_t getPc() const { return pc; } - // Addition with direct memory access. - void op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Addition with direct or indirect memory access. + void op_add(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Subtraction with direct memory access. - void op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Subtraction with direct or indirect memory access. + void op_sub(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Multiplication with direct memory access. - void op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Multiplication with direct or indirect memory access. + void op_mul(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Division with direct memory access. - void op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Division with direct or indirect memory access. + void op_div(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Bitwise not with direct memory access. - void op_not(uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Bitwise not with direct or indirect memory access. + void op_not(uint8_t indirect, uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Equality with direct memory access. - void op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // 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); // Set a constant from bytecode with direct memory access. void set(uint128_t val, uint32_t dst_offset, AvmMemoryTag in_tag); @@ -65,24 +65,42 @@ class AvmTraceBuilder { // Halt -> stop program execution. void halt(); - // CALLDATACOPY opcode with direct memory access, i.e., - // M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] - void calldata_copy(uint32_t cd_offset, + // CALLDATACOPY opcode with direct/indirect memory access, i.e., + // direct: M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + // indirect: M[M[dst_offset]:M[dst_offset]+copy_size] = calldata[cd_offset:cd_offset+copy_size] + void calldata_copy(uint8_t indirect, + uint32_t cd_offset, uint32_t copy_size, uint32_t dst_offset, std::vector const& call_data_mem); - // RETURN opcode with direct memory access, i.e., - // return(M[ret_offset:ret_offset+ret_size]) - std::vector return_op(uint32_t ret_offset, uint32_t ret_size); + // RETURN opcode with direct and indirect memory access, i.e., + // direct: return(M[ret_offset:ret_offset+ret_size]) + // indirect: return(M[M[ret_offset]:M[ret_offset]+ret_size]) + std::vector return_op(uint8_t indirect, uint32_t ret_offset, uint32_t ret_size); private: + // Used for the standard indirect address resolution of three operands opcode. + struct IndirectThreeResolution { + bool tag_match = false; + uint32_t direct_a_offset; + uint32_t direct_b_offset; + uint32_t direct_dst_offset; + + bool indirect_flag_a = false; + bool indirect_flag_b = false; + bool indirect_flag_c = false; + }; + std::vector main_trace; AvmMemTraceBuilder mem_trace_builder; AvmAluTraceBuilder alu_trace_builder; void finalise_mem_trace_lookup_counts(); + IndirectThreeResolution resolve_ind_three( + uint32_t clk, uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset); + uint32_t pc = 0; uint32_t internal_return_ptr = CALLSTACK_OFFSET; std::stack internal_call_stack = {}; diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp index d71343f2c971..3e4992b8c9b3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp @@ -168,7 +168,7 @@ std::vector gen_mutated_trace_add(FF const& a, FF const& b, FF const& c_mut auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_add(0, 1, 2, tag); + trace_builder.op_add(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -186,7 +186,7 @@ std::vector gen_mutated_trace_sub(FF const& a, FF const& b, FF const& c_mut auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_sub(0, 1, 2, tag); + trace_builder.op_sub(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -204,7 +204,7 @@ std::vector gen_mutated_trace_mul(FF const& a, FF const& b, FF const& c_mut auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_mul(0, 1, 2, tag); + trace_builder.op_mul(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -225,7 +225,7 @@ std::vector gen_mutated_trace_eq( auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_eq(0, 1, 2, tag); + trace_builder.op_eq(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -298,11 +298,11 @@ class AvmArithmeticNegativeTestsU128 : public AvmArithmeticTests {}; // Test on basic addition over finite field type. TEST_F(AvmArithmeticTestsFF, addition) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] - trace_builder.op_add(0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] - trace_builder.return_op(0, 5); + trace_builder.op_add(0, 0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] + trace_builder.return_op(0, 0, 5); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(37), FF(4), FF(41), FF(0), FF(1), FF(4), AvmMemoryTag::FF); @@ -317,11 +317,11 @@ TEST_F(AvmArithmeticTestsFF, addition) // Test on basic subtraction over finite field type. TEST_F(AvmArithmeticTestsFF, subtraction) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] - trace_builder.op_sub(2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_sub(0, 2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(17), FF(8), FF(9), FF(2), FF(0), FF(1), AvmMemoryTag::FF); @@ -336,11 +336,11 @@ TEST_F(AvmArithmeticTestsFF, subtraction) // Test on basic multiplication over finite field type. TEST_F(AvmArithmeticTestsFF, multiplication) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] - trace_builder.op_mul(2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_mul(0, 2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(20), FF(5), FF(100), FF(2), FF(0), FF(1), AvmMemoryTag::FF); @@ -356,11 +356,11 @@ TEST_F(AvmArithmeticTestsFF, multiplication) // Test on multiplication by zero over finite field type. TEST_F(AvmArithmeticTestsFF, multiplicationByZero) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 127 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 127 }); // Memory layout: [127,0,0,0,0,0,....] - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::FF); // [127,0,0,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::FF); // [127,0,0,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(127), FF(0), FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::FF); @@ -376,11 +376,11 @@ TEST_F(AvmArithmeticTestsFF, multiplicationByZero) // Test on basic division over finite field type. TEST_F(AvmArithmeticTestsFF, division) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] - trace_builder.op_div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_div(0, 1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -399,11 +399,11 @@ TEST_F(AvmArithmeticTestsFF, division) // Test on division with zero numerator over finite field type. TEST_F(AvmArithmeticTestsFF, divisionNumeratorZero) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] - trace_builder.op_div(1, 0, 0, AvmMemoryTag::FF); // [0,0,0,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_div(0, 1, 0, 0, AvmMemoryTag::FF); // [0,0,0,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -423,10 +423,10 @@ TEST_F(AvmArithmeticTestsFF, divisionNumeratorZero) // We check that the operator error flag is raised. TEST_F(AvmArithmeticTestsFF, divisionByZeroError) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -449,7 +449,7 @@ TEST_F(AvmArithmeticTestsFF, divisionByZeroError) TEST_F(AvmArithmeticTestsFF, divisionZeroByZeroError) { // Memory layout: [0,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -473,19 +473,19 @@ TEST_F(AvmArithmeticTestsFF, divisionZeroByZeroError) // No check on the evaluation is performed here. TEST_F(AvmArithmeticTestsFF, mixedOperationsWithError) { - trace_builder.calldata_copy(0, 3, 2, std::vector{ 45, 23, 12 }); + trace_builder.calldata_copy(0, 0, 3, 2, std::vector{ 45, 23, 12 }); // Memory layout: [0,0,45,23,12,0,0,0,....] - trace_builder.op_add(2, 3, 4, AvmMemoryTag::FF); // [0,0,45,23,68,0,0,0,....] - trace_builder.op_add(4, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,68,0,0,....] - trace_builder.op_add(5, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,0,....] - trace_builder.op_add(5, 6, 7, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,0....] - trace_builder.op_sub(7, 6, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136,0....] - trace_builder.op_mul(8, 8, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136^2,0....] - trace_builder.op_div(3, 5, 1, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] - trace_builder.op_div(1, 1, 9, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] + trace_builder.op_add(0, 2, 3, 4, AvmMemoryTag::FF); // [0,0,45,23,68,0,0,0,....] + trace_builder.op_add(0, 4, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,68,0,0,....] + trace_builder.op_add(0, 5, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,0,....] + trace_builder.op_add(0, 5, 6, 7, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,0....] + trace_builder.op_sub(0, 7, 6, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136,0....] + trace_builder.op_mul(0, 8, 8, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136^2,0....] + trace_builder.op_div(0, 3, 5, 1, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] + trace_builder.op_div(0, 1, 1, 9, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] trace_builder.op_div( - 9, 0, 4, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 + 0, 9, 0, 4, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -497,9 +497,9 @@ TEST_F(AvmArithmeticTestsFF, equality) { // Pick a field-sized number FF elem = FF::modulus - FF(1); - trace_builder.calldata_copy(0, 3, 0, std::vector{ elem, elem, 1 }); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q -1, 1,0..] - trace_builder.return_op(0, 3); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ elem, elem, 1 }); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q -1, 1,0..] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, elem, elem, FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::FF); @@ -514,9 +514,9 @@ TEST_F(AvmArithmeticTestsFF, equality) TEST_F(AvmArithmeticTestsFF, nonEquality) { FF elem = FF::modulus - FF(1); - trace_builder.calldata_copy(0, 3, 0, std::vector{ elem, elem + FF(1), 0 }); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q, 1,0..] - trace_builder.return_op(0, 0); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ elem, elem + FF(1), 0 }); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q, 1,0..] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, elem, FF(0), FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::FF); @@ -539,8 +539,8 @@ TEST_F(AvmArithmeticTestsU8, addition) trace_builder.set(29, 1, AvmMemoryTag::U8); // Memory layout: [62,29,0,0,0,....] - trace_builder.op_add(0, 1, 2, AvmMemoryTag::U8); // [62,29,91,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 2, AvmMemoryTag::U8); // [62,29,91,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(62), FF(29), FF(91), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -560,8 +560,8 @@ TEST_F(AvmArithmeticTestsU8, additionCarry) trace_builder.set(100, 1, AvmMemoryTag::U8); // Memory layout: [159,100,0,0,0,....] - trace_builder.op_add(0, 1, 2, AvmMemoryTag::U8); // [159,100,3,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 2, AvmMemoryTag::U8); // [159,100,3,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(159), FF(100), FF(3), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -582,8 +582,8 @@ TEST_F(AvmArithmeticTestsU8, subtraction) trace_builder.set(29, 1, AvmMemoryTag::U8); // Memory layout: [162,29,0,0,0,....] - trace_builder.op_sub(0, 1, 2, AvmMemoryTag::U8); // [162,29,133,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 0, 1, 2, AvmMemoryTag::U8); // [162,29,133,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(162), FF(29), FF(133), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -604,8 +604,8 @@ TEST_F(AvmArithmeticTestsU8, subtractionCarry) trace_builder.set(29, 1, AvmMemoryTag::U8); // Memory layout: [5,29,0,0,0,....] - trace_builder.op_sub(0, 1, 2, AvmMemoryTag::U8); // [5,29,232,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 0, 1, 2, AvmMemoryTag::U8); // [5,29,232,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(5), FF(29), FF(232), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -632,8 +632,8 @@ TEST_F(AvmArithmeticTestsU8, multiplication) trace_builder.set(13, 0, AvmMemoryTag::U8); trace_builder.set(15, 1, AvmMemoryTag::U8); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U8); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U8); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(13), FF(15), FF(195), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -655,8 +655,8 @@ TEST_F(AvmArithmeticTestsU8, multiplicationOverflow) trace_builder.set(200, 0, AvmMemoryTag::U8); trace_builder.set(170, 1, AvmMemoryTag::U8); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U8); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U8); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(200), FF(170), FF(208), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -677,8 +677,8 @@ TEST_F(AvmArithmeticTestsU8, equality) { trace_builder.set(128, 0, AvmMemoryTag::U8); trace_builder.set(128, 1, AvmMemoryTag::U8); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U8); // Memory layout: [128,128,1,0,..,0] - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U8); // Memory layout: [128,128,1,0,..,0] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, FF(128), FF(128), FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -694,8 +694,8 @@ TEST_F(AvmArithmeticTestsU8, nonEquality) { trace_builder.set(84, 0, AvmMemoryTag::U8); trace_builder.set(200, 1, AvmMemoryTag::U8); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U8); // Memory layout: [84,200,0,0,..,0] - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U8); // Memory layout: [84,200,0,0,..,0] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, 84, 200, FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -717,8 +717,8 @@ TEST_F(AvmArithmeticTestsU16, addition) trace_builder.set(1775, 119, AvmMemoryTag::U16); trace_builder.set(33005, 546, AvmMemoryTag::U16); - trace_builder.op_add(546, 119, 5, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 546, 119, 5, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -739,8 +739,8 @@ TEST_F(AvmArithmeticTestsU16, additionCarry) trace_builder.set(UINT16_MAX - 982, 0, AvmMemoryTag::U16); trace_builder.set(1000, 1, AvmMemoryTag::U16); - trace_builder.op_add(1, 0, 0, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 1, 0, 0, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -761,8 +761,8 @@ TEST_F(AvmArithmeticTestsU16, subtraction) trace_builder.set(1775, 119, AvmMemoryTag::U16); trace_builder.set(33005, 546, AvmMemoryTag::U16); - trace_builder.op_sub(546, 119, 5, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 546, 119, 5, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -785,8 +785,8 @@ TEST_F(AvmArithmeticTestsU16, subtractionCarry) trace_builder.set(UINT16_MAX - 982, 0, AvmMemoryTag::U16); trace_builder.set(1000, 1, AvmMemoryTag::U16); - trace_builder.op_sub(1, 0, 0, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 1, 0, 0, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -814,8 +814,8 @@ TEST_F(AvmArithmeticTestsU16, multiplication) trace_builder.set(200, 0, AvmMemoryTag::U16); trace_builder.set(245, 1, AvmMemoryTag::U16); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -839,8 +839,8 @@ TEST_F(AvmArithmeticTestsU16, multiplicationOverflow) trace_builder.set(512, 0, AvmMemoryTag::U16); trace_builder.set(1024, 1, AvmMemoryTag::U16); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(512), FF(1024), FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::U16); @@ -863,8 +863,8 @@ TEST_F(AvmArithmeticTestsU16, equality) { trace_builder.set(35823, 0, AvmMemoryTag::U16); trace_builder.set(35823, 1, AvmMemoryTag::U16); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, FF(35823), FF(35823), FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::U16); @@ -880,8 +880,8 @@ TEST_F(AvmArithmeticTestsU16, nonEquality) { trace_builder.set(35'823, 0, AvmMemoryTag::U16); trace_builder.set(50'123, 1, AvmMemoryTag::U16); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, 35'823, 50'123, FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::U16); @@ -903,8 +903,8 @@ TEST_F(AvmArithmeticTestsU32, addition) trace_builder.set(1000000000, 8, AvmMemoryTag::U32); trace_builder.set(1234567891, 9, AvmMemoryTag::U32); - trace_builder.op_add(8, 9, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add( @@ -926,8 +926,8 @@ TEST_F(AvmArithmeticTestsU32, additionCarry) trace_builder.set(UINT32_MAX - 1293, 8, AvmMemoryTag::U32); trace_builder.set(2293, 9, AvmMemoryTag::U32); - trace_builder.op_add(8, 9, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -948,8 +948,8 @@ TEST_F(AvmArithmeticTestsU32, subtraction) trace_builder.set(1345678991, 8, AvmMemoryTag::U32); trace_builder.set(1234567891, 9, AvmMemoryTag::U32); - trace_builder.op_sub(8, 9, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub( @@ -975,8 +975,8 @@ TEST_F(AvmArithmeticTestsU32, subtractionCarry) trace_builder.set(UINT32_MAX - 99, 8, AvmMemoryTag::U32); trace_builder.set(3210987654, 9, AvmMemoryTag::U32); - trace_builder.op_sub(9, 8, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 9, 8, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub( @@ -1006,8 +1006,8 @@ TEST_F(AvmArithmeticTestsU32, multiplication) trace_builder.set(11111, 0, AvmMemoryTag::U32); trace_builder.set(11111, 1, AvmMemoryTag::U32); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1035,8 +1035,8 @@ TEST_F(AvmArithmeticTestsU32, multiplicationOverflow) trace_builder.set(11 << 25, 0, AvmMemoryTag::U32); trace_builder.set(13 << 22, 1, AvmMemoryTag::U32); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1062,8 +1062,8 @@ TEST_F(AvmArithmeticTestsU32, equality) { trace_builder.set(0xb435e9c1, 0, AvmMemoryTag::U32); trace_builder.set(0xb435e9c1, 1, AvmMemoryTag::U32); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1080,8 +1080,8 @@ TEST_F(AvmArithmeticTestsU32, nonEquality) { trace_builder.set(0xb435e9c1, 0, AvmMemoryTag::U32); trace_builder.set(0xb435e9c0, 1, AvmMemoryTag::U32); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1108,8 +1108,8 @@ TEST_F(AvmArithmeticTestsU64, addition) trace_builder.set(a, 8, AvmMemoryTag::U64); trace_builder.set(b, 9, AvmMemoryTag::U64); - trace_builder.op_add(8, 9, 9, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 9, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(a), FF(b), FF(c), FF(8), FF(9), FF(9), AvmMemoryTag::U64); @@ -1138,8 +1138,8 @@ TEST_F(AvmArithmeticTestsU64, additionCarry) trace_builder.set(a, 0, AvmMemoryTag::U64); trace_builder.set(b, 1, AvmMemoryTag::U64); - trace_builder.op_add(0, 1, 0, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 0, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(a), FF(b), FF(c), FF(0), FF(1), FF(0), AvmMemoryTag::U64); @@ -1166,8 +1166,8 @@ TEST_F(AvmArithmeticTestsU64, subtraction) trace_builder.set(a, 8, AvmMemoryTag::U64); trace_builder.set(b, 9, AvmMemoryTag::U64); - trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 9, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(a), FF(b), FF(c), FF(8), FF(9), FF(9), AvmMemoryTag::U64); @@ -1198,8 +1198,8 @@ TEST_F(AvmArithmeticTestsU64, subtractionCarry) trace_builder.set(a, 0, AvmMemoryTag::U64); trace_builder.set(b, 1, AvmMemoryTag::U64); - trace_builder.op_sub(0, 1, 0, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 0, 1, 0, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(a), FF(b), FF(c), FF(0), FF(1), FF(0), AvmMemoryTag::U64); @@ -1226,8 +1226,8 @@ TEST_F(AvmArithmeticTestsU64, multiplication) trace_builder.set(999888777, 0, AvmMemoryTag::U64); trace_builder.set(555444333, 1, AvmMemoryTag::U64); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul( @@ -1259,8 +1259,8 @@ TEST_F(AvmArithmeticTestsU64, multiplicationOverflow) trace_builder.set(a, 0, AvmMemoryTag::U64); trace_builder.set(b, 1, AvmMemoryTag::U64); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(a), FF(b), FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::U64); @@ -1287,8 +1287,8 @@ TEST_F(AvmArithmeticTestsU64, equality) { trace_builder.set(0xffffffffffffffe0LLU, 0, AvmMemoryTag::U64); trace_builder.set(0xffffffffffffffe0LLU, 1, AvmMemoryTag::U64); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq( @@ -1305,8 +1305,8 @@ TEST_F(AvmArithmeticTestsU64, nonEquality) { trace_builder.set(0xffffffffffffffe0LLU, 0, AvmMemoryTag::U64); trace_builder.set(0xffffffffffaeffe0LLU, 1, AvmMemoryTag::U64); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq( @@ -1333,8 +1333,8 @@ TEST_F(AvmArithmeticTestsU128, addition) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_add(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, @@ -1373,8 +1373,8 @@ TEST_F(AvmArithmeticTestsU128, additionCarry) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_add(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, @@ -1412,8 +1412,8 @@ TEST_F(AvmArithmeticTestsU128, subtraction) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, @@ -1454,8 +1454,8 @@ TEST_F(AvmArithmeticTestsU128, subtractionCarry) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, @@ -1492,8 +1492,8 @@ TEST_F(AvmArithmeticTestsU128, multiplication) // Integer multiplication output in HEX: 70289AEB0A7DDA0BAE60CA3A5 FF c{ uint256_t{ 0xA7DDA0BAE60CA3A5, 0x70289AEB0, 0, 0 } }; - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul( @@ -1529,8 +1529,8 @@ TEST_F(AvmArithmeticTestsU128, multiplicationOverflow) trace_builder.set(a, 0, AvmMemoryTag::U128); trace_builder.set(b, 1, AvmMemoryTag::U128); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, @@ -1582,8 +1582,8 @@ TEST_F(AvmArithmeticTestsU128, equality) uint128_t const elem = (uint128_t{ 0x5555222233334444LLU } << 64) + uint128_t{ 0x88889999AAAABBBBLLU }; trace_builder.set(elem, 0, AvmMemoryTag::U128); trace_builder.set(elem, 1, AvmMemoryTag::U128); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, @@ -1608,8 +1608,8 @@ TEST_F(AvmArithmeticTestsU128, nonEquality) uint128_t const b = a - (0xdeadbeefLLU << 32); trace_builder.set(a, 0, AvmMemoryTag::U128); trace_builder.set(b, 1, AvmMemoryTag::U128); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, @@ -1676,10 +1676,10 @@ TEST_F(AvmArithmeticNegativeTestsFF, multiplication) // Test on basic incorrect division over finite field type. TEST_F(AvmArithmeticNegativeTestsFF, divisionFF) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] - trace_builder.op_div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] + trace_builder.op_div(0, 1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1693,10 +1693,10 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionFF) // in the trace. TEST_F(AvmArithmeticNegativeTestsFF, divisionNoZeroButError) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] - trace_builder.op_div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] + trace_builder.op_div(0, 1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1719,10 +1719,10 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionNoZeroButError) // Test with division by zero occurs and no error is raised (remove error flag) TEST_F(AvmArithmeticNegativeTestsFF, divisionByZeroNoError) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1739,7 +1739,7 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionByZeroNoError) TEST_F(AvmArithmeticNegativeTestsFF, divisionZeroByZeroNoError) { // Memory layout: [0,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1756,11 +1756,11 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionZeroByZeroNoError) // the addition, subtraction, multiplication. TEST_F(AvmArithmeticNegativeTestsFF, operationWithErrorFlag) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] - trace_builder.op_add(0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] - trace_builder.return_op(0, 5); + trace_builder.op_add(0, 0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] + trace_builder.return_op(0, 0, 5); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1774,11 +1774,11 @@ TEST_F(AvmArithmeticNegativeTestsFF, operationWithErrorFlag) trace_builder.reset(); - trace_builder.calldata_copy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] - trace_builder.op_sub(2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_sub(0, 2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] + trace_builder.return_op(0, 0, 3); trace = trace_builder.finalize(); // Find the first row enabling the subtraction selector @@ -1791,11 +1791,11 @@ TEST_F(AvmArithmeticNegativeTestsFF, operationWithErrorFlag) trace_builder.reset(); - trace_builder.calldata_copy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] - trace_builder.op_mul(2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_mul(0, 2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] + trace_builder.return_op(0, 0, 3); trace = trace_builder.finalize(); // Find the first row enabling the multiplication selector diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp index 7fae3fa13cbb..0fb368cb1e5d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp @@ -59,7 +59,7 @@ std::vector gen_mutated_trace_not(FF const& a, FF const& c_mutated, avm_tra { auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); - trace_builder.op_not(0, 1, tag); + trace_builder.op_not(0, 0, 1, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -106,9 +106,9 @@ class AvmBitwiseNegativeTestsU128 : public AvmBitwiseTests {}; TEST_F(AvmBitwiseTestsU8, BitwiseNot) { - trace_builder.set(1, 0, AvmMemoryTag::U8); // Memory Layout: [1,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U8); // [1,254,0,0,....] - trace_builder.return_op(0, 0); + 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,....] + 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); @@ -119,9 +119,9 @@ TEST_F(AvmBitwiseTestsU8, BitwiseNot) TEST_F(AvmBitwiseTestsU16, BitwiseNot) { - trace_builder.set(512, 0, AvmMemoryTag::U16); // Memory Layout: [512,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U16); // [512,65023,0,0,0,....] - trace_builder.return_op(0, 0); + 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); @@ -133,8 +133,8 @@ TEST_F(AvmBitwiseTestsU16, BitwiseNot) TEST_F(AvmBitwiseTestsU32, BitwiseNot) { trace_builder.set(131'072, 0, AvmMemoryTag::U32); // Memory Layout: [131072,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U32); // [131072,4294836223,,0,0,....] - trace_builder.return_op(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); @@ -146,8 +146,8 @@ TEST_F(AvmBitwiseTestsU32, BitwiseNot) TEST_F(AvmBitwiseTestsU64, BitwiseNot) { trace_builder.set(0x100000000LLU, 0, AvmMemoryTag::U64); // Memory Layout: [8589934592,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U64); // [8589934592,18446744069414584319,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U64); // [8589934592,18446744069414584319,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -162,8 +162,8 @@ TEST_F(AvmBitwiseTestsU128, BitwiseNot) uint128_t const a = uint128_t{ 0x4000000000000 } << 64; trace_builder.set(a, 0, AvmMemoryTag::U128); - trace_builder.op_not(0, 1, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); uint128_t const res = (uint128_t{ 0xfffbffffffffffff } << 64) + uint128_t{ 0xffffffffffffffff }; @@ -192,10 +192,10 @@ TEST_F(AvmBitwiseNegativeTestsFF, UndefinedOverFF) // Triggers a write row 1 of mem_trace and alu_trace trace_builder.set(10, 0, AvmMemoryTag::U8); // Triggers a write in row 2 of alu_trace - trace_builder.op_not(0, 1, AvmMemoryTag::U8); + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U8); // Finally, we will have a write in row 3 of the mem_trace to copy the result // from the op_not operation. - trace_builder.return_op(0, 0); + trace_builder.return_op(0, 0, 0); // Manually update the memory tags in the relevant trace; auto trace = trace_builder.finalize(); // TODO(ilyas): When the SET opcodes applies relational constraints, this will fail diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_indirect_mem.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_indirect_mem.test.cpp new file mode 100644 index 000000000000..e15356d5ae71 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_indirect_mem.test.cpp @@ -0,0 +1,161 @@ +#include "avm_common.test.hpp" +#include "barretenberg/vm/avm_trace/avm_common.hpp" + +namespace tests_avm { +using namespace bb::avm_trace; + +class AvmIndirectMemTests : public ::testing::Test { + public: + AvmTraceBuilder trace_builder; + + protected: + // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. + void SetUp() override { srs::init_crs_factory("../srs_db/ignition"); }; +}; + +/****************************************************************************** + * + * INDIRECT MEMORY - POSITIVE TESTS + * + ******************************************************************************/ + +// Testing an addition operation with all indirect operands. +// Indirect addresses are located at indices 0,1,2 +// Direct addresses are located at indices 10,11,12 +// Input values are respectively: a=100, b=101 +TEST_F(AvmIndirectMemTests, allIndirectAdd) +{ + // Set direct addresses + trace_builder.set(10, 0, AvmMemoryTag::U32); + trace_builder.set(11, 1, AvmMemoryTag::U32); + trace_builder.set(12, 2, AvmMemoryTag::U32); + + // Set input values + trace_builder.set(100, 10, AvmMemoryTag::U16); + trace_builder.set(101, 11, AvmMemoryTag::U16); + + // All indirect flags are encoded as 7 = 1 + 2 + 4 + trace_builder.op_add(7, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the addition selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_add == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + // Check all addresses and values + EXPECT_EQ(row->avm_main_ia, FF(100)); + EXPECT_EQ(row->avm_main_ib, FF(101)); + EXPECT_EQ(row->avm_main_ic, FF(201)); + EXPECT_EQ(row->avm_main_ind_a, FF(0)); + EXPECT_EQ(row->avm_main_ind_b, FF(1)); + EXPECT_EQ(row->avm_main_ind_c, FF(2)); + EXPECT_EQ(row->avm_main_mem_idx_a, FF(10)); + EXPECT_EQ(row->avm_main_mem_idx_b, FF(11)); + EXPECT_EQ(row->avm_main_mem_idx_c, FF(12)); + + // Check memory operation tags + EXPECT_EQ(row->avm_main_ind_op_a, FF(1)); + EXPECT_EQ(row->avm_main_ind_op_b, FF(1)); + EXPECT_EQ(row->avm_main_ind_op_c, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_a, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + + validate_trace_proof(std::move(trace)); +} + +// Testing a subtraction operation with direct input operands a, b, and an indirect +// output operand c. +// Indirect address is located at index 5 +// Direct addresses are located at indices 50,51,52 +// Input values are respectively: a=600, b=500 +TEST_F(AvmIndirectMemTests, indirectOutputSub) +{ + // Set direct output address + trace_builder.set(52, 5, AvmMemoryTag::U32); + + // Set input values + trace_builder.set(600, 50, AvmMemoryTag::U128); + trace_builder.set(500, 51, AvmMemoryTag::U128); + + // The indirect flag is encoded as 4 + trace_builder.op_sub(4, 50, 51, 5, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the subtraction selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_sub == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + // Check all addresses and values + EXPECT_EQ(row->avm_main_ia, FF(600)); + EXPECT_EQ(row->avm_main_ib, FF(500)); + EXPECT_EQ(row->avm_main_ic, FF(100)); + EXPECT_EQ(row->avm_main_ind_a, FF(0)); + EXPECT_EQ(row->avm_main_ind_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_c, FF(5)); + EXPECT_EQ(row->avm_main_mem_idx_a, FF(50)); + EXPECT_EQ(row->avm_main_mem_idx_b, FF(51)); + EXPECT_EQ(row->avm_main_mem_idx_c, FF(52)); + + // Check memory operation tags + EXPECT_EQ(row->avm_main_ind_op_a, FF(0)); + EXPECT_EQ(row->avm_main_ind_op_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_op_c, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_a, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + + validate_trace_proof(std::move(trace)); +} + +// Testing a multiplication operation with indirect input operand a, +// and indirect input operand b and output operand c. +// Indirect address is located at index 1000 +// Direct addresses are located at indices 100,101,102 +// Input values are respectively: a=4, b=7 +TEST_F(AvmIndirectMemTests, indirectInputAMul) +{ + // Set direct input address for a + trace_builder.set(100, 1000, AvmMemoryTag::U32); + + // Set input values + trace_builder.set(4, 100, AvmMemoryTag::U64); + trace_builder.set(7, 101, AvmMemoryTag::U64); + + // The indirect flag is encoded as 1 + trace_builder.op_mul(1, 1000, 101, 102, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the multiplication selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_mul == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + // Check all addresses and values + EXPECT_EQ(row->avm_main_ia, FF(4)); + EXPECT_EQ(row->avm_main_ib, FF(7)); + EXPECT_EQ(row->avm_main_ic, FF(28)); + EXPECT_EQ(row->avm_main_ind_a, FF(1000)); + EXPECT_EQ(row->avm_main_ind_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_c, FF(0)); + EXPECT_EQ(row->avm_main_mem_idx_a, FF(100)); + EXPECT_EQ(row->avm_main_mem_idx_b, FF(101)); + EXPECT_EQ(row->avm_main_mem_idx_c, FF(102)); + + // Check memory operation tags + EXPECT_EQ(row->avm_main_ind_op_a, FF(1)); + EXPECT_EQ(row->avm_main_ind_op_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_op_c, FF(0)); + EXPECT_EQ(row->avm_main_mem_op_a, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + + validate_trace_proof(std::move(trace)); +} + +} // namespace tests_avm diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp index 9940e88eca00..ea1199a1b2cc 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp @@ -39,7 +39,7 @@ TEST_F(AvmInterTableTests, tagErrNotCopiedInMain) // Equality operation on U128 and second operand is of type U16. trace_builder.set(32, 18, AvmMemoryTag::U128); trace_builder.set(32, 76, AvmMemoryTag::U16); - trace_builder.op_eq(18, 76, 65, AvmMemoryTag::U128); + trace_builder.op_eq(0, 18, 76, 65, AvmMemoryTag::U128); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -89,10 +89,10 @@ class AvmPermMainAluNegativeTests : public AvmInterTableTests { trace_builder.set(19, 0, AvmMemoryTag::U64); trace_builder.set(15, 1, AvmMemoryTag::U64); - trace_builder.op_add(0, 1, 1, AvmMemoryTag::U64); // 19 + 15 = 34 - trace_builder.op_add(0, 1, 1, AvmMemoryTag::U64); // 19 + 34 = 53 - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64); // 19 * 53 = 1007 - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 1, AvmMemoryTag::U64); // 19 + 15 = 34 + trace_builder.op_add(0, 0, 1, 1, AvmMemoryTag::U64); // 19 + 34 = 53 + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U64); // 19 * 53 = 1007 + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); @@ -190,8 +190,8 @@ class AvmPermMainMemNegativeTests : public AvmInterTableTests { { trace_builder.set(a, 52, AvmMemoryTag::U8); trace_builder.set(b, 11, AvmMemoryTag::U8); - trace_builder.op_sub(52, 11, 55, AvmMemoryTag::U8); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 52, 11, 55, AvmMemoryTag::U8); + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp index 63dd61810ac6..861403b4b099 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp @@ -42,7 +42,7 @@ class AvmMemOpcodeTests : public ::testing::Test { } trace_builder.op_mov(indirect ? 3 : 0, src_offset, dst_offset); - trace_builder.return_op(0, 0); + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); } @@ -182,7 +182,7 @@ TEST_F(AvmMemOpcodeTests, indirectMovInvalidAddressTag) trace_builder.set(16, 101, AvmMemoryTag::U128); // This will make the indirect load failing. trace_builder.set(5, 15, AvmMemoryTag::FF); trace_builder.op_mov(3, 100, 101); - trace_builder.return_op(0, 0); + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); computeIndices(true); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp index ac73aa1e55de..3fdea73260e7 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp @@ -30,9 +30,9 @@ class AvmMemoryTests : public ::testing::Test { // The proof must pass and we check that the AVM error is raised. TEST_F(AvmMemoryTests, mismatchedTagAddOperation) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 98, 12 }); - trace_builder.op_add(0, 1, 4, AvmMemoryTag::U8); + trace_builder.op_add(0, 0, 1, 4, AvmMemoryTag::U8); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -79,7 +79,7 @@ TEST_F(AvmMemoryTests, mismatchedTagEqOperation) trace_builder.set(3, 0, AvmMemoryTag::U32); trace_builder.set(5, 1, AvmMemoryTag::U16); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U32); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U32); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -123,7 +123,7 @@ TEST_F(AvmMemoryTests, mLastAccessViolation) trace_builder.set(9, 1, AvmMemoryTag::U8); // Memory layout: [4,9,0,0,0,0,....] - trace_builder.op_sub(1, 0, 2, AvmMemoryTag::U8); // [4,9,5,0,0,0.....] + trace_builder.op_sub(0, 1, 0, 2, AvmMemoryTag::U8); // [4,9,5,0,0,0.....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -154,8 +154,8 @@ TEST_F(AvmMemoryTests, readWriteConsistencyValViolation) trace_builder.set(9, 1, AvmMemoryTag::U8); // Memory layout: [4,9,0,0,0,0,....] - trace_builder.op_mul(1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] - trace_builder.return_op(2, 1); // Return single memory word at position 2 (36) + trace_builder.op_mul(0, 1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] + trace_builder.return_op(0, 2, 1); // Return single memory word at position 2 (36) auto trace = trace_builder.finalize(); // Find the row with multiplication operation @@ -184,8 +184,8 @@ TEST_F(AvmMemoryTests, readWriteConsistencyTagViolation) trace_builder.set(9, 1, AvmMemoryTag::U8); // Memory layout: [4,9,0,0,0,0,....] - trace_builder.op_mul(1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] - trace_builder.return_op(2, 1); // Return single memory word at position 2 (36) + trace_builder.op_mul(0, 1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] + trace_builder.return_op(0, 2, 1); // Return single memory word at position 2 (36) auto trace = trace_builder.finalize(); // Find the row with multiplication operation @@ -210,7 +210,7 @@ TEST_F(AvmMemoryTests, readWriteConsistencyTagViolation) // Testing violation that a memory read at uninitialized location must have value 0. TEST_F(AvmMemoryTests, readUninitializedMemoryViolation) { - trace_builder.return_op(1, 1); // Return single memory word at position 1 + trace_builder.return_op(0, 1, 1); // Return single memory word at position 1 auto trace = trace_builder.finalize(); trace[1].avm_mem_m_val = 9; @@ -222,9 +222,9 @@ TEST_F(AvmMemoryTests, readUninitializedMemoryViolation) // must raise a VM error. TEST_F(AvmMemoryTests, mismatchedTagErrorViolation) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 98, 12 }); - trace_builder.op_sub(0, 1, 4, AvmMemoryTag::U8); + trace_builder.op_sub(0, 0, 1, 4, AvmMemoryTag::U8); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -256,9 +256,9 @@ TEST_F(AvmMemoryTests, mismatchedTagErrorViolation) // must not set a VM error. TEST_F(AvmMemoryTests, consistentTagNoErrorViolation) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 84, 7 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 84, 7 }); - trace_builder.op_div(0, 1, 4, AvmMemoryTag::FF); + trace_builder.op_div(0, 0, 1, 4, AvmMemoryTag::FF); trace_builder.halt(); auto trace = trace_builder.finalize();