Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion barretenberg/cpp/pil/avm/main.pil
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace main(256);

pol commit sel_execution_end; // Toggle next row of last execution trace row.
// Used as a LHS selector of the lookup to enforce final gas values which correspond to
// l2_gas_remaining and da_gas_remaining values located at the row after last execution row.
// l2_gas_remaining and da_gas_remaining values located at the row after last execution row.
sel_execution_end' = sel_execution_row * (1 - sel_execution_row') * (1 - sel_first);

//===== PUBLIC COLUMNS=========================================================
Expand Down
2 changes: 2 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm/tests/cast.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ TEST_F(AvmCastTests, indirectAddrTruncationU64ToU8)

TEST_F(AvmCastTests, indirectAddrWrongResolutionU64ToU8)
{
// TODO(#9131): Re-enable as part of #9131
GTEST_SKIP();
// Indirect addresses. src:5 dst:6
// Direct addresses. src:10 dst:11
trace_builder.op_set(0, 10, 5, AvmMemoryTag::U8); // Not an address type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1723,7 +1723,7 @@ TEST_F(AvmExecutionTests, daGasLeft)
"0007" // addr a 7
"0009" // addr b 9
"0001" // addr c 1
+ to_hex(OpCode::GETENVVAR_16) + // opcode L2GASLEFT
+ to_hex(OpCode::GETENVVAR_16) + // opcode DAGASLEFT
"00" // Indirect flag
+ to_hex(static_cast<uint8_t>(EnvironmentVariable::DAGASLEFT)) +
"0027" // dst_offset (indirect addr: 17)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,19 @@ TEST_F(AvmIndirectMemTests, allIndirectAdd)
EXPECT_EQ(row->main_ib, FF(101));
EXPECT_EQ(row->main_ic, FF(201));
EXPECT_EQ(row->main_ind_addr_a, FF(0));
EXPECT_EQ(row->main_ind_addr_b, FF(1));
EXPECT_EQ(row->main_ind_addr_c, FF(2));

// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_EQ(row->main_ind_addr_b, FF(1));
// EXPECT_EQ(row->main_ind_addr_c, FF(2));
EXPECT_EQ(row->main_mem_addr_a, FF(10));
EXPECT_EQ(row->main_mem_addr_b, FF(11));
EXPECT_EQ(row->main_mem_addr_c, FF(12));

// Check memory operation tags
EXPECT_EQ(row->main_sel_resolve_ind_addr_a, FF(1));
EXPECT_EQ(row->main_sel_resolve_ind_addr_b, FF(1));
EXPECT_EQ(row->main_sel_resolve_ind_addr_c, FF(1));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_EQ(row->main_sel_resolve_ind_addr_a, FF(1));
// EXPECT_EQ(row->main_sel_resolve_ind_addr_b, FF(1));
// EXPECT_EQ(row->main_sel_resolve_ind_addr_c, FF(1));
EXPECT_EQ(row->main_sel_mem_op_a, FF(1));
EXPECT_EQ(row->main_sel_mem_op_b, FF(1));
EXPECT_EQ(row->main_sel_mem_op_c, FF(1));
Expand Down Expand Up @@ -102,15 +105,17 @@ TEST_F(AvmIndirectMemTests, indirectOutputSub)
EXPECT_EQ(row->main_ic, FF(100));
EXPECT_EQ(row->main_ind_addr_a, FF(0));
EXPECT_EQ(row->main_ind_addr_b, FF(0));
EXPECT_EQ(row->main_ind_addr_c, FF(5));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_EQ(row->main_ind_addr_c, FF(5));
EXPECT_EQ(row->main_mem_addr_a, FF(50));
EXPECT_EQ(row->main_mem_addr_b, FF(51));
EXPECT_EQ(row->main_mem_addr_c, FF(52));

// Check memory operation tags
EXPECT_EQ(row->main_sel_resolve_ind_addr_a, FF(0));
EXPECT_EQ(row->main_sel_resolve_ind_addr_b, FF(0));
EXPECT_EQ(row->main_sel_resolve_ind_addr_c, FF(1));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_EQ(row->main_sel_resolve_ind_addr_c, FF(1));
EXPECT_EQ(row->main_sel_mem_op_a, FF(1));
EXPECT_EQ(row->main_sel_mem_op_b, FF(1));
EXPECT_EQ(row->main_sel_mem_op_c, FF(1));
Expand Down Expand Up @@ -146,15 +151,17 @@ TEST_F(AvmIndirectMemTests, indirectInputAMul)
EXPECT_EQ(row->main_ia, FF(4));
EXPECT_EQ(row->main_ib, FF(7));
EXPECT_EQ(row->main_ic, FF(28));
EXPECT_EQ(row->main_ind_addr_a, FF(1000));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_EQ(row->main_ind_addr_a, FF(1000));
EXPECT_EQ(row->main_ind_addr_b, FF(0));
EXPECT_EQ(row->main_ind_addr_c, FF(0));
EXPECT_EQ(row->main_mem_addr_a, FF(100));
EXPECT_EQ(row->main_mem_addr_b, FF(101));
EXPECT_EQ(row->main_mem_addr_c, FF(102));

// Check memory operation tags
EXPECT_EQ(row->main_sel_resolve_ind_addr_a, FF(1));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_EQ(row->main_sel_resolve_ind_addr_a, FF(1));
EXPECT_EQ(row->main_sel_resolve_ind_addr_b, FF(0));
EXPECT_EQ(row->main_sel_resolve_ind_addr_c, FF(0));
EXPECT_EQ(row->main_sel_mem_op_a, FF(1));
Expand Down
11 changes: 6 additions & 5 deletions barretenberg/cpp/src/barretenberg/vm/avm/tests/kernel.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ void test_kernel_lookup(bool indirect,
/*
* Helper function to assert row values for a kernel lookup opcode
*/
void expect_row(auto row, FF selector, FF ia, FF ind_a, FF mem_addr_a, AvmMemoryTag w_in_tag)
void expect_row(auto row, FF selector, FF ia, [[maybe_unused]] FF ind_a, FF mem_addr_a, AvmMemoryTag w_in_tag)
{
// Checks dependent on the opcode
EXPECT_EQ(row->main_kernel_in_offset, selector);
Expand All @@ -96,8 +96,9 @@ void expect_row(auto row, FF selector, FF ia, FF ind_a, FF mem_addr_a, AvmMemory

// Checks that are fixed for kernel inputs
EXPECT_EQ(row->main_rwa, FF(1));
EXPECT_EQ(row->main_ind_addr_a, ind_a);
EXPECT_EQ(row->main_sel_resolve_ind_addr_a, FF(ind_a != 0));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_EQ(row->main_ind_addr_a, ind_a);
// EXPECT_EQ(row->main_sel_resolve_ind_addr_a, FF(ind_a != 0));
EXPECT_EQ(row->main_sel_mem_op_a, FF(1));
EXPECT_EQ(row->main_w_in_tag, static_cast<uint32_t>(w_in_tag));
EXPECT_EQ(row->main_sel_q_kernel_lookup, FF(1));
Expand Down Expand Up @@ -1249,7 +1250,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNullifierExists)

auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) {
trace_builder.op_set(0, value, value_offset, AvmMemoryTag::FF);
trace_builder.op_nullifier_exists(/*indirect=*/0, value_offset, metadata_offset);
trace_builder.op_nullifier_exists(/*indirect=*/0, value_offset, /*address_offset*/ 0, metadata_offset);
};
auto checks = [=](bool indirect, const std::vector<Row>& trace) {
auto row = std::ranges::find_if(
Expand Down Expand Up @@ -1288,7 +1289,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNullifierNonExists)

auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) {
trace_builder.op_set(0, value, value_offset, AvmMemoryTag::FF);
trace_builder.op_nullifier_exists(/*indirect=*/0, value_offset, metadata_offset);
trace_builder.op_nullifier_exists(/*indirect=*/0, value_offset, /*address_offset*/ 0, metadata_offset);
};
auto checks = [=](bool indirect, const std::vector<Row>& trace) {
auto row = std::ranges::find_if(
Expand Down
40 changes: 28 additions & 12 deletions barretenberg/cpp/src/barretenberg/vm/avm/tests/mem_opcodes.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "barretenberg/vm/avm/trace/common.hpp"
#include "barretenberg/vm/avm/trace/mem_trace.hpp"
#include "common.test.hpp"
#include "gtest/gtest.h"
#include <cstddef>
#include <cstdint>
#include <gmock/gmock.h>
Expand Down Expand Up @@ -225,6 +226,9 @@ TEST_F(AvmMemOpcodeTests, uninitializedValueMov)

TEST_F(AvmMemOpcodeTests, indUninitializedValueMov)
{
// TODO(#9131): Re-enable once we have error handling on wrong address resolution
GTEST_SKIP();

trace_builder.op_set(0, 1, 3, AvmMemoryTag::U32);
trace_builder.op_set(0, 4, 1, AvmMemoryTag::U32);
trace_builder.op_mov(3, 2, 3);
Expand All @@ -236,12 +240,18 @@ TEST_F(AvmMemOpcodeTests, indUninitializedValueMov)

TEST_F(AvmMemOpcodeTests, indirectMov)
{
// Re-enable once we constrain address resolution
GTEST_SKIP();

build_mov_trace(true, 23, 0, 1, AvmMemoryTag::U8, 2, 3);
validate_mov_trace(true, 23, 0, 1, AvmMemoryTag::U8, 2, 3);
}

TEST_F(AvmMemOpcodeTests, indirectMovInvalidAddressTag)
{
// TODO(#9131): Re-enable once we have error handling on wrong address resolution
GTEST_SKIP();

trace_builder.op_set(0, 15, 100, AvmMemoryTag::U32);
trace_builder.op_set(0, 16, 101, AvmMemoryTag::U128); // This will make the indirect load failing.
trace_builder.op_set(0, 5, 15, AvmMemoryTag::FF);
Expand Down Expand Up @@ -299,17 +309,19 @@ TEST_F(AvmMemOpcodeTests, indirectSet)
trace_builder.op_return(0, 0, 0);
trace = trace_builder.finalize();

compute_index_c(2, true);
// TODO(JEANMON): Turn following boolean to true once we have constraining address resolution
compute_index_c(2, false);
auto const& row = trace.at(2);

EXPECT_THAT(row,
AllOf(MAIN_ROW_FIELD_EQ(tag_err, 0),
MAIN_ROW_FIELD_EQ(ic, 1979),
MAIN_ROW_FIELD_EQ(mem_addr_c, 100),
MAIN_ROW_FIELD_EQ(sel_mem_op_c, 1),
MAIN_ROW_FIELD_EQ(rwc, 1),
MAIN_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
MAIN_ROW_FIELD_EQ(ind_addr_c, 10)));
MAIN_ROW_FIELD_EQ(rwc, 1)));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// MAIN_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
// MAIN_ROW_FIELD_EQ(ind_addr_c, 10)));

EXPECT_THAT(trace.at(mem_c_row_idx),
AllOf(MEM_ROW_FIELD_EQ(val, 1979),
Expand All @@ -320,20 +332,24 @@ TEST_F(AvmMemOpcodeTests, indirectSet)
MEM_ROW_FIELD_EQ(w_in_tag, static_cast<uint32_t>(AvmMemoryTag::U64)),
MEM_ROW_FIELD_EQ(tag, static_cast<uint32_t>(AvmMemoryTag::U64))));

EXPECT_THAT(trace.at(mem_ind_c_row_idx),
AllOf(MEM_ROW_FIELD_EQ(val, 100),
MEM_ROW_FIELD_EQ(addr, 10),
MEM_ROW_FIELD_EQ(sel_op_c, 0),
MEM_ROW_FIELD_EQ(rw, 0),
MEM_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
MEM_ROW_FIELD_EQ(r_in_tag, static_cast<uint32_t>(AvmMemoryTag::U32)),
MEM_ROW_FIELD_EQ(tag, static_cast<uint32_t>(AvmMemoryTag::U32))));
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// EXPECT_THAT(trace.at(mem_ind_c_row_idx),
// AllOf(MEM_ROW_FIELD_EQ(val, 100),
// MEM_ROW_FIELD_EQ(addr, 10),
// MEM_ROW_FIELD_EQ(sel_op_c, 0),
// MEM_ROW_FIELD_EQ(rw, 0),
// MEM_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
// MEM_ROW_FIELD_EQ(r_in_tag, static_cast<uint32_t>(AvmMemoryTag::U32)),
// MEM_ROW_FIELD_EQ(tag, static_cast<uint32_t>(AvmMemoryTag::U32))));

validate_trace(std::move(trace), public_inputs);
}

TEST_F(AvmMemOpcodeTests, indirectSetWrongTag)
{
// TODO(#9131): Re-enable once we have error handling on wrong address resolution
GTEST_SKIP();

trace_builder.op_set(0, 100, 10, AvmMemoryTag::U8); // The address 100 has incorrect tag U8.
trace_builder.op_set(1, 1979, 10, AvmMemoryTag::U64); // Set 1979 at memory index 100
trace_builder.op_return(0, 0, 0);
Expand Down
52 changes: 52 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm/tests/memory.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,56 @@ TEST_F(AvmMemoryTests, noErrorTagWriteViolation)
EXPECT_THROW_WITH_MESSAGE(validate_trace_check_circuit(std::move(trace)), "NO_TAG_ERR_WRITE");
}

// Basic test on direct relative memory addressing
TEST_F(AvmMemoryTests, directRelativeMemory)
{
trace_builder.op_set(0, 42, 0, AvmMemoryTag::U32); // Relative base offset = 42

trace_builder.op_set(0, 3, 52, AvmMemoryTag::U16); // Value 3 at offset 52, relative offset 10
trace_builder.op_set(0, 5, 142, AvmMemoryTag::U16); // Value 5 at offset 142, relative offset 100

// Addition with direct relative addressing on the 2 input operands and direct addressing on the output
// indirect byte: 00011000 = 24
trace_builder.op_add(24, 10, 100, 10, AvmMemoryTag::U16);
trace_builder.op_return(0, 0, 0);
auto trace = trace_builder.finalize();

// Find the first row enabling the add selector
auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_add == FF(1); });

ASSERT_TRUE(row != trace.end());

// Result of addition 3 + 5 = 8 at memory position 10
EXPECT_EQ(row->main_ic, 8);
EXPECT_EQ(row->main_mem_addr_c, 10);
}

// Basic test on indirect relative memory addressing
TEST_F(AvmMemoryTests, indirectRelativeMemory)
{
trace_builder.op_set(0, 100, 0, AvmMemoryTag::U32); // Relative base offset = 100

// Operands a and b are saved at memory offsets 10 and 11 respectively.
// Unresolved/indirect addresses for a and b are 123 and 147, i.e., M[123]=10 and M[147]=11
// Indirect relative addresses for a and b are thus 23 and 47 respectively.

trace_builder.op_set(0, 10, 123, AvmMemoryTag::U32); // Direct address of a set at indirect offset
trace_builder.op_set(0, 11, 147, AvmMemoryTag::U32); // Direct address of b set at indirect offset

trace_builder.op_set(0, 3, 10, AvmMemoryTag::U8); // a resolved memory offset
trace_builder.op_set(0, 5, 11, AvmMemoryTag::U8); // b resolved memory offset

// Output c = a + b = 8 is stored at direct relative offset 2, i.e., address 102.
// indirect byte: 00111011 = 1 + 2 + 8 + 16 + 32 = 59
trace_builder.op_add(59, 23, 47, 2, AvmMemoryTag::U8);
trace_builder.op_return(0, 0, 0);
auto trace = trace_builder.finalize();

// Find the first row enabling the add selector
auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_add == FF(1); });

EXPECT_EQ(row->main_ic, 8);
EXPECT_EQ(row->main_mem_addr_c, 102);
}

} // namespace tests_avm
13 changes: 9 additions & 4 deletions barretenberg/cpp/src/barretenberg/vm/avm/tests/slice.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,15 +223,17 @@ TEST_F(AvmSliceTests, indirectTwoCallsOverlap)
EXPECT_THAT(main_rows.at(0),
AllOf(MAIN_ROW_FIELD_EQ(ia, 1),
MAIN_ROW_FIELD_EQ(ib, 3),
MAIN_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
MAIN_ROW_FIELD_EQ(ind_addr_c, 100),
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// MAIN_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
// MAIN_ROW_FIELD_EQ(ind_addr_c, 100),
MAIN_ROW_FIELD_EQ(mem_addr_c, 34),
MAIN_ROW_FIELD_EQ(clk, 6)));
EXPECT_THAT(main_rows.at(1),
AllOf(MAIN_ROW_FIELD_EQ(ia, 2),
MAIN_ROW_FIELD_EQ(ib, 3),
MAIN_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
MAIN_ROW_FIELD_EQ(ind_addr_c, 101),
// TODO(JEANMON): Uncomment once we have a constraining address resolution
// MAIN_ROW_FIELD_EQ(sel_resolve_ind_addr_c, 1),
// MAIN_ROW_FIELD_EQ(ind_addr_c, 101),
MAIN_ROW_FIELD_EQ(mem_addr_c, 2123),
MAIN_ROW_FIELD_EQ(clk, 7)));

Expand All @@ -240,6 +242,9 @@ TEST_F(AvmSliceTests, indirectTwoCallsOverlap)

TEST_F(AvmSliceTests, indirectFailedResolution)
{
// TODO(#9131): Re-enable as part of #9131
GTEST_SKIP();

gen_trace_builder({ 2, 3, 4, 5, 6 });
trace_builder.op_set(0, 34, 100, AvmMemoryTag::U16); // indirect address 100 resolves to 34
trace_builder.op_set(0, 1, 1, AvmMemoryTag::U32);
Expand Down
77 changes: 77 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/addressing_mode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#include "barretenberg/vm/avm/trace/mem_trace.hpp"
#include <cstdint>

namespace bb::avm_trace {

enum class AddressingMode {
DIRECT = 0,
INDIRECT = 1,
RELATIVE = 2,
INDIRECT_RELATIVE = 3,
};

struct AddressWithMode {
AddressingMode mode;
uint32_t offset;

AddressWithMode() = default;
AddressWithMode(uint32_t offset)
: mode(AddressingMode::DIRECT)
, offset(offset)
{}
AddressWithMode(AddressingMode mode, uint32_t offset)
: mode(mode)
, offset(offset)
{}

// Dont mutate
AddressWithMode operator+(uint val) const noexcept { return { mode, offset + val }; }
};

template <size_t N> class Addressing {
public:
Addressing(const std::array<AddressingMode, N>& mode_per_operand, uint8_t space_id)
: mode_per_operand(mode_per_operand)
, space_id(space_id){};

static Addressing<N> fromWire(uint16_t wireModes, uint8_t space_id)
{
std::array<AddressingMode, N> modes;
for (size_t i = 0; i < N; i++) {
modes[i] = static_cast<AddressingMode>(
(((wireModes >> i) & 1) * static_cast<uint16_t>(AddressingMode::INDIRECT)) |
(((wireModes >> (i + N)) & 1) * static_cast<uint16_t>(AddressingMode::RELATIVE)));
}
return Addressing<N>(modes, space_id);
}

std::array<uint32_t, N> resolve(const std::array<uint32_t, N>& offsets, AvmMemTraceBuilder& mem_builder) const
{
std::array<uint32_t, N> resolved;
for (size_t i = 0; i < N; i++) {
resolved[i] = offsets[i];
const auto mode = mode_per_operand[i];
if ((static_cast<uint8_t>(mode) & static_cast<uint8_t>(AddressingMode::RELATIVE)) != 0) {
const auto mem_tag = mem_builder.unconstrained_get_memory_tag(space_id, 0);
// TODO(#9131): Error handling needs to be done
ASSERT(mem_tag == AvmMemoryTag::U32);
resolved[i] += static_cast<uint32_t>(mem_builder.unconstrained_read(space_id, 0));
}
if ((static_cast<uint8_t>(mode) & static_cast<uint8_t>(AddressingMode::INDIRECT)) != 0) {
const auto mem_tag = mem_builder.unconstrained_get_memory_tag(space_id, resolved[i]);
// TODO(#9131): Error handling needs to be done
ASSERT(mem_tag == AvmMemoryTag::U32);
resolved[i] = static_cast<uint32_t>(mem_builder.unconstrained_read(space_id, resolved[i]));
}
}
return resolved;
}

private:
std::array<AddressingMode, N> mode_per_operand;
uint8_t space_id;
};

} // namespace bb::avm_trace
Loading