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_BC_DEC_SEL_BYTES_REM_NON_ZERO);
176 trace.set(C::bc_decomposition_sel, 2, 0); // Mutate to wrong value
178 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_SEL_BYTES_REM_NON_ZERO),
179 "BC_DEC_SEL_BYTES_REM_NON_ZERO");
180}
181
182TEST(BytecodeDecompositionConstrainingTest, NegativeDeactivateLastContract)
183{
184 TestTraceContainer trace({
185 {
186 { C::bc_decomposition_bytes_rem_min_one_inv, FF(2).invert() },
187 { C::bc_decomposition_bytes_remaining, 3 },
188 { C::bc_decomposition_sel, 1 },
189 },
190 {
191 { C::bc_decomposition_bytes_rem_min_one_inv, 1 },
192 { C::bc_decomposition_bytes_remaining, 2 },
193 { C::bc_decomposition_sel, 1 },
194 },
195 {
196 { C::bc_decomposition_bytes_rem_min_one_inv, 0 },
197 { C::bc_decomposition_last_of_contract, 1 },
198 { C::bc_decomposition_bytes_remaining, 1 },
199 { C::bc_decomposition_sel, 1 },
200 },
201 });
202
203 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_LAST_CONTRACT_BYTES_REM_ONE);
204 trace.set(C::bc_decomposition_last_of_contract, 2, 0); // Mutate to wrong value
206 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_LAST_CONTRACT_BYTES_REM_ONE),
207 "BC_DEC_LAST_CONTRACT_BYTES_REM_ONE");
208}
209
210TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationFirstRow)
211{
212 TestTraceContainer trace({
213 { { C::precomputed_first_row, 1 } },
214 {
215 { C::bc_decomposition_pc, 0 },
216 { C::bc_decomposition_sel, 1 },
217 },
218 });
219
220 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION);
221 trace.set(C::bc_decomposition_pc, 1, 7); // Mutate to wrong value
223 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION),
224 "BC_DEC_PC_ZERO_INITIALIZATION");
225}
226
227TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationInside)
228{
229 TestTraceContainer trace({
230 { { C::bc_decomposition_last_of_contract, 1 } },
231 {
232 { C::bc_decomposition_pc, 0 },
233 { C::bc_decomposition_sel, 1 },
234 },
235 });
236
237 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION);
238 trace.set(C::bc_decomposition_pc, 1, 32); // Mutate to wrong value
240 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION),
241 "BC_DEC_PC_ZERO_INITIALIZATION");
242}
243
244TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongIncrement)
245{
246 TestTraceContainer trace({
247 {
248 { C::bc_decomposition_pc, 5 },
249 { C::bc_decomposition_sel, 1 },
250 },
251 {
252 { C::bc_decomposition_pc, 6 },
253 { C::bc_decomposition_sel, 1 },
254 },
255 {
256 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
257 { C::bc_decomposition_pc, 7 },
258 { C::bc_decomposition_sel, 1 },
259 },
260 });
261
262 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_INCREMENT);
263 trace.set(C::bc_decomposition_pc, 2, 6); // Mutate to wrong value
265 "BC_DEC_PC_INCREMENT");
266}
267
268TEST(BytecodeDecompositionConstrainingTest, NegativeBytesRemWrongDecrement)
269{
270 TestTraceContainer trace({
271 {
272 { C::bc_decomposition_bytes_remaining, 5 },
273 { C::bc_decomposition_sel, 1 },
274 },
275 {
276 { C::bc_decomposition_bytes_remaining, 4 },
277 { C::bc_decomposition_sel, 1 },
278 },
279 {
280 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
281 { C::bc_decomposition_bytes_remaining, 3 },
282 { C::bc_decomposition_sel, 1 },
283 },
284 });
285
286 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_BYTES_REMAINING_DECREMENT);
287 trace.set(C::bc_decomposition_bytes_remaining, 0, 4); // Mutate to wrong value
289 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_BYTES_REMAINING_DECREMENT),
290 "BC_DEC_BYTES_REMAINING_DECREMENT");
291}
292
293TEST(BytecodeDecompositionConstrainingTest, NegativeMutateBytecodeId)
294{
295 TestTraceContainer trace({
296 {
297 { C::bc_decomposition_id, 147 },
298 { C::bc_decomposition_sel, 1 },
299 },
300 {
301 { C::bc_decomposition_id, 147 },
302 { C::bc_decomposition_sel, 1 },
303 },
304 {
305 { C::bc_decomposition_last_of_contract, 1 }, // Required otherwise the test passes trivially
306 { C::bc_decomposition_id, 147 },
307 { C::bc_decomposition_sel, 1 },
308 },
309 });
310
311 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_ID_CONSTANT);
312 trace.set(C::bc_decomposition_id, 2, 77); // Mutate to wrong value
314 "BC_DEC_ID_CONSTANT");
315}
316
317// Both positive and negative tests for sel_windows_gt_remaining initialization
318TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingInitialization)
319{
320 TestTraceContainer trace({
321 {
322 { C::bc_decomposition_last_of_contract, 1 },
323 { C::bc_decomposition_sel, 1 },
324 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
325 },
326 });
327
328 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT);
329
330 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value
332 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT),
333 "SEL_WINDOWS_GT_REMAINING_INIT");
334}
335
336// Both positive and negative tests for sel_windows_gt_remaining propagation without mutation.
337TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagation)
338{
339 TestTraceContainer trace({
340 {
341 { C::bc_decomposition_sel, 1 },
342 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
343 },
344 {
345 { C::bc_decomposition_last_of_contract, 1 },
346 { C::bc_decomposition_sel, 1 },
347 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
348 },
349 });
350
351 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
352
353 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value at the top
355 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
356 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
357
358 // Reset to correct value
359 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1);
360
361 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 1, 0); // Mutate to wrong value at the bottom
363 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
364 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
365
366 // Test propagattion of 0 instead of 1
367 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to correct value
368 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
369}
370
371// Both positive and negative tests for sel_windows_gt_remaining propagation with mutation.
372TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagationWithMutation)
373{
374 TestTraceContainer trace({
375 {
376 { C::bc_decomposition_is_windows_eq_remaining, 1 },
377 { C::bc_decomposition_sel, 1 },
378 { C::bc_decomposition_sel_windows_gt_remaining, 0 },
379 },
380 {
381 { C::bc_decomposition_sel, 1 },
382 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
383 },
384 {
385 { C::bc_decomposition_last_of_contract, 1 },
386 { C::bc_decomposition_sel, 1 },
387 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
388 },
389 });
390
391 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
392
393 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1); // Mutate to wrong value
395 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
396 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
397}
398
399TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadNoCorrection)
400{
401 TestTraceContainer trace({
402 {
403 { C::bc_decomposition_bytes_to_read, DECOMPOSE_WINDOW_SIZE },
404 { C::bc_decomposition_bytes_remaining, 75 },
405 { C::bc_decomposition_sel, 1 },
406 },
407 });
408
409 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
410 trace.set(C::bc_decomposition_bytes_to_read, 0, 75); // Mutate to wrong value (bytes_remaining)
412 "SET_BYTES_TO_READ");
413}
414
415TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadWithCorrection)
416{
417 TestTraceContainer trace({
418 {
419 { C::bc_decomposition_bytes_to_read, 13 },
420 { C::bc_decomposition_bytes_remaining, 13 },
421 { C::bc_decomposition_sel, 1 },
422 { C::bc_decomposition_sel_windows_gt_remaining, 1 },
423 },
424 });
425
426 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
427 trace.set(C::bc_decomposition_bytes_to_read, 0, DECOMPOSE_WINDOW_SIZE); // Mutate to wrong value
429 "SET_BYTES_TO_READ");
430}
431
432TEST(BytecodeDecompositionConstrainingTest, NegativeWrongPacking)
433{
434 TestTraceContainer trace;
435 trace.set(0,
436 { {
437 { C::bc_decomposition_sel_packed, 1 },
438 { C::bc_decomposition_bytes, 0x12 },
439 { C::bc_decomposition_bytes_pc_plus_1, 0x34 },
440 { C::bc_decomposition_bytes_pc_plus_2, 0x56 },
441 { C::bc_decomposition_bytes_pc_plus_3, 0x78 },
442 { C::bc_decomposition_bytes_pc_plus_4, 0x9A },
443 { C::bc_decomposition_bytes_pc_plus_5, 0xBC },
444 { C::bc_decomposition_bytes_pc_plus_6, 0xDE },
445 { C::bc_decomposition_bytes_pc_plus_7, 0xF0 },
446 { C::bc_decomposition_bytes_pc_plus_8, 0x12 },
447 { C::bc_decomposition_bytes_pc_plus_9, 0x34 },
448 { C::bc_decomposition_bytes_pc_plus_10, 0x56 },
449 { C::bc_decomposition_bytes_pc_plus_11, 0x78 },
450 { C::bc_decomposition_bytes_pc_plus_12, 0x9A },
451 { C::bc_decomposition_bytes_pc_plus_13, 0xBC },
452 { C::bc_decomposition_bytes_pc_plus_14, 0xDE },
453 { C::bc_decomposition_bytes_pc_plus_15, 0xF0 },
454 { C::bc_decomposition_bytes_pc_plus_16, 0x12 },
455 { C::bc_decomposition_bytes_pc_plus_17, 0x34 },
456 { C::bc_decomposition_bytes_pc_plus_18, 0x56 },
457 { C::bc_decomposition_bytes_pc_plus_19, 0x78 },
458 { C::bc_decomposition_bytes_pc_plus_20, 0x9A },
459 { C::bc_decomposition_bytes_pc_plus_21, 0xBC },
460 { C::bc_decomposition_bytes_pc_plus_22, 0xDE },
461 { C::bc_decomposition_bytes_pc_plus_23, 0xF0 },
462 { C::bc_decomposition_bytes_pc_plus_24, 0x12 },
463 { C::bc_decomposition_bytes_pc_plus_25, 0x34 },
464 { C::bc_decomposition_bytes_pc_plus_26, 0x56 },
465 { C::bc_decomposition_bytes_pc_plus_27, 0x78 },
466 { C::bc_decomposition_bytes_pc_plus_28, 0x9A },
467 { C::bc_decomposition_bytes_pc_plus_29, 0xBC },
468 { C::bc_decomposition_bytes_pc_plus_30, 0xDE },
469 { C::bc_decomposition_packed_field,
470 // Note that we have to prepend 0x00 to the packed field to make it 32 bytes long
471 // since the constructor for FF expects 32 bytes.
472 FF("0x00123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE") },
473 } });
474
475 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DECOMPOSITION_REPACKING);
476 trace.set(C::bc_decomposition_bytes_pc_plus_20, 0, 0); // Mutate to wrong value
478 "BC_DECOMPOSITION_REPACKING");
479}
480
481// Negative test where sel_packed == 1 and sel == 0
482TEST(BytecodeDecompositionConstrainingTest, NegativeSelPackedNotSel)
483{
484 TestTraceContainer trace;
485 trace.set(0,
486 { {
487 { C::bc_decomposition_sel_packed, 1 },
488 { C::bc_decomposition_sel, 1 },
489 } });
490
491 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_TOGGLED_AT_PACKED);
492 trace.set(C::bc_decomposition_sel, 0, 0); // Mutate to wrong value
494 "SEL_TOGGLED_AT_PACKED");
495}
496
497// Negative test where sel_packed == 0 at pc = 0
498TEST(BytecodeDecompositionConstrainingTest, NegativeSelPackedInit)
499{
500 TestTraceContainer trace;
501 init_trace(trace);
502 BytecodeTraceBuilder builder;
503
504 builder.process_decomposition(
505 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(10)) } }, trace);
506 set_perm_selectors(trace);
507 check_relation<bc_decomposition>(trace);
508
509 // First bytecode row should be packed:
510 trace.set(C::bc_decomposition_sel_packed, 1, 0); // Mutate to wrong value
511 trace.set(C::bc_decomposition_sel_packed_read_0_, 1, 0);
513 "SEL_PACKED_INIT");
514}
515
516// Negative test where sel_packed == 0 at pc = 31
517TEST(BytecodeDecompositionConstrainingTest, NegativeSelNotPacked)
518{
519 TestTraceContainer trace;
520 init_trace(trace);
521 BytecodeTraceBuilder builder;
522
523 builder.process_decomposition(
524 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
525 set_perm_selectors(trace);
526 check_relation<bc_decomposition>(trace);
527
528 // At row 32, pc = 31 and should be packed:
529 ASSERT_EQ(trace.get(C::bc_decomposition_pc, 32), 31);
530 trace.set(C::bc_decomposition_sel_packed, 32, 0); // Mutate to wrong value
531 trace.set(C::bc_decomposition_sel_packed_read_1_, 32, 0);
532 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED),
533 "PC_IS_PACKED");
534}
535
536// Negative test where sel_packed == 1 at incorrect pc:
537TEST(BytecodeDecompositionConstrainingTest, NegativeSelPacked)
538{
539 TestTraceContainer trace;
540 init_trace(trace);
541 BytecodeTraceBuilder builder;
542
543 builder.process_decomposition(
544 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
545 set_perm_selectors(trace);
546 check_relation<bc_decomposition>(trace);
547
548 // Should only be packed every 31 bytes:
549 trace.set(C::bc_decomposition_sel_packed, 20, 1); // Mutate to wrong value
550 trace.set(C::bc_decomposition_sel_packed_read_0_, 20, 1);
551 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED),
552 "PC_IS_PACKED");
553}
554
555// Negative test where next_packed_pc is set incorrectly:
556TEST(BytecodeDecompositionConstrainingTest, NegativePackedPc)
557{
558 TestTraceContainer trace;
559 init_trace(trace);
560 BytecodeTraceBuilder builder;
561
562 builder.process_decomposition(
563 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(20)) } }, trace);
564 set_perm_selectors(trace);
565 check_relation<bc_decomposition>(trace);
566
567 // Try to claim that when pc = 10, we should have sel_packed = 1:
568 ASSERT_EQ(trace.get(C::bc_decomposition_pc, 11), 10);
569 trace.set(C::bc_decomposition_sel_packed, 11, 1); // Mutate to wrong value
570 trace.set(C::bc_decomposition_sel_packed_read_0_, 11, 1);
571 trace.set(C::bc_decomposition_next_packed_pc, 11, 10);
572 trace.set(C::bc_decomposition_next_packed_pc_min_pc_inv, 11, 0);
573 // Passes main relation...
574 check_relation<bc_decomposition>(trace, bc_decomposition::SR_PC_IS_PACKED);
575 // ...but fails propagation:
577 "NEXT_PACKED_PC_PROPAGATION failed at row 10");
578 // We cannot set every row up to 11, because we force pc = 0 <==> sel_packed = 1, which then increments
579 // next_packed_pc by 31:
580 for (uint32_t i = 2; i < 11; i++) {
581 trace.set(C::bc_decomposition_next_packed_pc, i, 10);
582 trace.set(C::bc_decomposition_next_packed_pc_min_pc_inv, i, FF(10 - i + 1).invert());
583 }
585 "NEXT_PACKED_PC_PROPAGATION failed at row 1");
586}
587
588} // namespace
589} // namespace bb::avm2::constraining
static constexpr size_t SR_NEXT_PACKED_PC_PROPAGATION
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_BC_DEC_LAST_CONTRACT_BYTES_REM_ONE
static constexpr size_t SR_SEL_PACKED_INIT
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION
static constexpr size_t SR_BC_DEC_PC_INCREMENT
static constexpr size_t SR_BC_DEC_SEL_BYTES_REM_NON_ZERO
static constexpr size_t SR_BC_DEC_PC_ZERO_INITIALIZATION
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_INIT
static constexpr size_t SR_BC_DEC_ID_CONSTANT
static constexpr size_t SR_BC_DEC_BYTES_REMAINING_DECREMENT
static constexpr size_t SR_SET_BYTES_TO_READ
void process_misc(TraceContainer &trace, const uint32_t num_rows=MAX_AVM_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:119
AluTraceBuilder builder
Definition alu.test.cpp:123
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:402
std::vector< uint8_t > random_bytes(size_t n)
Definition fixtures.cpp:33
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
constexpr uint32_t DECOMPOSE_WINDOW_SIZE
AvmFlavorSettings::FF FF
Definition field.hpp:10
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13