Skip to content

Commit 6d21c85

Browse files
authored
feat(avm)!: Remove some range checks in bc decomposition subtrace (#16453)
Range checks related to setting the boolean asserting "WINDOWS > bytes_remaining" have been removed and replaced by "standard relations". The newly introduced relations leverage on "bytes_remaining" column being a decrementing counter. We set the selector to be 0 at the row where "bytes_remaining == WINDOWS" and 1 for the next row (bytes_remaining == WINDOWS - 1) and then propagate value 0 to the top and value 1 to the bottom. Benchmarks after this PR: ``` bc_decomposition_acc 7.54 us 7.54 us 92926 bc_decomposition_interactions_acc 0.351 us 0.351 us 1988845 ``` Benchmarks before this PR: ``` bc_decomposition_acc 7.35 us 7.35 us 94833 bc_decomposition_interactions_acc 1.15 us 1.15 us 610300 ``` NUM_WITNESS_ENTITIES went from 2922 to 2917; NUM_SHIFTED_ENTITIES wnet from 315 to 316;
2 parents f3fe5a3 + 4f80335 commit 6d21c85

10 files changed

Lines changed: 307 additions & 257 deletions

File tree

barretenberg/cpp/pil/vm2/bytecode/bc_decomposition.pil

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -132,37 +132,45 @@ pol commit bytes_pc_plus_1, bytes_pc_plus_2, bytes_pc_plus_3, bytes_pc_plus_4, b
132132
// 39 | 1 | 1 | 0xD | 0x0 | 0x0 | ...
133133

134134
pol commit bytes_to_read;
135-
pol commit sel_overflow_correction_needed;
136-
sel_overflow_correction_needed * (1 - sel_overflow_correction_needed) = 0;
135+
pol commit sel_windows_gt_remaining;
136+
sel_windows_gt_remaining * (1 - sel_windows_gt_remaining) = 0;
137137
// We need to constrain bytes_to_read = min(WINDOW_SIZE, bytes_remaining) which is equal to
138138
// bytes_remaining if bytes_remaining <= WINDOW_SIZE and WINDOW_SIZE otherwise.
139139

140-
// Absolute value of WINDOW_SIZE - bytes_remaining
141-
pol commit abs_diff;
142-
// Remark: The factor sel in relation below is only required to use the skippable mechanism.
143-
// sel_overflow_correction_needed = 1 if bytes_remaining < WINDOW_SIZE and
144-
// sel_overflow_correction_needed = 0 if bytes_remaining > WINDOW_SIZE
145-
#[BC_DEC_ABS_DIFF]
146-
sel * (2 * sel_overflow_correction_needed * (WINDOW_SIZE - bytes_remaining) - WINDOW_SIZE + bytes_remaining - abs_diff) = 0;
140+
pol commit is_windows_eq_remaining;
141+
pol commit windows_min_remaining_inv;
142+
is_windows_eq_remaining * (1 - is_windows_eq_remaining) = 0;
147143

148-
// We prove that the abs_diff is positive (and therefore sel_overflow_correction_needed correct) over the integers
149-
// using a range check over 24 bits. We know that WINDOWS_SIZE fits into 16 bits and bytes_remaining cannot be larger
150-
// than the trace size 2^21 (and bytecode hashing/validation could not pass). This provides guarantee that
151-
// abs_diff cannot be the result of an underflow. This would be only possible for bytes_remaining being very close
152-
// to the field order.
144+
// bytes_remaining == WINDOW_SIZE <==> is_windows_eq_remaining == 1
145+
#[IS_WINDOWS_EQ_REMAINING]
146+
sel * ((WINDOW_SIZE - bytes_remaining) * (is_windows_eq_remaining * (1 - windows_min_remaining_inv) + windows_min_remaining_inv) + is_windows_eq_remaining - 1) = 0;
153147

154-
pol commit abs_diff_lo;
155-
pol commit abs_diff_hi;
156-
abs_diff = abs_diff_hi * 2**16 + abs_diff_lo;
157148

158-
#[ABS_DIFF_LO_IS_U16]
159-
sel { abs_diff_lo } in precomputed.sel_range_16 { precomputed.clk };
160-
161-
#[ABS_DIFF_HI_IS_U8]
162-
sel { abs_diff_hi } in precomputed.sel_range_8 { precomputed.clk };
163-
164-
#[BC_DEC_OVERFLOW_CORRECTION_VALUE]
165-
sel * ((1 - sel_overflow_correction_needed) * (bytes_to_read - WINDOW_SIZE) + sel_overflow_correction_needed * (bytes_to_read - bytes_remaining)) = 0;
149+
// We want to constrain sel_windows_gt_remaining as follows:
150+
// sel_windows_gt_remaining = 1 if bytes_remaining < WINDOW_SIZE and
151+
// sel_windows_gt_remaining = 0 if bytes_remaining >= WINDOW_SIZE
152+
//
153+
// Instead of using range-checks/GT gadget to show an inequality, we leverage on the fact that bytes_remaining
154+
// is a decrementing counter.
155+
// So the pattern for sel_windows_gt_remaining bottom-up is: 1, 1, 1, ..., 1, 0, 0, 0, ...
156+
// where first 0 entry is at the row where bytes_remaining == WINDOW_SIZE.
157+
//
158+
// We initialize sel_windows_gt_remaining = 1 on last row of the bytecode
159+
// and propagate the boolean value to the above row whenever bytes_remaining != WINDOW_SIZE.
160+
// If we encounter the row where bytes_remaining == WINDOW_SIZE, we swap the boolean value.
161+
// Whenever the bytecode is smaller than WINDOW_SIZE, we exclusively propagate the value 1.
162+
163+
// Set sel_windows_gt_remaining = 1 on the last row of the bytecode.
164+
#[SEL_WINDOWS_GT_REMAINING_INIT]
165+
last_of_contract * (1 - sel_windows_gt_remaining) = 0;
166+
167+
// If we reach is_windows_eq_remaining == 1, we pass from 1 to 0. (Decrement a single time.)
168+
// sel_windows_gt_remaining = sel_windows_gt_remaining' - is_windows_eq_remaining
169+
#[SEL_WINDOWS_GT_REMAINING_PROPAGATION]
170+
(1 - FIRST_OR_LAST_CONTRACT) * (sel_windows_gt_remaining' - is_windows_eq_remaining - sel_windows_gt_remaining) = 0;
171+
172+
#[SET_BYTES_TO_READ]
173+
sel * ((1 - sel_windows_gt_remaining) * (bytes_to_read - WINDOW_SIZE) + sel_windows_gt_remaining * (bytes_to_read - bytes_remaining)) = 0;
166174

167175
// Constrain shifted columns.
168176
// We need to guard with (1 - FIRST_OR_LAST_CONTRACT) because otherwise we would need to copy value

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

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace {
2121
using testing::random_bytes;
2222
using testing::random_contract_class;
2323
using tracegen::BytecodeTraceBuilder;
24+
using tracegen::DECOMPOSE_WINDOW_SIZE;
2425
using tracegen::TestTraceContainer;
2526

2627
using FF = AvmFlavorSettings::FF;
@@ -256,21 +257,102 @@ TEST(BytecodeDecompositionConstrainingTest, NegativeMutateBytecodeId)
256257
"BC_DEC_ID_CONSTANT");
257258
}
258259

260+
// Both positive and negative tests for sel_windows_gt_remaining initialization
261+
TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingInitialization)
262+
{
263+
TestTraceContainer trace = TestTraceContainer::from_rows({
264+
{
265+
.bc_decomposition_last_of_contract = 1,
266+
.bc_decomposition_sel = 1,
267+
.bc_decomposition_sel_windows_gt_remaining = 1,
268+
},
269+
});
270+
271+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT);
272+
273+
trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value
274+
EXPECT_THROW_WITH_MESSAGE(
275+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT),
276+
"SEL_WINDOWS_GT_REMAINING_INIT");
277+
}
278+
279+
// Both positive and negative tests for sel_windows_gt_remaining propagation without mutation.
280+
TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagation)
281+
{
282+
TestTraceContainer trace = TestTraceContainer::from_rows({
283+
{
284+
.bc_decomposition_sel = 1,
285+
.bc_decomposition_sel_windows_gt_remaining = 1,
286+
},
287+
{
288+
.bc_decomposition_last_of_contract = 1,
289+
.bc_decomposition_sel = 1,
290+
.bc_decomposition_sel_windows_gt_remaining = 1,
291+
},
292+
});
293+
294+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
295+
296+
trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value at the top
297+
EXPECT_THROW_WITH_MESSAGE(
298+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
299+
"SEL_WINDOWS_GT_REMAINING_PROPAGATION");
300+
301+
// Reset to correct value
302+
trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1);
303+
304+
trace.set(C::bc_decomposition_sel_windows_gt_remaining, 1, 0); // Mutate to wrong value at the bottom
305+
EXPECT_THROW_WITH_MESSAGE(
306+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
307+
"SEL_WINDOWS_GT_REMAINING_PROPAGATION");
308+
309+
// Test propagattion of 0 instead of 1
310+
trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to correct value
311+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
312+
}
313+
314+
// Both positive and negative tests for sel_windows_gt_remaining propagation with mutation.
315+
TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagationWithMutation)
316+
{
317+
TestTraceContainer trace = TestTraceContainer::from_rows({
318+
{
319+
.bc_decomposition_is_windows_eq_remaining = 1,
320+
.bc_decomposition_sel = 1,
321+
.bc_decomposition_sel_windows_gt_remaining = 0,
322+
},
323+
{
324+
.bc_decomposition_sel = 1,
325+
.bc_decomposition_sel_windows_gt_remaining = 1,
326+
},
327+
{
328+
.bc_decomposition_last_of_contract = 1,
329+
.bc_decomposition_sel = 1,
330+
.bc_decomposition_sel_windows_gt_remaining = 1,
331+
},
332+
});
333+
334+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
335+
336+
trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1); // Mutate to wrong value
337+
EXPECT_THROW_WITH_MESSAGE(
338+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
339+
"SEL_WINDOWS_GT_REMAINING_PROPAGATION");
340+
}
341+
259342
TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadNoCorrection)
260343
{
261344
TestTraceContainer trace = TestTraceContainer::from_rows({
262345
{
263346
.bc_decomposition_bytes_remaining = 75,
264-
.bc_decomposition_bytes_to_read = tracegen::DECOMPOSE_WINDOW_SIZE,
347+
.bc_decomposition_bytes_to_read = DECOMPOSE_WINDOW_SIZE,
265348
.bc_decomposition_sel = 1,
266349
},
267350
});
268351

269-
check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_OVERFLOW_CORRECTION_VALUE);
352+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
270353
trace.set(C::bc_decomposition_bytes_to_read, 0, 75); // Mutate to wrong value (bytes_remaining)
271-
EXPECT_THROW_WITH_MESSAGE(
272-
check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_OVERFLOW_CORRECTION_VALUE),
273-
"BC_DEC_OVERFLOW_CORRECTION_VALUE");
354+
EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ),
355+
"SET_BYTES_TO_READ");
274356
}
275357

276358
TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadWithCorrection)
@@ -280,16 +362,14 @@ TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadWithCorrecti
280362
.bc_decomposition_bytes_remaining = 13,
281363
.bc_decomposition_bytes_to_read = 13,
282364
.bc_decomposition_sel = 1,
283-
.bc_decomposition_sel_overflow_correction_needed = 1,
365+
.bc_decomposition_sel_windows_gt_remaining = 1,
284366
},
285367
});
286368

287-
check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_OVERFLOW_CORRECTION_VALUE);
288-
trace.set(
289-
C::bc_decomposition_bytes_to_read, 0, tracegen::DECOMPOSE_WINDOW_SIZE); // Mutate to wrong value (WINDOWS_SIZE)
290-
EXPECT_THROW_WITH_MESSAGE(
291-
check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_OVERFLOW_CORRECTION_VALUE),
292-
"BC_DEC_OVERFLOW_CORRECTION_VALUE");
369+
check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
370+
trace.set(C::bc_decomposition_bytes_to_read, 0, DECOMPOSE_WINDOW_SIZE); // Mutate to wrong value
371+
EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ),
372+
"SET_BYTES_TO_READ");
293373
}
294374

295375
TEST(BytecodeDecompositionConstrainingTest, NegativeWrongPacking)

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

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

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ namespace bb::avm2 {
129129

130130
struct AvmFlavorVariables {
131131
static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 133;
132-
static constexpr size_t NUM_WITNESS_ENTITIES = 2924;
133-
static constexpr size_t NUM_SHIFTED_ENTITIES = 315;
132+
static constexpr size_t NUM_WITNESS_ENTITIES = 2919;
133+
static constexpr size_t NUM_SHIFTED_ENTITIES = 316;
134134
static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES;
135-
static constexpr size_t NUM_ALL_ENTITIES = 3372;
135+
static constexpr size_t NUM_ALL_ENTITIES = 3368;
136136

137137
// Need to be templated for recursive verifier
138138
template <typename FF_>
@@ -243,8 +243,6 @@ struct AvmFlavorVariables {
243243
lookup_alu_range_check_trunc_mid_relation<FF_>,
244244
lookup_alu_register_tag_value_relation<FF_>,
245245
lookup_alu_tag_max_bits_value_relation<FF_>,
246-
lookup_bc_decomposition_abs_diff_hi_is_u8_relation<FF_>,
247-
lookup_bc_decomposition_abs_diff_lo_is_u16_relation<FF_>,
248246
lookup_bc_decomposition_bytes_are_bytes_relation<FF_>,
249247
lookup_bc_hashing_get_packed_field_relation<FF_>,
250248
lookup_bc_hashing_iv_is_len_relation<FF_>,

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ template <typename FF_> class bc_decompositionImpl {
1414
public:
1515
using FF = FF_;
1616

17-
static constexpr std::array<size_t, 52> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 4, 4, 5, 3, 4, 4, 3, 3, 4, 2, 4,
18-
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
19-
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
20-
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };
17+
static constexpr std::array<size_t, 54> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 4, 4, 5, 3, 4, 4, 3, 3, 3, 5, 3, 3,
18+
4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
19+
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
20+
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };
2121

2222
template <typename AllEntities> inline static bool skip(const AllEntities& in)
2323
{
@@ -54,13 +54,17 @@ template <typename FF> class bc_decomposition : public Relation<bc_decomposition
5454
return "BC_DEC_BYTES_REMAINING_DECREMENT";
5555
case 8:
5656
return "BC_DEC_ID_CONSTANT";
57-
case 10:
58-
return "BC_DEC_ABS_DIFF";
57+
case 11:
58+
return "IS_WINDOWS_EQ_REMAINING";
5959
case 12:
60-
return "BC_DEC_OVERFLOW_CORRECTION_VALUE";
61-
case 50:
60+
return "SEL_WINDOWS_GT_REMAINING_INIT";
61+
case 13:
62+
return "SEL_WINDOWS_GT_REMAINING_PROPAGATION";
63+
case 14:
64+
return "SET_BYTES_TO_READ";
65+
case 52:
6266
return "SEL_TOGGLED_AT_PACKED";
63-
case 51:
67+
case 53:
6468
return "BC_DECOMPOSITION_REPACKING";
6569
}
6670
return std::to_string(index);
@@ -74,10 +78,12 @@ template <typename FF> class bc_decomposition : public Relation<bc_decomposition
7478
static constexpr size_t SR_BC_DEC_PC_INCREMENT = 6;
7579
static constexpr size_t SR_BC_DEC_BYTES_REMAINING_DECREMENT = 7;
7680
static constexpr size_t SR_BC_DEC_ID_CONSTANT = 8;
77-
static constexpr size_t SR_BC_DEC_ABS_DIFF = 10;
78-
static constexpr size_t SR_BC_DEC_OVERFLOW_CORRECTION_VALUE = 12;
79-
static constexpr size_t SR_SEL_TOGGLED_AT_PACKED = 50;
80-
static constexpr size_t SR_BC_DECOMPOSITION_REPACKING = 51;
81+
static constexpr size_t SR_IS_WINDOWS_EQ_REMAINING = 11;
82+
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_INIT = 12;
83+
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION = 13;
84+
static constexpr size_t SR_SET_BYTES_TO_READ = 14;
85+
static constexpr size_t SR_SEL_TOGGLED_AT_PACKED = 52;
86+
static constexpr size_t SR_BC_DECOMPOSITION_REPACKING = 53;
8187
};
8288

8389
} // namespace bb::avm2

0 commit comments

Comments
 (0)