Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bc_decomposition.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5#include <memory>
6#include <vector>
7
20
21namespace bb::avm2::constraining {
22namespace {
23
25using tracegen::BytecodeTraceBuilder;
26using tracegen::PrecomputedTraceBuilder;
27using tracegen::TestTraceContainer;
28
30using C = Column;
31using bc_decomposition = bb::avm2::bc_decomposition<FF>;
32
33void init_trace(TestTraceContainer& trace)
34{
35 // Add first row.
36 trace.set(C::precomputed_first_row, 0, 1);
37}
38
39void set_perm_selectors(TestTraceContainer& trace)
40{
41 // These are normally set by the MultiPermutationBuilder e.g.:
42 // MultiPermutationBuilder<perm_bc_hashing_get_packed_field_0_settings,
43 // perm_bc_hashing_get_packed_field_1_settings,
44 // perm_bc_hashing_get_packed_field_2_settings>
45 // perm_builder(C::bc_decomposition_sel_packed);
46 // perm_builder.process(trace);
47 // ...But since we are only testing decomp (without hashing) in some cases, this helper sets the selectors so we
48 // don't fail:
49 constexpr std::array<C, 3> selectors = { C::bc_decomposition_sel_packed_read_0_,
50 C::bc_decomposition_sel_packed_read_1_,
51 C::bc_decomposition_sel_packed_read_2_ };
52 for (uint32_t r = 0; r < trace.get_num_rows();) {
53 uint32_t bytes_remaining = static_cast<uint32_t>(trace.get(C::bc_decomposition_bytes_remaining, r));
54 for (uint32_t i = r; i < r + bytes_remaining; i += 31) {
55 // Cycle through the permutation selectors for each packed_field:
56 trace.set(i, { { { selectors[((i - r) % 31) % 3], 1 } } });
57 }
58 r += bytes_remaining > 0 ? bytes_remaining : 1;
59 }
60}
61
62TEST(BytecodeDecompositionConstrainingTest, EmptyRow)
63{
64 check_relation<bc_decomposition>(testing::empty_trace());
65}
66
67TEST(BytecodeDecompositionConstrainingTest, SingleBytecode)
68{
69 TestTraceContainer trace;
70 init_trace(trace);
71 BytecodeTraceBuilder builder;
72 PrecomputedTraceBuilder precomputed_builder;
73
74 builder.process_decomposition(
75 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
76
77 EXPECT_EQ(trace.get_num_rows(), 1 + 40);
78
81 set_perm_selectors(trace);
82
83 check_relation<bc_decomposition>(trace);
84 check_interaction<BytecodeTraceBuilder, lookup_bc_decomposition_bytes_are_bytes_settings>(trace);
85}
86
87TEST(BytecodeDecompositionConstrainingTest, ShortSingleBytecode)
88{
89 // Bytecode is shorter than the sliding window.
90 TestTraceContainer trace;
91 init_trace(trace);
92 BytecodeTraceBuilder builder;
93 PrecomputedTraceBuilder precomputed_builder;
94
95 builder.process_decomposition(
96 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(5)) } }, trace);
97
98 EXPECT_EQ(trace.get_num_rows(), 1 + 5);
99
102 set_perm_selectors(trace);
103
104 check_relation<bc_decomposition>(trace);
105 check_interaction<BytecodeTraceBuilder, lookup_bc_decomposition_bytes_are_bytes_settings>(trace);
106}
107
108TEST(BytecodeDecompositionConstrainingTest, MultipleBytecodes)
109{
110 TestTraceContainer trace;
111 init_trace(trace);
112 BytecodeTraceBuilder builder;
113 PrecomputedTraceBuilder precomputed_builder;
114
115 builder.process_decomposition(
116 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) },
117 { .bytecode_id = 2, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(55)) } },
118 trace);
119
120 EXPECT_EQ(trace.get_num_rows(), 1 + 40 + 55);
121
124 set_perm_selectors(trace);
125
126 check_relation<bc_decomposition>(trace);
127 check_interaction<BytecodeTraceBuilder, lookup_bc_decomposition_bytes_are_bytes_settings>(trace);
128}
129
130TEST(BytecodeDecompositionConstrainingTest, MultipleBytecodesWithShortOnes)
131{
132 TestTraceContainer trace;
133 init_trace(trace);
134 BytecodeTraceBuilder builder;
135 PrecomputedTraceBuilder precomputed_builder;
136
137 builder.process_decomposition(
138 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) },
139 { .bytecode_id = 2, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(5)) },
140 { .bytecode_id = 3, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(10)) },
141 { .bytecode_id = 4, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(55)) },
142 { .bytecode_id = 5, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(2)) } },
143 trace);
144
145 EXPECT_EQ(trace.get_num_rows(), 1 + 40 + 5 + 10 + 55 + 2);
146
149 set_perm_selectors(trace);
150
151 check_relation<bc_decomposition>(trace);
152 check_interaction<BytecodeTraceBuilder, lookup_bc_decomposition_bytes_are_bytes_settings>(trace);
153}
154
155TEST(BytecodeDecompositionConstrainingTest, NegativeDeactivatedSel)
156{
157 TestTraceContainer trace({
158 {
159 { C::bc_decomposition_bytes_rem_inv, FF(33).invert() },
160 { C::bc_decomposition_bytes_remaining, 33 },
161 { C::bc_decomposition_sel, 1 },
162 },
163 {
164 { C::bc_decomposition_bytes_rem_inv, FF(32).invert() },
165 { C::bc_decomposition_bytes_remaining, 32 },
166 { C::bc_decomposition_sel, 1 },
167 },
168 {
169 { C::bc_decomposition_bytes_rem_inv, FF(31).invert() },
170 { C::bc_decomposition_bytes_remaining, 31 },
171 { C::bc_decomposition_sel, 1 },
172 },
173 });
174
175 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BYTES_REM_NON_ZERO);
176 trace.set(C::bc_decomposition_sel, 2, 0); // Mutate to wrong value
177 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_BYTES_REM_NON_ZERO),
178 "BYTES_REM_NON_ZERO");
179}
180
181TEST(BytecodeDecompositionConstrainingTest, NegativeDeactivateLastContract)
182{
183 TestTraceContainer trace({
184 {
185 { C::bc_decomposition_bytes_rem_min_one_inv, FF(2).invert() },
186 { C::bc_decomposition_bytes_remaining, 3 },
187 { C::bc_decomposition_sel, 1 },
188 },
189 {
190 { C::bc_decomposition_bytes_rem_min_one_inv, 1 },
191 { C::bc_decomposition_bytes_remaining, 2 },
192 { C::bc_decomposition_sel, 1 },
193 },
194 {
195 { C::bc_decomposition_bytes_rem_min_one_inv, 0 },
196 { C::bc_decomposition_last_of_contract, 1 },
197 { C::bc_decomposition_bytes_remaining, 1 },
198 { C::bc_decomposition_sel, 1 },
199 },
200 });
201
202 check_relation<bc_decomposition>(trace, bc_decomposition::SR_LAST_CONTRACT_BYTES_REM_ONE);
203 trace.set(C::bc_decomposition_last_of_contract, 2, 0); // Mutate to wrong value
205 "LAST_CONTRACT_BYTES_REM_ONE");
206}
207
208TEST(BytecodeDecompositionConstrainingTest, NegativeDeactivateStart)
209{
210 TestTraceContainer trace({
211 { { C::precomputed_first_row, 1 } },
212 {
213 { C::bc_decomposition_pc, 0 },
214 { C::bc_decomposition_sel, 1 },
215 { C::bc_decomposition_start, 1 },
216 },
217 });
218
219 check_relation<bc_decomposition>(trace, bc_decomposition::SR_START_AFTER_LATCH);
220 trace.set(C::bc_decomposition_start, 1, 0); // Mutate to wrong value
221 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_START_AFTER_LATCH),
222 "START_AFTER_LATCH");
223}
224
225TEST(BytecodeDecompositionConstrainingTest, NegativeStartEndNotSel)
226{
227 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } },
228 {
229 { C::bc_decomposition_sel, 1 },
230 { C::bc_decomposition_start, 1 },
231 },
232 {
233 { C::bc_decomposition_last_of_contract, 1 },
234 { C::bc_decomposition_sel, 1 },
235 } });
236
237 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_ON_START_OR_END);
238 trace.set(C::bc_decomposition_sel, 1, 0); // Mutate to wrong value
239 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_ON_START_OR_END),
240 "SEL_ON_START_OR_END");
241 trace.set(C::bc_decomposition_sel, 1, 1);
242 trace.set(C::bc_decomposition_sel, 2, 0); // Mutate to wrong value
243 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_ON_START_OR_END),
244 "SEL_ON_START_OR_END");
245}
246
247TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationFirstRow)
248{
249 TestTraceContainer trace({
250 { { C::precomputed_first_row, 1 } },
251 { { C::bc_decomposition_pc, 0 }, { C::bc_decomposition_sel, 1 }, { C::bc_decomposition_start, 1 } },
252 });
253
254 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION);
255 trace.set(C::bc_decomposition_pc, 1, 7); // Mutate to wrong value
256 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION),
257 "PC_ZERO_INITIALIZATION");
258}
259
260TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationInside)
261{
262 TestTraceContainer trace({
263 { { C::bc_decomposition_last_of_contract, 1 } },
264 { { C::bc_decomposition_pc, 0 }, { C::bc_decomposition_sel, 1 }, { C::bc_decomposition_start, 1 } },
265 });
266
267 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION);
268 trace.set(C::bc_decomposition_pc, 1, 32); // Mutate to wrong value
269 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION),
270 "PC_ZERO_INITIALIZATION");
271}
272
273TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongIncrement)
274{
275 TestTraceContainer trace({
276 {
277 { C::bc_decomposition_pc, 5 },
278 { C::bc_decomposition_sel, 1 },
279 },
280 {
281 { C::bc_decomposition_pc, 6 },
282 { C::bc_decomposition_sel, 1 },
283 },
284 {
285 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
286 { C::bc_decomposition_pc, 7 },
287 { C::bc_decomposition_sel, 1 },
288 },
289 });
290
291 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_INCREMENTS);
292 trace.set(C::bc_decomposition_pc, 2, 6); // Mutate to wrong value
293 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_INCREMENTS),
294 "PC_INCREMENTS");
295}
296
297TEST(BytecodeDecompositionConstrainingTest, NegativeBytesRemWrongDecrement)
298{
299 TestTraceContainer trace({
300 {
301 { C::bc_decomposition_bytes_remaining, 5 },
302 { C::bc_decomposition_sel, 1 },
303 },
304 {
305 { C::bc_decomposition_bytes_remaining, 4 },
306 { C::bc_decomposition_sel, 1 },
307 },
308 {
309 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
310 { C::bc_decomposition_bytes_remaining, 3 },
311 { C::bc_decomposition_sel, 1 },
312 },
313 });
314
315 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BYTES_REMAINING_DECREMENTS);
316 trace.set(C::bc_decomposition_bytes_remaining, 0, 4); // Mutate to wrong value
317 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_BYTES_REMAINING_DECREMENTS),
318 "BYTES_REMAINING_DECREMENTS");
319}
320
321TEST(BytecodeDecompositionConstrainingTest, NegativeMutateBytecodeId)
322{
323 TestTraceContainer trace({
324 {
325 { C::bc_decomposition_id, 147 },
326 { C::bc_decomposition_sel, 1 },
327 },
328 {
329 { C::bc_decomposition_id, 147 },
330 { C::bc_decomposition_sel, 1 },
331 },
332 {
333 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
334 { C::bc_decomposition_id, 147 },
335 { C::bc_decomposition_sel, 1 },
336 },
337 });
338
339 check_relation<bc_decomposition>(trace, bc_decomposition::SR_ID_PROPAGATION);
340 trace.set(C::bc_decomposition_id, 2, 77); // Mutate to wrong value
341 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_ID_PROPAGATION),
342 "ID_PROPAGATION");
343}
344
345// Both positive and negative tests for sel_windows_gt_remaining initialization
346TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingInitialization)
347{
348 TestTraceContainer trace({
349 {
350 { C::bc_decomposition_last_of_contract, 1 },
351 { C::bc_decomposition_sel, 1 },
352 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
353 },
354 });
355
356 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT);
357
358 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value
360 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT),
361 "SEL_WINDOWS_GT_REMAINING_INIT");
362}
363
364// Both positive and negative tests for sel_windows_gt_remaining propagation without mutation.
365TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagation)
366{
367 TestTraceContainer trace({
368 {
369 { C::bc_decomposition_sel, 1 },
370 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
371 },
372 {
373 { C::bc_decomposition_last_of_contract, 1 },
374 { C::bc_decomposition_sel, 1 },
375 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
376 },
377 });
378
379 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
380
381 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value at the top
383 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
384 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
385
386 // Reset to correct value
387 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1);
388
389 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 1, 0); // Mutate to wrong value at the bottom
391 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
392 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
393
394 // Test propagattion of 0 instead of 1
395 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to correct value
396 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
397}
398
399// Both positive and negative tests for sel_windows_gt_remaining propagation with mutation.
400TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagationWithMutation)
401{
402 TestTraceContainer trace({
403 {
404 { C::bc_decomposition_sel_windows_eq_remaining, 1 },
405 { C::bc_decomposition_sel, 1 },
406 { C::bc_decomposition_sel_windows_gt_remaining, 0 },
407 },
408 {
409 { C::bc_decomposition_sel, 1 },
410 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
411 },
412 {
413 { C::bc_decomposition_last_of_contract, 1 },
414 { C::bc_decomposition_sel, 1 },
415 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
416 },
417 });
418
419 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
420
421 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1); // Mutate to wrong value
423 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
424 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
425}
426
427TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadNoCorrection)
428{
429 TestTraceContainer trace({
430 {
431 { C::bc_decomposition_bytes_to_read, DECOMPOSE_WINDOW_SIZE },
432 { C::bc_decomposition_bytes_remaining, 75 },
433 { C::bc_decomposition_sel, 1 },
434 },
435 });
436
437 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
438 trace.set(C::bc_decomposition_bytes_to_read, 0, 75); // Mutate to wrong value (bytes_remaining)
439 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ),
440 "SET_BYTES_TO_READ");
441}
442
443TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadWithCorrection)
444{
445 TestTraceContainer trace({
446 {
447 { C::bc_decomposition_bytes_to_read, 13 },
448 { C::bc_decomposition_bytes_remaining, 13 },
449 { C::bc_decomposition_sel, 1 },
450 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
451 },
452 });
453
454 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
455 trace.set(C::bc_decomposition_bytes_to_read, 0, DECOMPOSE_WINDOW_SIZE); // Mutate to wrong value
456 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ),
457 "SET_BYTES_TO_READ");
458}
459
460TEST(BytecodeDecompositionConstrainingTest, NegativeWrongPacking)
461{
462 TestTraceContainer trace;
463 trace.set(0,
464 { {
465 { C::bc_decomposition_sel_packed, 1 },
466 { C::bc_decomposition_bytes, 0x12 },
467 { C::bc_decomposition_bytes_pc_plus_1, 0x34 },
468 { C::bc_decomposition_bytes_pc_plus_2, 0x56 },
469 { C::bc_decomposition_bytes_pc_plus_3, 0x78 },
470 { C::bc_decomposition_bytes_pc_plus_4, 0x9A },
471 { C::bc_decomposition_bytes_pc_plus_5, 0xBC },
472 { C::bc_decomposition_bytes_pc_plus_6, 0xDE },
473 { C::bc_decomposition_bytes_pc_plus_7, 0xF0 },
474 { C::bc_decomposition_bytes_pc_plus_8, 0x12 },
475 { C::bc_decomposition_bytes_pc_plus_9, 0x34 },
476 { C::bc_decomposition_bytes_pc_plus_10, 0x56 },
477 { C::bc_decomposition_bytes_pc_plus_11, 0x78 },
478 { C::bc_decomposition_bytes_pc_plus_12, 0x9A },
479 { C::bc_decomposition_bytes_pc_plus_13, 0xBC },
480 { C::bc_decomposition_bytes_pc_plus_14, 0xDE },
481 { C::bc_decomposition_bytes_pc_plus_15, 0xF0 },
482 { C::bc_decomposition_bytes_pc_plus_16, 0x12 },
483 { C::bc_decomposition_bytes_pc_plus_17, 0x34 },
484 { C::bc_decomposition_bytes_pc_plus_18, 0x56 },
485 { C::bc_decomposition_bytes_pc_plus_19, 0x78 },
486 { C::bc_decomposition_bytes_pc_plus_20, 0x9A },
487 { C::bc_decomposition_bytes_pc_plus_21, 0xBC },
488 { C::bc_decomposition_bytes_pc_plus_22, 0xDE },
489 { C::bc_decomposition_bytes_pc_plus_23, 0xF0 },
490 { C::bc_decomposition_bytes_pc_plus_24, 0x12 },
491 { C::bc_decomposition_bytes_pc_plus_25, 0x34 },
492 { C::bc_decomposition_bytes_pc_plus_26, 0x56 },
493 { C::bc_decomposition_bytes_pc_plus_27, 0x78 },
494 { C::bc_decomposition_bytes_pc_plus_28, 0x9A },
495 { C::bc_decomposition_bytes_pc_plus_29, 0xBC },
496 { C::bc_decomposition_bytes_pc_plus_30, 0xDE },
497 { C::bc_decomposition_packed_field,
498 // Note that we have to prepend 0x00 to the packed field to make it 32 bytes long
499 // since the constructor for FF expects 32 bytes.
500 FF("0x00123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE") },
501 } });
502
503 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DECOMPOSITION_REPACKING);
504 trace.set(C::bc_decomposition_bytes_pc_plus_20, 0, 0); // Mutate to wrong value
505 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DECOMPOSITION_REPACKING),
506 "BC_DECOMPOSITION_REPACKING");
507}
508
509// Negative test where sel_packed == 1 and sel == 0
510TEST(BytecodeDecompositionConstrainingTest, NegativeSelPackedNotSel)
511{
512 TestTraceContainer trace;
513 trace.set(0,
514 { {
515 { C::bc_decomposition_sel_packed, 1 },
516 { C::bc_decomposition_sel, 1 },
517 } });
518
519 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_TOGGLED_AT_PACKED);
520 trace.set(C::bc_decomposition_sel, 0, 0); // Mutate to wrong value
521 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_TOGGLED_AT_PACKED),
522 "SEL_TOGGLED_AT_PACKED");
523}
524
525// Negative test where sel_packed == 0 at pc = 0
526TEST(BytecodeDecompositionConstrainingTest, NegativeSelPackedInit)
527{
528 TestTraceContainer trace;
529 init_trace(trace);
530 BytecodeTraceBuilder builder;
531
532 builder.process_decomposition(
533 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(10)) } }, trace);
534 set_perm_selectors(trace);
535 check_relation<bc_decomposition>(trace);
536
537 // First bytecode row should be packed:
538 trace.set(C::bc_decomposition_sel_packed, 1, 0); // Mutate to wrong value
539 trace.set(C::bc_decomposition_sel_packed_read_0_, 1, 0);
540 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_PACKED_INIT),
541 "SEL_PACKED_INIT");
542}
543
544// Negative test where sel_packed == 0 at pc = 31
545TEST(BytecodeDecompositionConstrainingTest, NegativeSelNotPacked)
546{
547 TestTraceContainer trace;
548 init_trace(trace);
549 BytecodeTraceBuilder builder;
550
551 builder.process_decomposition(
552 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
553 set_perm_selectors(trace);
554 check_relation<bc_decomposition>(trace);
555
556 // At row 32, pc = 31 and should be packed:
557 ASSERT_EQ(trace.get(C::bc_decomposition_pc, 32), 31);
558 trace.set(C::bc_decomposition_sel_packed, 32, 0); // Mutate to wrong value
559 trace.set(C::bc_decomposition_sel_packed_read_1_, 32, 0);
560 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED),
561 "PC_IS_PACKED");
562}
563
564// Negative test where sel_packed == 1 at incorrect pc:
565TEST(BytecodeDecompositionConstrainingTest, NegativeSelPacked)
566{
567 TestTraceContainer trace;
568 init_trace(trace);
569 BytecodeTraceBuilder builder;
570
571 builder.process_decomposition(
572 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
573 set_perm_selectors(trace);
574 check_relation<bc_decomposition>(trace);
575
576 // Should only be packed every 31 bytes:
577 trace.set(C::bc_decomposition_sel_packed, 20, 1); // Mutate to wrong value
578 trace.set(C::bc_decomposition_sel_packed_read_0_, 20, 1);
579 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED),
580 "PC_IS_PACKED");
581}
582
583// Negative test where next_packed_pc is set incorrectly:
584TEST(BytecodeDecompositionConstrainingTest, NegativePackedPc)
585{
586 TestTraceContainer trace;
587 init_trace(trace);
588 BytecodeTraceBuilder builder;
589
590 builder.process_decomposition(
591 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(20)) } }, trace);
592 set_perm_selectors(trace);
593 check_relation<bc_decomposition>(trace);
594
595 // Try to claim that when pc = 10, we should have sel_packed = 1:
596 ASSERT_EQ(trace.get(C::bc_decomposition_pc, 11), 10);
597 trace.set(C::bc_decomposition_sel_packed, 11, 1); // Mutate to wrong value
598 trace.set(C::bc_decomposition_sel_packed_read_0_, 11, 1);
599 trace.set(C::bc_decomposition_next_packed_pc, 11, 10);
600 trace.set(C::bc_decomposition_next_packed_pc_min_pc_inv, 11, 0);
601 // Passes main relation...
602 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED);
603 // ...but fails propagation:
604 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_NEXT_PACKED_PC_PROPAGATION),
605 "NEXT_PACKED_PC_PROPAGATION failed at row 10");
606 // We cannot set every row up to 11, because we force pc = 0 <==> sel_packed = 1, which then increments
607 // next_packed_pc by 31:
608 for (uint32_t i = 2; i < 11; i++) {
609 trace.set(C::bc_decomposition_next_packed_pc, i, 10);
610 trace.set(C::bc_decomposition_next_packed_pc_min_pc_inv, i, FF(10 - i + 1).invert());
611 }
612 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_NEXT_PACKED_PC_PROPAGATION),
613 "NEXT_PACKED_PC_PROPAGATION failed at row 1");
614}
615
616} // namespace
617} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:193
static constexpr size_t SR_NEXT_PACKED_PC_PROPAGATION
static constexpr size_t SR_PC_ZERO_INITIALIZATION
static constexpr size_t SR_START_AFTER_LATCH
static constexpr size_t SR_SEL_TOGGLED_AT_PACKED
static constexpr size_t SR_PC_IS_PACKED
static constexpr size_t SR_BC_DECOMPOSITION_REPACKING
static constexpr size_t SR_BYTES_REMAINING_DECREMENTS
static constexpr size_t SR_SEL_PACKED_INIT
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION
static constexpr size_t SR_LAST_CONTRACT_BYTES_REM_ONE
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_INIT
static constexpr size_t SR_PC_INCREMENTS
static constexpr size_t SR_BYTES_REM_NON_ZERO
static constexpr size_t SR_SEL_ON_START_OR_END
static constexpr size_t SR_ID_PROPAGATION
static constexpr size_t SR_SET_BYTES_TO_READ
void process_misc(TraceContainer &trace, const uint32_t num_rows=PRECOMPUTED_TRACE_SIZE)
const FF & get(Column col, uint32_t row) const
void set(Column col, uint32_t row, const FF &value)
PrecomputedTraceBuilder precomputed_builder
Definition alu.test.cpp:120
AluTraceBuilder builder
Definition alu.test.cpp:124
TestTraceContainer trace
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
std::vector< uint8_t > random_bytes(size_t n)
Definition fixtures.cpp:33
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr uint32_t DECOMPOSE_WINDOW_SIZE
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13