Skip to content

Commit 78de546

Browse files
committed
fix(avm)!: handle zero copy size
1 parent 9b5e114 commit 78de546

7 files changed

Lines changed: 225 additions & 88 deletions

File tree

barretenberg/cpp/pil/vm2/data_copy.pil

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,6 @@ namespace data_copy;
118118
pol commit sel_rd_copy;
119119
sel_rd_copy * (1 - sel_rd_copy) = 0;
120120

121-
// Two varieties depending of if we gate by error
122-
pol SEL_NO_ERR = SEL * (1 - err);
123-
124121
pol commit clk;
125122

126123
// Things are range checked to 32 bits
@@ -224,11 +221,21 @@ namespace data_copy;
224221
#[START_AFTER_END]
225222
(sel_cd_copy' + sel_rd_copy') * sel_end * (sel_start' - 1) = 0;
226223

224+
pol commit sel_write_count_is_zero;
225+
pol commit write_count_zero_inv; // Could optimise by using the existing write_count_minus_on_inv
226+
// sel_write_count_is_zero = 1 IFF copy_size = 0 && sel_start = 1 (and there are no errors)
227+
#[ZERO_SIZED_WRITE]
228+
sel_start_no_err * (copy_size * (sel_write_count_is_zero * (1 - write_count_zero_inv) + write_count_zero_inv) - 1 + sel_write_count_is_zero) = 0;
229+
#[END_IF_WRITE_IS_ZERO]
230+
sel_start_no_err * sel_write_count_is_zero * (sel_end - 1) = 0;
231+
232+
pol SEL_PERFORM_COPY = SEL * (1 - err) * (1 - sel_write_count_is_zero);
233+
227234
pol WRITE_COUNT_MINUS_ONE = copy_size - 1;
228235
pol commit write_count_minus_one_inv;
229236
// sel_end = 1 IFF copy_size - 1 = 0;
230237
#[END_WRITE_CONDITION]
231-
SEL_NO_ERR * (WRITE_COUNT_MINUS_ONE * (sel_end * (1 - write_count_minus_one_inv) + write_count_minus_one_inv) - 1 + sel_end) = 0;
238+
SEL_PERFORM_COPY * (WRITE_COUNT_MINUS_ONE * (sel_end * (1 - write_count_minus_one_inv) + write_count_minus_one_inv) - 1 + sel_end) = 0;
232239

233240
#[END_ON_ERR] // sel_end = 1 if error
234241
err * (sel_end - 1) = 0;
@@ -246,15 +253,15 @@ namespace data_copy;
246253
// If sel_offset_gt_max_read = 1 (i.e. when offset > MAX_READ_INDEX, reads_left = 0)
247254
// otherwise, reads_left = MAX_READ_INDEX - offset
248255
#[INIT_READS_LEFT]
249-
sel_start_no_err * ( reads_left - (max_read_index - offset) * (1 - offset_gt_max_read_index)) = 0;
256+
sel_start_no_err * (1 - sel_write_count_is_zero) * (reads_left - (max_read_index - offset) * (1 - offset_gt_max_read_index)) = 0;
250257

251258
//////////////////////////////
252259
// Execute Data Copy
253260
//////////////////////////////
254261
// Most of these relations are either gated explicitly by an err or by sel_end (which is 1 when err = 1)
255262
// ===== Writing to dst_context_id =====
256263
pol commit sel_mem_write;
257-
sel_mem_write = SEL_NO_ERR; // We write if there is no error
264+
sel_mem_write = SEL_PERFORM_COPY * (1 - sel_write_count_is_zero); // We write if there is no error and copy_size != 0
258265
// Data copy size decrements for each row until we end
259266
#[DECR_COPY_SIZE]
260267
SEL * (1 - sel_end) * (copy_size' - copy_size + 1) = 0;
@@ -270,7 +277,7 @@ namespace data_copy;
270277
// ===== Reading for nested call =====
271278
pol commit read_addr; // The addr to start reading the data from: src_addr + offset;
272279
#[INIT_READ_ADDR]
273-
SEL * sel_start_no_err * (read_addr - src_addr - offset) = 0;
280+
sel_start_no_err * (1 - sel_write_count_is_zero) * (read_addr - src_addr - offset) = 0;
274281
// Subsequent read addrs are incremented by 1 unless this is a padding row
275282
#[INCR_READ_ADDR]
276283
SEL * (1 - padding) * (1 - sel_end) * (read_addr' - read_addr - 1) = 0;
@@ -281,16 +288,16 @@ namespace data_copy;
281288
pol commit padding; // Padding = 1 if reads_left = 0
282289
pol commit reads_left_inv;
283290
#[PADDING_CONDITION]
284-
SEL_NO_ERR * (reads_left * (padding * (1 - reads_left_inv) + reads_left_inv) - 1 + padding) = 0;
291+
SEL_PERFORM_COPY * (reads_left * (padding * (1 - reads_left_inv) + reads_left_inv) - 1 + padding) = 0;
285292

286293
// Read from memory if we are not the top level call and not a padding row
287294
pol commit sel_mem_read; // If the current row is a memory op read
288-
sel_mem_read = SEL_NO_ERR * (1 - is_top_level) * (1 - padding);
295+
sel_mem_read = SEL_PERFORM_COPY * (1 - is_top_level) * (1 - padding);
289296

290297
// === Value Padding ===
291298
pol commit value;
292299
#[PAD_VALUE]
293-
SEL_NO_ERR * padding * value = 0;
300+
SEL_PERFORM_COPY * padding * value = 0;
294301

295302
#[MEM_READ]
296303
sel_mem_read { clk, read_addr, value, /*mem_tag=*/precomputed.zero/*FF*/, /*rw=*/precomputed.zero/*(read)*/, src_context_id }
@@ -303,7 +310,7 @@ namespace data_copy;
303310
// After calldata hashing
304311
pol commit cd_copy_col_read;
305312
#[CD_COPY_COLUMN]
306-
cd_copy_col_read = SEL_NO_ERR * (1 - padding) * is_top_level * sel_cd_copy;
313+
cd_copy_col_read = SEL_PERFORM_COPY * (1 - padding) * is_top_level * sel_cd_copy;
307314

308315
#[COL_READ]
309316
cd_copy_col_read { value, dst_context_id, read_addr }
@@ -355,3 +362,4 @@ namespace data_copy;
355362
src_addr, src_data_size,
356363
sel_rd_copy, err
357364
};
365+

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,29 @@ class NestedCdConstrainingBuilderTest : public DataCopyConstrainingBuilderTest {
7474
}
7575
};
7676

77+
TEST_F(NestedCdConstrainingBuilderTest, CdZeroCopy)
78+
{
79+
uint32_t copy_size = 0;
80+
uint32_t cd_offset = 0; // Offset into calldata
81+
82+
EXPECT_CALL(context, get_calldata(cd_offset, copy_size)).WillOnce(::testing::Return(std::vector<FF>{}));
83+
84+
copy_data.cd_copy(context, copy_size, cd_offset, dst_addr);
85+
86+
tracegen::DataCopyTraceBuilder builder;
87+
builder.process(event_emitter.dump_events(), trace);
88+
89+
tracegen::GreaterThanTraceBuilder gt_builder;
90+
gt_builder.process(gt_event_emitter.dump_events(), trace);
91+
92+
check_relation<data_copy>(trace);
93+
check_interaction<DataCopyTraceBuilder,
94+
lookup_data_copy_max_read_index_gt_settings,
95+
lookup_data_copy_offset_gt_max_read_index_settings,
96+
lookup_data_copy_check_src_addr_in_range_settings,
97+
lookup_data_copy_check_dst_addr_in_range_settings>(trace);
98+
}
99+
77100
TEST_F(NestedCdConstrainingBuilderTest, SimpleNestedCdCopy)
78101
{
79102
uint32_t copy_size = static_cast<uint32_t>(data.size());
@@ -194,6 +217,29 @@ class EnqueuedCdConstrainingBuilderTest : public DataCopyConstrainingBuilderTest
194217
}
195218
};
196219

220+
TEST_F(EnqueuedCdConstrainingBuilderTest, CdZeroCopy)
221+
{
222+
uint32_t copy_size = 0;
223+
uint32_t cd_offset = 0; // Offset into calldata
224+
225+
EXPECT_CALL(context, get_calldata(cd_offset, copy_size)).WillOnce(::testing::Return(std::vector<FF>{}));
226+
227+
copy_data.cd_copy(context, copy_size, cd_offset, dst_addr);
228+
229+
tracegen::DataCopyTraceBuilder builder;
230+
builder.process(event_emitter.dump_events(), trace);
231+
232+
tracegen::GreaterThanTraceBuilder gt_builder;
233+
gt_builder.process(gt_event_emitter.dump_events(), trace);
234+
235+
check_relation<data_copy>(trace);
236+
check_interaction<DataCopyTraceBuilder,
237+
lookup_data_copy_max_read_index_gt_settings,
238+
lookup_data_copy_offset_gt_max_read_index_settings,
239+
lookup_data_copy_check_src_addr_in_range_settings,
240+
lookup_data_copy_check_dst_addr_in_range_settings>(trace);
241+
}
242+
197243
TEST_F(EnqueuedCdConstrainingBuilderTest, SimpleEnqueuedCdCopy)
198244
{
199245
auto copy_size = static_cast<uint32_t>(data.size());
@@ -343,6 +389,42 @@ TEST(DataCopyWithExecutionPerm, CdCopy)
343389
perm_data_copy_dispatch_rd_copy_settings>(trace);
344390
}
345391

392+
class NestedRdConstrainingBuilderTest : public DataCopyConstrainingBuilderTest {
393+
protected:
394+
NestedRdConstrainingBuilderTest()
395+
{
396+
// Set up parent context
397+
EXPECT_CALL(context, has_parent).WillRepeatedly(Return(true));
398+
EXPECT_CALL(context, get_last_child_id).WillRepeatedly(Return(2));
399+
EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(2));
400+
EXPECT_CALL(context, get_last_rd_size).WillRepeatedly(Return(data.size()));
401+
EXPECT_CALL(context, get_last_rd_addr).WillRepeatedly(Return(0));
402+
}
403+
};
404+
405+
TEST_F(NestedRdConstrainingBuilderTest, RdZeroCopy)
406+
{
407+
uint32_t copy_size = 0;
408+
uint32_t rd_offset = 0; // Offset into calldata
409+
410+
EXPECT_CALL(context, get_returndata(rd_offset, copy_size)).WillOnce(::testing::Return(std::vector<FF>{}));
411+
412+
copy_data.rd_copy(context, copy_size, rd_offset, dst_addr);
413+
414+
tracegen::DataCopyTraceBuilder builder;
415+
builder.process(event_emitter.dump_events(), trace);
416+
417+
tracegen::GreaterThanTraceBuilder gt_builder;
418+
gt_builder.process(gt_event_emitter.dump_events(), trace);
419+
420+
check_relation<data_copy>(trace);
421+
check_interaction<DataCopyTraceBuilder,
422+
lookup_data_copy_max_read_index_gt_settings,
423+
lookup_data_copy_offset_gt_max_read_index_settings,
424+
lookup_data_copy_check_src_addr_in_range_settings,
425+
lookup_data_copy_check_dst_addr_in_range_settings>(trace);
426+
}
427+
346428
TEST(DataCopyWithExecutionPerm, RdCopy)
347429
{
348430
// Current Context

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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ namespace bb::avm2 {
132132

133133
struct AvmFlavorVariables {
134134
static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 133;
135-
static constexpr size_t NUM_WITNESS_ENTITIES = 2925;
135+
static constexpr size_t NUM_WITNESS_ENTITIES = 2927;
136136
static constexpr size_t NUM_SHIFTED_ENTITIES = 316;
137137
static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES;
138-
static constexpr size_t NUM_ALL_ENTITIES = 3374;
138+
static constexpr size_t NUM_ALL_ENTITIES = 3376;
139139

140140
// Need to be templated for recursive verifier
141141
template <typename FF_>

barretenberg/cpp/src/barretenberg/vm2/generated/relations/data_copy.hpp

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ template <typename FF_> class data_copyImpl {
1414
public:
1515
using FF = FF_;
1616

17-
static constexpr std::array<size_t, 33> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 3, 3, 3, 3, 5, 3, 4, 3, 3,
18-
3, 4, 3, 3, 3, 3, 4, 6, 3, 4, 3,
19-
4, 5, 4, 5, 5, 6, 5, 5, 6, 3, 3 };
17+
static constexpr std::array<size_t, 35> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 3, 3, 3, 3, 5, 3, 4, 3, 3, 3,
18+
4, 3, 3, 3, 3, 4, 5, 4, 7, 3, 5, 5,
19+
4, 5, 4, 5, 5, 7, 6, 6, 7, 3, 3 };
2020

2121
template <typename AllEntities> inline static bool skip(const AllEntities& in)
2222
{
@@ -46,26 +46,30 @@ template <typename FF> class data_copy : public Relation<data_copyImpl<FF>> {
4646
case 17:
4747
return "START_AFTER_END";
4848
case 18:
49-
return "END_WRITE_CONDITION";
49+
return "ZERO_SIZED_WRITE";
5050
case 19:
51-
return "END_ON_ERR";
51+
return "END_IF_WRITE_IS_ZERO";
5252
case 20:
53-
return "INIT_READS_LEFT";
53+
return "END_WRITE_CONDITION";
54+
case 21:
55+
return "END_ON_ERR";
5456
case 22:
57+
return "INIT_READS_LEFT";
58+
case 24:
5559
return "DECR_COPY_SIZE";
56-
case 23:
60+
case 25:
5761
return "INCR_WRITE_ADDR";
58-
case 24:
62+
case 26:
5963
return "INIT_READ_ADDR";
60-
case 25:
64+
case 27:
6165
return "INCR_READ_ADDR";
62-
case 26:
66+
case 28:
6367
return "DECR_READ_COUNT";
64-
case 27:
65-
return "PADDING_CONDITION";
6668
case 29:
69+
return "PADDING_CONDITION";
70+
case 31:
6771
return "PAD_VALUE";
68-
case 30:
72+
case 32:
6973
return "CD_COPY_COLUMN";
7074
}
7175
return std::to_string(index);
@@ -74,17 +78,19 @@ template <typename FF> class data_copy : public Relation<data_copyImpl<FF>> {
7478
// Subrelation indices constants, to be used in tests.
7579
static constexpr size_t SR_TOP_LEVEL_COND = 6;
7680
static constexpr size_t SR_START_AFTER_END = 17;
77-
static constexpr size_t SR_END_WRITE_CONDITION = 18;
78-
static constexpr size_t SR_END_ON_ERR = 19;
79-
static constexpr size_t SR_INIT_READS_LEFT = 20;
80-
static constexpr size_t SR_DECR_COPY_SIZE = 22;
81-
static constexpr size_t SR_INCR_WRITE_ADDR = 23;
82-
static constexpr size_t SR_INIT_READ_ADDR = 24;
83-
static constexpr size_t SR_INCR_READ_ADDR = 25;
84-
static constexpr size_t SR_DECR_READ_COUNT = 26;
85-
static constexpr size_t SR_PADDING_CONDITION = 27;
86-
static constexpr size_t SR_PAD_VALUE = 29;
87-
static constexpr size_t SR_CD_COPY_COLUMN = 30;
81+
static constexpr size_t SR_ZERO_SIZED_WRITE = 18;
82+
static constexpr size_t SR_END_IF_WRITE_IS_ZERO = 19;
83+
static constexpr size_t SR_END_WRITE_CONDITION = 20;
84+
static constexpr size_t SR_END_ON_ERR = 21;
85+
static constexpr size_t SR_INIT_READS_LEFT = 22;
86+
static constexpr size_t SR_DECR_COPY_SIZE = 24;
87+
static constexpr size_t SR_INCR_WRITE_ADDR = 25;
88+
static constexpr size_t SR_INIT_READ_ADDR = 26;
89+
static constexpr size_t SR_INCR_READ_ADDR = 27;
90+
static constexpr size_t SR_DECR_READ_COUNT = 28;
91+
static constexpr size_t SR_PADDING_CONDITION = 29;
92+
static constexpr size_t SR_PAD_VALUE = 31;
93+
static constexpr size_t SR_CD_COPY_COLUMN = 32;
8894
};
8995

9096
} // namespace bb::avm2

0 commit comments

Comments
 (0)