Skip to content

Commit 062c6a9

Browse files
authored
feat(avm): quick n dirty memory trace (#13659)
I wanted to start generating rows for memory. I'm still not sure of the interactions between mem and range checks but there will be some so the setup makes sense.
1 parent 90c2b7b commit 062c6a9

File tree

18 files changed

+241
-20
lines changed

18 files changed

+241
-20
lines changed

barretenberg/cpp/pil/vm2/execution.pil

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ include "class_id_derivation.pil";
99
include "range_check.pil";
1010
include "bitwise.pil";
1111
include "merkle_check.pil";
12+
include "memory.pil";
1213
include "precomputed.pil";
1314
include "sha256.pil";
1415
include "ecc.pil";

barretenberg/cpp/pil/vm2/memory.pil

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
include "range_check.pil";
2+
3+
namespace memory;
4+
5+
pol commit sel;
6+
pol commit address;
7+
pol commit value;
8+
pol commit tag;
9+
pol commit rw;
10+
pol commit space_id;
11+
12+
#[skippable_if]
13+
sel = 0;
14+
15+
sel * (sel - 1) = 0;
16+
rw * (1 - rw) = 0;
17+
18+
// TODO: consider tag-value consistency checking.
19+
// TODO: consider address range checking.

barretenberg/cpp/src/barretenberg/vm2/common/tagged_value.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ template <typename Op> struct UnaryOperationVisitor {
9393

9494
} // namespace
9595

96+
uint8_t get_tag_bits(ValueTag tag)
97+
{
98+
switch (tag) {
99+
case ValueTag::U1:
100+
return 1;
101+
case ValueTag::U8:
102+
return 8;
103+
case ValueTag::U16:
104+
return 16;
105+
case ValueTag::U32:
106+
return 32;
107+
case ValueTag::U64:
108+
return 64;
109+
case ValueTag::U128:
110+
return 128;
111+
case ValueTag::FF:
112+
return 254;
113+
}
114+
115+
assert(false && "Invalid tag");
116+
return 0;
117+
}
118+
96119
// Constructor
97120
TaggedValue::TaggedValue(TaggedValue::value_type value_)
98121
: value(value_)

barretenberg/cpp/src/barretenberg/vm2/common/tagged_value.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ template <typename T> ValueTag tag_for_type()
4141
}
4242
}
4343

44+
uint8_t get_tag_bits(ValueTag tag);
45+
4446
class TaggedValue {
4547
public:
4648
// We are using variant to avoid heap allocations at the cost of a bigger memory footprint.

barretenberg/cpp/src/barretenberg/vm2/constraining/relations/sha256.test.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ using ::testing::ReturnRef;
2828
using ::testing::StrictMock;
2929

3030
using simulation::EventEmitter;
31-
using simulation::Memory;
32-
using simulation::MemoryEvent;
33-
using simulation::NoopEventEmitter;
31+
using simulation::MemoryStore;
3432
using simulation::Sha256;
3533
using simulation::Sha256CompressionEvent;
3634

@@ -53,8 +51,7 @@ TEST(Sha256ConstrainingTest, EmptyRow)
5351
// TOOD: Replace this with a hardcoded test vector and write a negative test
5452
TEST(Sha256ConstrainingTest, Basic)
5553
{
56-
NoopEventEmitter<MemoryEvent> emitter;
57-
Memory mem(/*space_id=*/0, emitter);
54+
MemoryStore mem;
5855
StrictMock<simulation::MockContext> context;
5956
EXPECT_CALL(context, get_memory()).WillRepeatedly(ReturnRef(mem));
6057

@@ -89,8 +86,7 @@ TEST(Sha256ConstrainingTest, Basic)
8986

9087
TEST(Sha256ConstrainingTest, Interaction)
9188
{
92-
NoopEventEmitter<MemoryEvent> emitter;
93-
Memory mem(/*space_id=*/0, emitter);
89+
MemoryStore mem;
9490
StrictMock<simulation::MockContext> context;
9591
EXPECT_CALL(context, get_memory()).WillRepeatedly(ReturnRef(mem));
9692

barretenberg/cpp/src/barretenberg/vm2/generated/columns.hpp

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

barretenberg/cpp/src/barretenberg/vm2/generated/flavor_variables.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "relations/execution.hpp"
1616
#include "relations/ff_gt.hpp"
1717
#include "relations/instr_fetching.hpp"
18+
#include "relations/memory.hpp"
1819
#include "relations/merkle_check.hpp"
1920
#include "relations/nullifier_check.hpp"
2021
#include "relations/poseidon2_hash.hpp"
@@ -49,10 +50,10 @@ namespace bb::avm2 {
4950

5051
struct AvmFlavorVariables {
5152
static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 45;
52-
static constexpr size_t NUM_WITNESS_ENTITIES = 1020;
53+
static constexpr size_t NUM_WITNESS_ENTITIES = 1026;
5354
static constexpr size_t NUM_SHIFTED_ENTITIES = 135;
5455
static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES;
55-
static constexpr size_t NUM_ALL_ENTITIES = 1200;
56+
static constexpr size_t NUM_ALL_ENTITIES = 1206;
5657

5758
// Need to be templated for recursive verifier
5859
template <typename FF_>
@@ -71,6 +72,7 @@ struct AvmFlavorVariables {
7172
avm2::execution<FF_>,
7273
avm2::ff_gt<FF_>,
7374
avm2::instr_fetching<FF_>,
75+
avm2::memory<FF_>,
7476
avm2::merkle_check<FF_>,
7577
avm2::nullifier_check<FF_>,
7678
avm2::poseidon2_hash<FF_>,
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// AUTOGENERATED FILE
2+
#pragma once
3+
4+
#include <string_view>
5+
6+
#include "barretenberg/relations/relation_parameters.hpp"
7+
#include "barretenberg/relations/relation_types.hpp"
8+
9+
namespace bb::avm2 {
10+
11+
template <typename FF_> class memoryImpl {
12+
public:
13+
using FF = FF_;
14+
15+
static constexpr std::array<size_t, 2> SUBRELATION_PARTIAL_LENGTHS = { 3, 3 };
16+
17+
template <typename AllEntities> inline static bool skip(const AllEntities& in)
18+
{
19+
const auto& new_term = in;
20+
return (new_term.memory_sel).is_zero();
21+
}
22+
23+
template <typename ContainerOverSubrelations, typename AllEntities>
24+
void static accumulate(ContainerOverSubrelations& evals,
25+
const AllEntities& new_term,
26+
[[maybe_unused]] const RelationParameters<FF>&,
27+
[[maybe_unused]] const FF& scaling_factor)
28+
{
29+
30+
{
31+
using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
32+
auto tmp = new_term.memory_sel * (new_term.memory_sel - FF(1));
33+
tmp *= scaling_factor;
34+
std::get<0>(evals) += typename Accumulator::View(tmp);
35+
}
36+
{
37+
using Accumulator = typename std::tuple_element_t<1, ContainerOverSubrelations>;
38+
auto tmp = new_term.memory_rw * (FF(1) - new_term.memory_rw);
39+
tmp *= scaling_factor;
40+
std::get<1>(evals) += typename Accumulator::View(tmp);
41+
}
42+
}
43+
};
44+
45+
template <typename FF> class memory : public Relation<memoryImpl<FF>> {
46+
public:
47+
static constexpr const std::string_view NAME = "memory";
48+
49+
static std::string get_subrelation_label(size_t index)
50+
{
51+
switch (index) {}
52+
return std::to_string(index);
53+
}
54+
};
55+
56+
} // namespace bb::avm2

barretenberg/cpp/src/barretenberg/vm2/simulation/execution_components.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ std::unique_ptr<ContextInterface> ExecutionComponentsProvider::make_nested_conte
1919
msg_sender,
2020
is_static,
2121
std::make_unique<BytecodeManager>(address, tx_bytecode_manager),
22-
std::make_unique<Memory>(context_id, memory_events),
22+
std::make_unique<Memory>(context_id, range_check, memory_events),
2323
parent_context,
2424
cd_offset_address,
2525
cd_size_address);
@@ -37,7 +37,7 @@ std::unique_ptr<ContextInterface> ExecutionComponentsProvider::make_enqueued_con
3737
msg_sender,
3838
is_static,
3939
std::make_unique<BytecodeManager>(address, tx_bytecode_manager),
40-
std::make_unique<Memory>(context_id, memory_events),
40+
std::make_unique<Memory>(context_id, range_check, memory_events),
4141
calldata);
4242
}
4343

barretenberg/cpp/src/barretenberg/vm2/simulation/execution_components.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "barretenberg/vm2/simulation/events/event_emitter.hpp"
1414
#include "barretenberg/vm2/simulation/events/memory_event.hpp"
1515
#include "barretenberg/vm2/simulation/memory.hpp"
16+
#include "barretenberg/vm2/simulation/range_check.hpp"
1617

1718
namespace bb::avm2::simulation {
1819

@@ -39,9 +40,11 @@ class ExecutionComponentsProviderInterface {
3940
class ExecutionComponentsProvider : public ExecutionComponentsProviderInterface {
4041
public:
4142
ExecutionComponentsProvider(TxBytecodeManagerInterface& tx_bytecode_manager,
43+
RangeCheckInterface& range_check,
4244
EventEmitterInterface<MemoryEvent>& memory_events,
4345
const InstructionInfoDBInterface& instruction_info_db)
4446
: tx_bytecode_manager(tx_bytecode_manager)
47+
, range_check(range_check)
4548
, memory_events(memory_events)
4649
, instruction_info_db(instruction_info_db)
4750
{}
@@ -61,6 +64,7 @@ class ExecutionComponentsProvider : public ExecutionComponentsProviderInterface
6164
uint32_t next_context_id = 0;
6265

6366
TxBytecodeManagerInterface& tx_bytecode_manager;
67+
RangeCheckInterface& range_check;
6468
EventEmitterInterface<MemoryEvent>& memory_events;
6569
const InstructionInfoDBInterface& instruction_info_db;
6670

barretenberg/cpp/src/barretenberg/vm2/simulation/memory.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <memory>
55

66
#include "barretenberg/common/log.hpp"
7+
#include "barretenberg/numeric/uint128/uint128.hpp"
78
#include "barretenberg/vm2/common/memory_types.hpp"
89

910
namespace bb::avm2::simulation {
@@ -21,14 +22,17 @@ bool MemoryInterface::is_valid_address(const MemoryValue& address)
2122

2223
void Memory::set(MemoryAddress index, MemoryValue value)
2324
{
24-
// TODO: validate tag-value makes sense.
25+
// TODO: validate address?
26+
// TODO: reconsider tag validation.
27+
validate_tag(value);
2528
memory[index] = value;
2629
debug("Memory write: ", index, " <- ", value.to_string());
2730
events.emit({ .mode = MemoryMode::WRITE, .addr = index, .value = value, .space_id = space_id });
2831
}
2932

3033
const MemoryValue& Memory::get(MemoryAddress index) const
3134
{
35+
// TODO: validate address?
3236
static const auto default_value = MemoryValue::from<FF>(0);
3337

3438
auto it = memory.find(index);
@@ -39,4 +43,17 @@ const MemoryValue& Memory::get(MemoryAddress index) const
3943
return vt;
4044
}
4145

46+
// Sadly this is circuit leaking. In simulation we know the tag-value is consistent.
47+
// But the circuit does need to force a range check.
48+
void Memory::validate_tag(const MemoryValue& value) const
49+
{
50+
if (value.get_tag() == MemoryTag::FF) {
51+
return;
52+
}
53+
54+
uint128_t value_as_uint128 = static_cast<uint128_t>(value.as_ff());
55+
auto tag_bits = get_tag_bits(value.get_tag());
56+
range_check.assert_range(value_as_uint128, tag_bits);
57+
}
58+
4259
} // namespace bb::avm2::simulation

barretenberg/cpp/src/barretenberg/vm2/simulation/memory.hpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "barretenberg/vm2/common/memory_types.hpp"
77
#include "barretenberg/vm2/simulation/events/event_emitter.hpp"
88
#include "barretenberg/vm2/simulation/events/memory_event.hpp"
9+
#include "barretenberg/vm2/simulation/range_check.hpp"
910

1011
namespace bb::avm2::simulation {
1112

@@ -26,8 +27,9 @@ class MemoryInterface {
2627

2728
class Memory : public MemoryInterface {
2829
public:
29-
Memory(uint32_t space_id, EventEmitterInterface<MemoryEvent>& event_emitter)
30+
Memory(uint32_t space_id, RangeCheckInterface& range_check, EventEmitterInterface<MemoryEvent>& event_emitter)
3031
: space_id(space_id)
32+
, range_check(range_check)
3133
, events(event_emitter)
3234
{}
3335

@@ -39,7 +41,33 @@ class Memory : public MemoryInterface {
3941
private:
4042
uint32_t space_id;
4143
unordered_flat_map<size_t, MemoryValue> memory;
44+
45+
RangeCheckInterface& range_check;
46+
// TODO: consider a deduplicating event emitter (within the same clk).
4247
EventEmitterInterface<MemoryEvent>& events;
48+
49+
void validate_tag(const MemoryValue& value) const;
50+
};
51+
52+
// Just a map that doesn't emit events or do anything else.
53+
class MemoryStore : public MemoryInterface {
54+
public:
55+
MemoryStore(uint32_t space_id = 0)
56+
: space_id(space_id)
57+
{}
58+
59+
const MemoryValue& get(MemoryAddress index) const override
60+
{
61+
static const auto default_value = MemoryValue::from<FF>(0);
62+
auto it = memory.find(index);
63+
return it != memory.end() ? it->second : default_value;
64+
}
65+
void set(MemoryAddress index, MemoryValue value) override { memory[index] = value; }
66+
uint32_t get_space_id() const override { return space_id; }
67+
68+
private:
69+
uint32_t space_id;
70+
unordered_flat_map<size_t, MemoryValue> memory;
4371
};
4472

4573
} // namespace bb::avm2::simulation

barretenberg/cpp/src/barretenberg/vm2/simulation/sha256.test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <gmock/gmock.h>
44
#include <gtest/gtest.h>
55

6+
#include "barretenberg/crypto/merkle_tree/memory_store.hpp"
67
#include "barretenberg/vm2/common/memory_types.hpp"
78
#include "barretenberg/vm2/simulation/events/event_emitter.hpp"
89
#include "barretenberg/vm2/simulation/events/memory_event.hpp"
@@ -18,8 +19,7 @@ using ::testing::StrictMock;
1819

1920
TEST(Sha256CompressionSimulationTest, Sha256Compression)
2021
{
21-
NoopEventEmitter<MemoryEvent> emitter;
22-
Memory mem(/*space_id=*/0, emitter);
22+
MemoryStore mem;
2323
StrictMock<MockContext> context;
2424
EXPECT_CALL(context, get_memory()).WillRepeatedly(ReturnRef(mem));
2525

barretenberg/cpp/src/barretenberg/vm2/simulation_helper.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ template <typename S> EventsContainer AvmSimulationHelper::simulate_with_setting
124124
bytecode_retrieval_emitter,
125125
bytecode_decomposition_emitter,
126126
instruction_fetching_emitter);
127-
ExecutionComponentsProvider execution_components(bytecode_manager, memory_emitter, instruction_info_db);
127+
ExecutionComponentsProvider execution_components(
128+
bytecode_manager, range_check, memory_emitter, instruction_info_db);
128129

129130
Alu alu(alu_emitter);
130131
Execution execution(alu, execution_components, instruction_info_db, execution_emitter, context_stack_emitter);

barretenberg/cpp/src/barretenberg/vm2/tracegen/lib/lookup_builder.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "barretenberg/common/utils.hpp"
1010
#include "barretenberg/vm2/common/field.hpp"
1111
#include "barretenberg/vm2/common/map.hpp"
12+
#include "barretenberg/vm2/common/stringify.hpp"
1213
#include "barretenberg/vm2/generated/columns.hpp"
1314
#include "barretenberg/vm2/tracegen/lib/interaction_builder.hpp"
1415
#include "barretenberg/vm2/tracegen/trace_container.hpp"
@@ -74,6 +75,14 @@ class LookupIntoDynamicTableGeneric : public BaseLookupTraceBuilder<LookupSettin
7475
if (it != row_idx.end()) {
7576
return it->second;
7677
}
78+
vinfo(
79+
"Failed computing counts for ",
80+
std::string(LookupSettings::NAME),
81+
" with src tuple: {",
82+
[&tup]<size_t... Is>(std::index_sequence<Is...>) {
83+
return ((field_to_string(tup[Is]) + ", ") + ...);
84+
}(std::make_index_sequence<LookupSettings::LOOKUP_TUPLE_SIZE>()),
85+
"}");
7786
throw std::runtime_error("Failed computing counts for " + std::string(LookupSettings::NAME) +
7887
". Could not find tuple in destination.");
7988
}

0 commit comments

Comments
 (0)