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),
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 check_relation<bc_decomposition>(trace, bc_decomposition::SR_LAST_CONTRACT_BYTES_REM_ONE),
207}
208
209TEST(BytecodeDecompositionConstrainingTest, NegativeDeactivateStart)
210{
211 TestTraceContainer trace({
212 { { C::precomputed_first_row, 1 } },
213 {
214 { C::bc_decomposition_pc, 0 },
215 { C::bc_decomposition_sel, 1 },
216 { C::bc_decomposition_start, 1 },
217 },
218 });
219
220 check_relation<bc_decomposition>(trace, bc_decomposition::SR_START_AFTER_LATCH);
221 trace.set(C::bc_decomposition_start, 1, 0); // Mutate to wrong value
222 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_START_AFTER_LATCH),
224}
225
226TEST(BytecodeDecompositionConstrainingTest, NegativeStartEndNotSel)
227{
228 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } },
229 {
230 { C::bc_decomposition_sel, 1 },
231 { C::bc_decomposition_start, 1 },
232 },
233 {
234 { C::bc_decomposition_last_of_contract, 1 },
235 { C::bc_decomposition_sel, 1 },
236 } });
237
238 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_ON_START_OR_END);
239 trace.set(C::bc_decomposition_sel, 1, 0); // Mutate to wrong value
240 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_ON_START_OR_END),
242 trace.set(C::bc_decomposition_sel, 1, 1);
243 trace.set(C::bc_decomposition_sel, 2, 0); // Mutate to wrong value
244 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_ON_START_OR_END),
246}
247
248TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationFirstRow)
249{
250 TestTraceContainer trace({
251 { { C::precomputed_first_row, 1 } },
252 { { C::bc_decomposition_pc, 0 }, { C::bc_decomposition_sel, 1 }, { C::bc_decomposition_start, 1 } },
253 });
254
255 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION);
256 trace.set(C::bc_decomposition_pc, 1, 7); // Mutate to wrong value
257 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION),
259}
260
261TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationInside)
262{
263 TestTraceContainer trace({
264 { { C::bc_decomposition_last_of_contract, 1 } },
265 { { C::bc_decomposition_pc, 0 }, { C::bc_decomposition_sel, 1 }, { C::bc_decomposition_start, 1 } },
266 });
267
268 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION);
269 trace.set(C::bc_decomposition_pc, 1, 32); // Mutate to wrong value
270 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_ZERO_INITIALIZATION),
272}
273
274TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongIncrement)
275{
276 TestTraceContainer trace({
277 {
278 { C::bc_decomposition_pc, 5 },
279 { C::bc_decomposition_sel, 1 },
280 },
281 {
282 { C::bc_decomposition_pc, 6 },
283 { C::bc_decomposition_sel, 1 },
284 },
285 {
286 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
287 { C::bc_decomposition_pc, 7 },
288 { C::bc_decomposition_sel, 1 },
289 },
290 });
291
292 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_INCREMENTS);
293 trace.set(C::bc_decomposition_pc, 2, 6); // Mutate to wrong value
294 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_INCREMENTS),
296}
297
298TEST(BytecodeDecompositionConstrainingTest, NegativeBytesRemWrongDecrement)
299{
300 TestTraceContainer trace({
301 {
302 { C::bc_decomposition_bytes_remaining, 5 },
303 { C::bc_decomposition_sel, 1 },
304 },
305 {
306 { C::bc_decomposition_bytes_remaining, 4 },
307 { C::bc_decomposition_sel, 1 },
308 },
309 {
310 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
311 { C::bc_decomposition_bytes_remaining, 3 },
312 { C::bc_decomposition_sel, 1 },
313 },
314 });
315
316 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BYTES_REMAINING_DECREMENTS);
317 trace.set(C::bc_decomposition_bytes_remaining, 0, 4); // Mutate to wrong value
318 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_BYTES_REMAINING_DECREMENTS),
320}
321
322TEST(BytecodeDecompositionConstrainingTest, NegativeMutateBytecodeId)
323{
324 TestTraceContainer trace({
325 {
326 { C::bc_decomposition_id, 147 },
327 { C::bc_decomposition_sel, 1 },
328 },
329 {
330 { C::bc_decomposition_id, 147 },
331 { C::bc_decomposition_sel, 1 },
332 },
333 {
334 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
335 { C::bc_decomposition_id, 147 },
336 { C::bc_decomposition_sel, 1 },
337 },
338 });
339
340 check_relation<bc_decomposition>(trace, bc_decomposition::SR_ID_PROPAGATION);
341 trace.set(C::bc_decomposition_id, 2, 77); // Mutate to wrong value
342 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_ID_PROPAGATION),
344}
345
346// Both positive and negative tests for sel_windows_gt_remaining initialization
347TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingInitialization)
348{
349 TestTraceContainer trace({
350 {
351 { C::bc_decomposition_last_of_contract, 1 },
352 { C::bc_decomposition_sel, 1 },
353 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
354 },
355 });
356
357 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT);
358
359 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value
361 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT),
363}
364
365// Both positive and negative tests for sel_windows_gt_remaining propagation without mutation.
366TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagation)
367{
368 TestTraceContainer trace({
369 {
370 { C::bc_decomposition_sel, 1 },
371 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
372 },
373 {
374 { C::bc_decomposition_last_of_contract, 1 },
375 { C::bc_decomposition_sel, 1 },
376 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
377 },
378 });
379
380 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
381
382 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value at the top
384 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
386
387 // Reset to correct value
388 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1);
389
390 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 1, 0); // Mutate to wrong value at the bottom
392 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
394
395 // Test propagattion of 0 instead of 1
396 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to correct value
397 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
398}
399
400// Both positive and negative tests for sel_windows_gt_remaining propagation with mutation.
401TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagationWithMutation)
402{
403 TestTraceContainer trace({
404 {
405 { C::bc_decomposition_sel_windows_eq_remaining, 1 },
406 { C::bc_decomposition_sel, 1 },
407 { C::bc_decomposition_sel_windows_gt_remaining, 0 },
408 },
409 {
410 { C::bc_decomposition_sel, 1 },
411 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
412 },
413 {
414 { C::bc_decomposition_last_of_contract, 1 },
415 { C::bc_decomposition_sel, 1 },
416 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
417 },
418 });
419
420 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
421
422 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1); // Mutate to wrong value
424 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
426}
427
428TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadNoCorrection)
429{
430 TestTraceContainer trace({
431 {
432 { C::bc_decomposition_bytes_to_read, DECOMPOSE_WINDOW_SIZE },
433 { C::bc_decomposition_bytes_remaining, 75 },
434 { C::bc_decomposition_sel, 1 },
435 },
436 });
437
438 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
439 trace.set(C::bc_decomposition_bytes_to_read, 0, 75); // Mutate to wrong value (bytes_remaining)
440 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ),
442}
443
444TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadWithCorrection)
445{
446 TestTraceContainer trace({
447 {
448 { C::bc_decomposition_bytes_to_read, 13 },
449 { C::bc_decomposition_bytes_remaining, 13 },
450 { C::bc_decomposition_sel, 1 },
451 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
452 },
453 });
454
455 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
456 trace.set(C::bc_decomposition_bytes_to_read, 0, DECOMPOSE_WINDOW_SIZE); // Mutate to wrong value
457 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ),
459}
460
461TEST(BytecodeDecompositionConstrainingTest, NegativeWrongPacking)
462{
463 TestTraceContainer trace;
464 trace.set(0,
465 { {
466 { C::bc_decomposition_sel_packed, 1 },
467 { C::bc_decomposition_bytes, 0x12 },
468 { C::bc_decomposition_bytes_pc_plus_1, 0x34 },
469 { C::bc_decomposition_bytes_pc_plus_2, 0x56 },
470 { C::bc_decomposition_bytes_pc_plus_3, 0x78 },
471 { C::bc_decomposition_bytes_pc_plus_4, 0x9A },
472 { C::bc_decomposition_bytes_pc_plus_5, 0xBC },
473 { C::bc_decomposition_bytes_pc_plus_6, 0xDE },
474 { C::bc_decomposition_bytes_pc_plus_7, 0xF0 },
475 { C::bc_decomposition_bytes_pc_plus_8, 0x12 },
476 { C::bc_decomposition_bytes_pc_plus_9, 0x34 },
477 { C::bc_decomposition_bytes_pc_plus_10, 0x56 },
478 { C::bc_decomposition_bytes_pc_plus_11, 0x78 },
479 { C::bc_decomposition_bytes_pc_plus_12, 0x9A },
480 { C::bc_decomposition_bytes_pc_plus_13, 0xBC },
481 { C::bc_decomposition_bytes_pc_plus_14, 0xDE },
482 { C::bc_decomposition_bytes_pc_plus_15, 0xF0 },
483 { C::bc_decomposition_bytes_pc_plus_16, 0x12 },
484 { C::bc_decomposition_bytes_pc_plus_17, 0x34 },
485 { C::bc_decomposition_bytes_pc_plus_18, 0x56 },
486 { C::bc_decomposition_bytes_pc_plus_19, 0x78 },
487 { C::bc_decomposition_bytes_pc_plus_20, 0x9A },
488 { C::bc_decomposition_bytes_pc_plus_21, 0xBC },
489 { C::bc_decomposition_bytes_pc_plus_22, 0xDE },
490 { C::bc_decomposition_bytes_pc_plus_23, 0xF0 },
491 { C::bc_decomposition_bytes_pc_plus_24, 0x12 },
492 { C::bc_decomposition_bytes_pc_plus_25, 0x34 },
493 { C::bc_decomposition_bytes_pc_plus_26, 0x56 },
494 { C::bc_decomposition_bytes_pc_plus_27, 0x78 },
495 { C::bc_decomposition_bytes_pc_plus_28, 0x9A },
496 { C::bc_decomposition_bytes_pc_plus_29, 0xBC },
497 { C::bc_decomposition_bytes_pc_plus_30, 0xDE },
498 { C::bc_decomposition_packed_field,
499 // Note that we have to prepend 0x00 to the packed field to make it 32 bytes long
500 // since the constructor for FF expects 32 bytes.
501 FF("0x00123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE") },
502 } });
503
504 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DECOMPOSITION_REPACKING);
505 trace.set(C::bc_decomposition_bytes_pc_plus_20, 0, 0); // Mutate to wrong value
506 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DECOMPOSITION_REPACKING),
508}
509
510// Negative test where sel_packed == 1 and sel == 0
511TEST(BytecodeDecompositionConstrainingTest, NegativeSelPackedNotSel)
512{
513 TestTraceContainer trace;
514 trace.set(0,
515 { {
516 { C::bc_decomposition_sel_packed, 1 },
517 { C::bc_decomposition_sel, 1 },
518 } });
519
520 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_TOGGLED_AT_PACKED);
521 trace.set(C::bc_decomposition_sel, 0, 0); // Mutate to wrong value
522 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_TOGGLED_AT_PACKED),
524}
525
526// Negative test where sel_packed == 0 at pc = 0
527TEST(BytecodeDecompositionConstrainingTest, NegativeSelPackedInit)
528{
529 TestTraceContainer trace;
530 init_trace(trace);
531 BytecodeTraceBuilder builder;
532
533 builder.process_decomposition(
534 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(10)) } }, trace);
535 set_perm_selectors(trace);
536 check_relation<bc_decomposition>(trace);
537
538 // First bytecode row should be packed:
539 trace.set(C::bc_decomposition_sel_packed, 1, 0); // Mutate to wrong value
540 trace.set(C::bc_decomposition_sel_packed_read_0_, 1, 0);
541 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_PACKED_INIT),
543}
544
545// Negative test where sel_packed == 0 at pc = 31
546TEST(BytecodeDecompositionConstrainingTest, NegativeSelNotPacked)
547{
548 TestTraceContainer trace;
549 init_trace(trace);
550 BytecodeTraceBuilder builder;
551
552 builder.process_decomposition(
553 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
554 set_perm_selectors(trace);
555 check_relation<bc_decomposition>(trace);
556
557 // At row 32, pc = 31 and should be packed:
558 ASSERT_EQ(trace.get(C::bc_decomposition_pc, 32), 31);
559 trace.set(C::bc_decomposition_sel_packed, 32, 0); // Mutate to wrong value
560 trace.set(C::bc_decomposition_sel_packed_read_1_, 32, 0);
561 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED),
563}
564
565// Negative test where sel_packed == 1 at incorrect pc:
566TEST(BytecodeDecompositionConstrainingTest, NegativeSelPacked)
567{
568 TestTraceContainer trace;
569 init_trace(trace);
570 BytecodeTraceBuilder builder;
571
572 builder.process_decomposition(
573 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
574 set_perm_selectors(trace);
575 check_relation<bc_decomposition>(trace);
576
577 // Should only be packed every 31 bytes:
578 trace.set(C::bc_decomposition_sel_packed, 20, 1); // Mutate to wrong value
579 trace.set(C::bc_decomposition_sel_packed_read_0_, 20, 1);
580 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED),
582}
583
584// Negative test where next_packed_pc is set incorrectly:
585TEST(BytecodeDecompositionConstrainingTest, NegativePackedPc)
586{
587 TestTraceContainer trace;
588 init_trace(trace);
589 BytecodeTraceBuilder builder;
590
591 builder.process_decomposition(
592 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(20)) } }, trace);
593 set_perm_selectors(trace);
594 check_relation<bc_decomposition>(trace);
595
596 // Try to claim that when pc = 10, we should have sel_packed = 1:
597 ASSERT_EQ(trace.get(C::bc_decomposition_pc, 11), 10);
598 trace.set(C::bc_decomposition_sel_packed, 11, 1); // Mutate to wrong value
599 trace.set(C::bc_decomposition_sel_packed_read_0_, 11, 1);
600 trace.set(C::bc_decomposition_next_packed_pc, 11, 10);
601 trace.set(C::bc_decomposition_next_packed_pc_min_pc_inv, 11, 0);
602 // Passes main relation...
603 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED);
604 // ...but fails propagation:
605 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_NEXT_PACKED_PC_PROPAGATION),
607 " failed at row 10");
608 // We cannot set every row up to 11, because we force pc = 0 <==> sel_packed = 1, which then increments
609 // next_packed_pc by 31:
610 for (uint32_t i = 2; i < 11; i++) {
611 trace.set(C::bc_decomposition_next_packed_pc, i, 10);
612 trace.set(C::bc_decomposition_next_packed_pc_min_pc_inv, i, FF(10 - i + 1).invert());
613 }
614 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_NEXT_PACKED_PC_PROPAGATION),
616 " failed at row 1");
617}
618
619} // namespace
620} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:224
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 std::string get_subrelation_label(size_t index)
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)
Populate miscellaneous precomputed columns: first_row selector and idx (row index).
void process_sel_range_8(TraceContainer &trace)
Generate a selector column that activates the first 2^8 (256) rows.
const FF & get(Column col, uint32_t row) const
void set(Column col, uint32_t row, const FF &value, bool use_atomic_limbs=false)
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:36
TestTraceContainer empty_trace()
Definition fixtures.cpp:156
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