Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bitwise.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5
18
19// Imports for keccak/sha256 vulnerability exploit tests
36
37namespace bb::avm2::constraining {
38namespace {
39
40using ::testing::Return;
41using ::testing::StrictMock;
42
43using tracegen::BitwiseTraceBuilder;
44using tracegen::ExecutionTraceBuilder;
45using tracegen::KeccakF1600TraceBuilder;
46using tracegen::PrecomputedTraceBuilder;
47using tracegen::Sha256TraceBuilder;
48using tracegen::TestTraceContainer;
49
50using simulation::Bitwise;
51using simulation::BitwiseEvent;
52using simulation::EventEmitter;
53using simulation::FieldGreaterThan;
54using simulation::FieldGreaterThanEvent;
55using simulation::GreaterThan;
56using simulation::GreaterThanEvent;
57using simulation::MemoryStore;
58using simulation::MockExecutionIdManager;
59using simulation::RangeCheck;
60using simulation::RangeCheckEvent;
61using simulation::Sha256;
62using simulation::Sha256CompressionEvent;
63
65using C = Column;
67using keccakf1600 = bb::avm2::keccakf1600<FF>;
68using sha256_relation = bb::avm2::sha256<FF>;
69
70TEST(BitwiseConstrainingTest, EmptyRow)
71{
72 check_relation<bitwise>(testing::empty_trace());
73}
74
75// Testing a positive AND operation for each integral type (U1, U8, ... U128)
76TEST(BitwiseConstrainingTest, AndWithTracegen)
77{
78 TestTraceContainer trace;
79 BitwiseTraceBuilder builder;
81 { .operation = BitwiseOperation::AND,
82 .a = MemoryValue::from(uint1_t(1)),
83 .b = MemoryValue::from(uint1_t(1)),
84 .res = 1 },
85 { .operation = BitwiseOperation::AND,
86 .a = MemoryValue::from<uint8_t>(85),
87 .b = MemoryValue::from<uint8_t>(175),
88 .res = 5 },
89 { .operation = BitwiseOperation::AND,
90 .a = MemoryValue::from<uint16_t>(5323),
91 .b = MemoryValue::from<uint16_t>(321),
92 .res = 65 },
93 { .operation = BitwiseOperation::AND,
94 .a = MemoryValue::from<uint32_t>(13793),
95 .b = MemoryValue::from<uint32_t>(10590617),
96 .res = 4481 },
97 { .operation = BitwiseOperation::AND,
98 .a = MemoryValue::from<uint64_t>(0x7bff744e3cdf79LLU),
99 .b = MemoryValue::from<uint64_t>(0x14ccccccccb6LLU),
100 .res = 0x14444c0ccc30LLU },
101 { .operation = BitwiseOperation::AND,
102 .a = MemoryValue::from<uint128_t>((uint128_t{ 0xb900000000000001 } << 64)),
103 .b = MemoryValue::from<uint128_t>((uint128_t{ 0x1006021301080000 } << 64) +
104 uint128_t{ 0x000000000000001080876844827 }),
105 .res = uint128_t{ 0x1000000000000000 } << 64 }
106 };
107
108 builder.process(events, trace);
109
110 EXPECT_EQ(trace.get_num_rows(), 33); // 33 = 1 + 1 + 1 + 2 + 4 + 8 + 16 (extra_shift_row U1 U8 U16 U32 U64 U128)
111 check_relation<bitwise>(trace);
112}
113
114// Testing a positive OR operation for each integral type (U1, U8, ... U128)
115TEST(BitwiseConstrainingTest, OrWithTracegen)
116{
117 TestTraceContainer trace;
118 BitwiseTraceBuilder builder;
120 { .operation = BitwiseOperation::OR,
121 .a = MemoryValue::from(uint1_t(1)),
122 .b = MemoryValue::from(uint1_t(0)),
123 .res = 1 },
124 { .operation = BitwiseOperation::OR,
125 .a = MemoryValue::from<uint8_t>(128),
126 .b = MemoryValue::from<uint8_t>(127),
127 .res = 255 },
128 { .operation = BitwiseOperation::OR,
129 .a = MemoryValue::from<uint16_t>(5323),
130 .b = MemoryValue::from<uint16_t>(321),
131 .res = 5579 },
132 { .operation = BitwiseOperation::OR,
133 .a = MemoryValue::from<uint32_t>(13793),
134 .b = MemoryValue::from<uint32_t>(10590617),
135 .res = 10599929 },
136 { .operation = BitwiseOperation::OR,
137 .a = MemoryValue::from<uint64_t>(0x7bff744e3cdf79LLU),
138 .b = MemoryValue::from<uint64_t>(0x14ccccccccb6LLU),
139 .res = 0x7bfffccefcdfffLLU },
140 { .operation = BitwiseOperation::OR,
141 .a = MemoryValue::from<uint128_t>((uint128_t{ 0xb900000000000000 } << 64)),
142 .b = MemoryValue::from<uint128_t>((uint128_t{ 0x1006021301080000 } << 64) +
143 uint128_t{ 0x000000000000001080876844827 }),
144 .res = (uint128_t{ 0xb906021301080000 } << 64) + uint128_t{ 0x0001080876844827 } },
145 };
146
147 builder.process(events, trace);
148
149 EXPECT_EQ(trace.get_num_rows(), 33); // 33 = 1 + 1 + 1 + 2 + 4 + 8 + 16 (extra_shift_row U1 U8 U16 U32 U64 U128)
150 check_relation<bitwise>(trace);
151}
152
153// Testing a positive XOR operation for each integral type (U1, U8, ... U128)
154TEST(BitwiseConstrainingTest, XorWithTracegen)
155{
156 TestTraceContainer trace;
157 BitwiseTraceBuilder builder;
158
160 { .operation = BitwiseOperation::XOR,
161 .a = MemoryValue::from(uint1_t(1)),
162 .b = MemoryValue::from(uint1_t(1)),
163 .res = 0 },
164 { .operation = BitwiseOperation::XOR,
165 .a = MemoryValue::from<uint8_t>(85),
166 .b = MemoryValue::from<uint8_t>(175),
167 .res = 250 },
168 { .operation = BitwiseOperation::XOR,
169 .a = MemoryValue::from<uint16_t>(5323),
170 .b = MemoryValue::from<uint16_t>(321),
171 .res = 5514 },
172 { .operation = BitwiseOperation::XOR,
173 .a = MemoryValue::from<uint32_t>(13793),
174 .b = MemoryValue::from<uint32_t>(10590617),
175 .res = 10595448 },
176 { .operation = BitwiseOperation::XOR,
177 .a = MemoryValue::from<uint64_t>(0x7bff744e3cdf79LLU),
178 .b = MemoryValue::from<uint64_t>(0x14ccccccccb6LLU),
179 .res = 0x7bebb882f013cfLLU },
180 { .operation = BitwiseOperation::XOR,
181 .a = MemoryValue::from<uint128_t>((uint128_t{ 0xb900000000000001 } << 64)),
182 .b = MemoryValue::from<uint128_t>((uint128_t{ 0x1006021301080000 } << 64) +
183 uint128_t{ 0x000000000000001080876844827 }),
184 .res = (uint128_t{ 0xa906021301080001 } << 64) + uint128_t{ 0x0001080876844827 } },
185 };
186
187 builder.process(events, trace);
188
189 EXPECT_EQ(trace.get_num_rows(), 33); // 33 = 1 + 1 + 1 + 2 + 4 + 8 + 16 (extra_shift_row U1 U8 U16 U32 U64 U128)
190 check_relation<bitwise>(trace);
191}
192
193TEST(BitwiseConstrainingTest, MixedOperationsWithTracegen)
194{
195 TestTraceContainer trace;
196 BitwiseTraceBuilder builder;
198 { .operation = BitwiseOperation::OR,
199 .a = MemoryValue::from(uint1_t(1)),
200 .b = MemoryValue::from(uint1_t(0)),
201 .res = 1 },
202 { .operation = BitwiseOperation::AND,
203 .a = MemoryValue::from<uint32_t>(13793),
204 .b = MemoryValue::from<uint32_t>(10590617),
205 .res = 4481 },
206 { .operation = BitwiseOperation::XOR,
207 .a = MemoryValue::from<uint16_t>(5323),
208 .b = MemoryValue::from<uint16_t>(321),
209 .res = 5514 },
210 { .operation = BitwiseOperation::XOR,
211 .a = MemoryValue::from<uint32_t>(13793),
212 .b = MemoryValue::from<uint32_t>(10590617),
213 .res = 10595448 },
214 { .operation = BitwiseOperation::AND,
215 .a = MemoryValue::from<uint8_t>(85),
216 .b = MemoryValue::from<uint8_t>(175),
217 .res = 5 },
218 { .operation = BitwiseOperation::AND,
219 .a = MemoryValue::from<uint8_t>(85),
220 .b = MemoryValue::from<uint8_t>(175),
221 .res = 5 },
222 };
223
224 builder.process(events, trace);
225
226 EXPECT_EQ(trace.get_num_rows(), 14); // 14 = 1 + 3 * 1 + 1 * 2 + 2 * 4 (extra_shift_row + 2U1 + 1U8 + 1U16 + 2U32)
227 check_relation<bitwise>(trace);
228}
229
230TEST(BitwiseConstrainingTest, NegativeWrongInit)
231{
232 TestTraceContainer trace({
233 {
234 { C::bitwise_ia_byte, 25 },
235 { C::bitwise_ib_byte, 25 },
236 { C::bitwise_ic_byte, 25 },
237 { C::bitwise_last, 1 },
238 { C::bitwise_acc_ia, 25 },
239 { C::bitwise_acc_ib, 25 },
240 { C::bitwise_acc_ic, 25 },
241 },
242 });
243
245
246 trace.set(C::bitwise_ia_byte, 0, 24); // Mutate to wrong value violating BITW_INIT_A
247 trace.set(C::bitwise_ib_byte, 0, 27); // Mutate to wrong value violating BITW_INIT_B
248 trace.set(C::bitwise_ic_byte, 0, 28); // Mutate to wrong value violating BITW_INIT_C
249
250 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_INIT_A), "BITW_INIT_A");
251 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_INIT_B), "BITW_INIT_B");
252 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_INIT_C), "BITW_INIT_C");
253}
254
255TEST(BitwiseConstrainingTest, NegativeTruncateCtr)
256{
257 TestTraceContainer trace({
258 {
259 { C::bitwise_sel, 1 },
260 { C::bitwise_ctr, 4 },
261 },
262 {
263 { C::bitwise_sel, 1 },
264 { C::bitwise_ctr, 3 },
265 },
266 {
267 { C::bitwise_sel, 1 },
268 { C::bitwise_ctr, 2 },
269 },
270 {
271 { C::bitwise_last, 1 },
272 { C::bitwise_sel, 1 },
273 { C::bitwise_ctr, 1 },
274 },
275 });
276
277 check_relation<bitwise>(trace, bitwise::SR_BITW_CTR_DECREMENT);
278
279 trace.set(C::bitwise_ctr, 3, 0);
280 trace.set(C::bitwise_last, 3, 0);
281 trace.set(C::bitwise_sel, 3, 0);
282
283 // Trace nows ends with bitwise_ctr == 2 without bitwise_last being set.
284 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_CTR_DECREMENT), "BITW_CTR_DECREMENT");
285}
286
287TEST(BitwiseConstrainingTest, NegativeGapCtr)
288{
289 TestTraceContainer trace({
290 {
291 { C::bitwise_sel, 1 },
292 { C::bitwise_ctr, 4 },
293 },
294 {
295 { C::bitwise_last, 1 },
296 { C::bitwise_sel, 1 },
297 { C::bitwise_ctr, 3 },
298 },
299 });
300
301 check_relation<bitwise>(trace, bitwise::SR_BITW_CTR_DECREMENT);
302 trace.set(C::bitwise_ctr, 1, 2); // Mutate to wrong value (ctr decreases from 4 to 2)
303 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_CTR_DECREMENT), "BITW_CTR_DECREMENT");
304}
305
306TEST(BitwiseConstrainingTest, NegativeLastSetBeforeEnd)
307{
308 TestTraceContainer trace({
309 {
310 { C::bitwise_ctr_min_one_inv, FF(7).invert() },
311 { C::bitwise_sel, 1 },
312 { C::bitwise_ctr, 8 },
313 },
314 {
315 { C::bitwise_ctr_min_one_inv, FF(6).invert() },
316 { C::bitwise_sel, 1 },
317 { C::bitwise_ctr, 7 },
318
319 },
320 {
321 { C::bitwise_ctr_min_one_inv, FF(5).invert() },
322 { C::bitwise_sel, 1 },
323 { C::bitwise_ctr, 6 },
324 },
325 });
326
327 check_relation<bitwise>(trace, bitwise::SR_BITW_LAST_FOR_CTR_ONE);
328 trace.set(C::bitwise_last, 2, 1); // Mutate to wrong value (wrongly activate bitwise_last on last row)
329 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_LAST_FOR_CTR_ONE),
330 "BITW_LAST_FOR_CTR_ONE");
331}
332
333TEST(BitwiseConstrainingTest, NegativeDeactivateRow)
334{
335 TestTraceContainer trace({
336 {
337 { C::bitwise_ctr_inv, FF(8).invert() },
338 { C::bitwise_sel, 1 },
339 { C::bitwise_ctr, 8 },
340 },
341 {
342 { C::bitwise_ctr_inv, FF(7).invert() },
343 { C::bitwise_sel, 1 },
344 { C::bitwise_ctr, 7 },
345 },
346 {
347 { C::bitwise_ctr_inv, FF(6).invert() },
348 { C::bitwise_sel, 1 },
349 { C::bitwise_ctr, 6 },
350 },
351 });
352
353 check_relation<bitwise>(trace, bitwise::SR_BITW_SEL_CTR_NON_ZERO);
354 trace.set(C::bitwise_sel, 1, 0); // Mutate to wrong value
355 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_SEL_CTR_NON_ZERO),
356 "BITW_SEL_CTR_NON_ZERO");
357}
358
359TEST(BitwiseConstrainingTest, NegativeChangeOpIDBeforeEnd)
360{
361 TestTraceContainer trace({
362 {
363 { C::bitwise_op_id, static_cast<uint8_t>(BitwiseOperation::XOR) },
364 },
365 {
366 { C::bitwise_op_id, static_cast<uint8_t>(BitwiseOperation::XOR) },
367 },
368 {
369 { C::bitwise_last, 1 },
370 { C::bitwise_op_id, static_cast<uint8_t>(BitwiseOperation::XOR) },
371 },
372 });
373
374 check_relation<bitwise>(trace, bitwise::SR_BITW_OP_ID_REL);
375 trace.set(C::bitwise_op_id, 1, static_cast<uint8_t>(BitwiseOperation::AND)); // Mutate to wrong value
376 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_OP_ID_REL), "BITW_OP_ID_REL");
377}
378
379TEST(BitwiseConstrainingTest, NegativeWrongAccumulation)
380{
381 TestTraceContainer trace({
382 {
383 { C::bitwise_ia_byte, 0x11 },
384 { C::bitwise_ib_byte, 0x22 },
385 { C::bitwise_ic_byte, 0x33 },
386 { C::bitwise_acc_ia, 0xaa11 },
387 { C::bitwise_acc_ib, 0xbb22 },
388 { C::bitwise_acc_ic, 0xcc33 },
389 },
390 {
391 { C::bitwise_last, 1 },
392 { C::bitwise_acc_ia, 0xaa },
393 { C::bitwise_acc_ib, 0xbb },
394 { C::bitwise_acc_ic, 0xcc },
395 },
396 });
397
399
400 trace.set(C::bitwise_acc_ia, 0, 0xaa1f); // Mutate to wrong value violating BITW_ACC_REL_A
401 trace.set(C::bitwise_acc_ib, 0, 0xbb2f); // Mutate to wrong value violating BITW_ACC_REL_B
402 trace.set(C::bitwise_acc_ic, 0, 0xcc3f); // Mutate to wrong value violating BITW_ACC_REL_C
403
404 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_ACC_REL_A), "BITW_ACC_REL_A");
405 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_ACC_REL_B), "BITW_ACC_REL_B");
406 EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, bitwise::SR_BITW_ACC_REL_C), "BITW_ACC_REL_C");
407}
408
409TEST(BitwiseConstrainingTest, MixedOperationsInteractions)
410{
411 TestTraceContainer trace;
412 BitwiseTraceBuilder builder;
413 PrecomputedTraceBuilder precomputed_builder;
415 { .operation = BitwiseOperation::OR,
416 .a = MemoryValue::from(uint1_t(1)),
417 .b = MemoryValue::from(uint1_t(0)),
418 .res = 1 },
419 { .operation = BitwiseOperation::AND,
420 .a = MemoryValue::from<uint32_t>(13793),
421 .b = MemoryValue::from<uint32_t>(10590617),
422 .res = 4481 },
423 { .operation = BitwiseOperation::XOR,
424 .a = MemoryValue::from<uint16_t>(5323),
425 .b = MemoryValue::from<uint16_t>(321),
426 .res = 5514 },
427 { .operation = BitwiseOperation::XOR,
428 .a = MemoryValue::from<uint32_t>(13793),
429 .b = MemoryValue::from<uint32_t>(10590617),
430 .res = 10595448 },
431 { .operation = BitwiseOperation::AND,
432 .a = MemoryValue::from<uint8_t>(85),
433 .b = MemoryValue::from<uint8_t>(175),
434 .res = 5 },
435 { .operation = BitwiseOperation::AND,
436 .a = MemoryValue::from<uint8_t>(85),
437 .b = MemoryValue::from<uint8_t>(175),
438 .res = 5 },
439 };
440
441 builder.process(events, trace);
442
447
448 check_all_interactions<BitwiseTraceBuilder>(trace);
449 check_relation<bitwise>(trace);
450}
451
452TEST(BitwiseConstrainingTest, BitwiseExecInteraction)
453{
454 TestTraceContainer trace({ {
455 // Bitwise Entry
456 { C::bitwise_err, 1 },
457 { C::bitwise_start, 1 },
458 { C::bitwise_tag_a, static_cast<uint8_t>(MemoryTag::FF) },
459 { C::bitwise_tag_b, static_cast<uint8_t>(MemoryTag::U8) },
460 { C::bitwise_acc_ia, 0x01 },
461 { C::bitwise_tag_c, static_cast<uint8_t>(MemoryTag::U8) },
462 { C::bitwise_acc_ib, 0x01 },
463 { C::bitwise_acc_ic, 0x00 },
464 // Execution Entry
465 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(MemoryTag::FF) },
466 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(MemoryTag::U8) },
467 { C::bitwise_op_id, static_cast<uint8_t>(BitwiseOperation::AND) },
468 { C::execution_mem_tag_reg_2_, static_cast<uint8_t>(MemoryTag::U8) },
469 { C::execution_register_0_, 0x01 },
470 { C::execution_register_1_, 0x01 },
471 { C::execution_register_2_, 0x00 },
472 { C::execution_sel_exec_dispatch_bitwise, 1 },
473 { C::execution_sel_opcode_error, 1 },
474 { C::execution_subtrace_operation_id, static_cast<uint8_t>(BitwiseOperation::AND) },
475 } });
476
477 check_interaction<ExecutionTraceBuilder, lookup_execution_dispatch_to_bitwise_settings>(trace);
478}
479
480TEST(BitwiseConstrainingTest, InvalidBitwiseExecInteraction)
481{
482 TestTraceContainer trace({ {
483 // Bitwise Entry
484 { C::bitwise_sel, 1 },
485 { C::bitwise_acc_ib, 0x01 },
486 { C::bitwise_acc_ia, 0x01 },
487 { C::bitwise_tag_a, static_cast<uint8_t>(MemoryTag::U8) },
488 { C::bitwise_tag_b, static_cast<uint8_t>(MemoryTag::U8) },
489 { C::bitwise_acc_ic, 0x00 },
490 { C::bitwise_tag_c, static_cast<uint8_t>(MemoryTag::U8) },
491 { C::bitwise_op_id, static_cast<uint8_t>(BitwiseOperation::AND) },
492
493 // Execution Entry
494 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(MemoryTag::U8) },
495 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(MemoryTag::U16) }, // Mismatch
496 { C::execution_mem_tag_reg_2_, static_cast<uint8_t>(MemoryTag::U8) },
497 { C::execution_register_0_, 0x01 },
498 { C::execution_register_1_, 0x01 },
499 { C::execution_register_2_, 0x00 },
500 { C::execution_sel_exec_dispatch_bitwise, 1 },
501 { C::execution_subtrace_operation_id, static_cast<uint8_t>(BitwiseOperation::AND) },
502 } });
503
505 (check_interaction<ExecutionTraceBuilder, lookup_execution_dispatch_to_bitwise_settings>(trace)),
506 "Failed.*EXECUTION_DISPATCH_TO_BITWISE. Could not find tuple in destination.");
507}
508
509TEST(BitwiseConstrainingTest, ErrorHandlingInputFF)
510{
511 TestTraceContainer trace;
512 BitwiseTraceBuilder builder;
513 PrecomputedTraceBuilder precomputed_builder;
514
516 { .operation = BitwiseOperation::XOR,
519 .res = 0 },
520 };
521 builder.process(events, trace);
524
525 check_relation<bitwise>(trace);
526}
527
528TEST(BitwiseConstrainingTest, ErrorHandlingInputTagMismatch)
529{
530 TestTraceContainer trace;
531 BitwiseTraceBuilder builder;
532
534 { .operation = BitwiseOperation::AND,
537 .res = 0 },
538 };
539 builder.process(events, trace);
540
541 check_relation<bitwise>(trace);
542 check_all_interactions<BitwiseTraceBuilder>(trace);
543}
544
545TEST(BitwiseConstrainingTest, ErrorHandlingMultiple)
546{
547 TestTraceContainer trace;
548 BitwiseTraceBuilder builder;
549
551 { .operation = BitwiseOperation::AND,
554 .res = 0 },
555 };
556 builder.process(events, trace);
557
558 check_relation<bitwise>(trace);
559}
560
561TEST(BitwiseConstrainingTest, ExecBitwiseDispatchOnErrorMismatch)
562{
563 // Bitwise operations on mismatch tags should error out and produce FF(0) result.
566
567 TestTraceContainer trace({ {
568 // Execution Entry
569 { C::execution_sel_exec_dispatch_bitwise, 1 },
570 { C::execution_subtrace_operation_id, static_cast<uint8_t>(BitwiseOperation::AND) },
571 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(a.get_tag()) },
572 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(b.get_tag()) },
573 { C::execution_register_0_, a.as_ff() },
574 { C::execution_register_1_, b.as_ff() },
575
576 // Output is FF(0) due to error
577 { C::execution_mem_tag_reg_2_, static_cast<uint8_t>(MemoryTag::FF) },
578 { C::execution_register_2_, 0x00 },
579 { C::execution_sel_opcode_error, 1 },
580 } });
581
582 std::vector<simulation::BitwiseEvent> event = { { .operation = BitwiseOperation::AND, .a = a, .b = b, .res = 0 } };
583
584 BitwiseTraceBuilder builder;
585 builder.process(event, trace);
586
587 check_relation<bitwise>(trace);
588 check_interaction<ExecutionTraceBuilder, lookup_execution_dispatch_to_bitwise_settings>(trace);
589}
590
591TEST(BitwiseConstrainingTest, ExecBitwiseDispatchOnErrorFF)
592{
593 // Bitwise operations on FF tags should error out and produce FF(0) result.
594 MemoryValue a =
595 MemoryValue::from_tag(MemoryTag::FF, FF("0x1b7f6afaafbe72d6c3fc1bc92828a395341af3d33f805af83f06cbf0dcaca8a9"));
596 MemoryValue b = MemoryValue::from_tag(MemoryTag::U64, 9873803468411284649ULL);
597
598 TestTraceContainer trace({ {
599 // Execution Entry
600 { C::execution_sel_exec_dispatch_bitwise, 1 },
601 { C::execution_subtrace_operation_id, static_cast<uint8_t>(BitwiseOperation::OR) },
602 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(a.get_tag()) },
603 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(b.get_tag()) },
604 { C::execution_register_0_, a.as_ff() },
605 { C::execution_register_1_, b.as_ff() },
606
607 // Output is FF(0) due to error
608 { C::execution_mem_tag_reg_2_, static_cast<uint8_t>(MemoryTag::FF) },
609 { C::execution_register_2_, 0x00 },
610 { C::execution_sel_opcode_error, 1 },
611 } });
612
613 std::vector<simulation::BitwiseEvent> event = { { .operation = BitwiseOperation::OR, .a = a, .b = b, .res = 0 } };
614
615 BitwiseTraceBuilder builder;
616 builder.process(event, trace);
617
618 check_relation<bitwise>(trace);
619 check_interaction<ExecutionTraceBuilder, lookup_execution_dispatch_to_bitwise_settings>(trace);
620}
621
623// Vulnerability Tests: Missing start * (1 - sel) = 0 constraint
625
626// This test demonstrates a SECURITY VULNERABILITY in bitwise.pil:
627// The `start_keccak` selector is not protected to only be active when `sel == 1`.
628// A malicious prover can set start_keccak=1 on inactive rows (sel=0) and claim
629// arbitrary XOR/AND results, bypassing all bitwise constraints.
630//
631// The fix is to add:
632// #[BITW_START_ONLY_WHEN_SEL]
633// (start_keccak + start_sha256) * (1 - sel) = 0;
634//
635// This is the same vulnerability class as poseidon2_hash.pil (fixed in that file).
636TEST(BitwiseConstrainingTest, VulnerabilityStartKeccakWithoutSel)
637{
638 // Create a ghost row where start_keccak=1 but sel=0.
639 // This represents a forged row that a malicious prover could create to
640 // claim: state_in_00 XOR state_in_01 = FAKE_OUTPUT
641 // without actually computing the XOR!
642 FF fake_input_a = FF(0xAAAABBBBCCCCDDDDULL);
643 FF fake_input_b = FF(0x1111222233334444ULL);
644 FF fake_output = FF(0x999999999999ULL); // NOT the real XOR!
645
646 TestTraceContainer trace({
647 {
648 // Ghost row: sel=0 but start_keccak=1 should be INVALID
649 // However, all relation checks pass because they're conditioned on sel
650 { C::bitwise_sel, 0 },
651 { C::bitwise_start, 1 },
652 { C::bitwise_start_keccak, 1 },
653 // Error handling: trigger tag mismatch to get err=1, last=1
654 // This avoids the #[INTEGRAL_TAG_LENGTH] lookup (sel_get_ctr=start*(1-err)=0)
655 { C::bitwise_tag_a, FF(MEM_TAG_U64) }, // U64 = 5
656 { C::bitwise_tag_b, FF(MEM_TAG_U32) }, // != tag_a, triggers mismatch
657 { C::bitwise_sel_tag_mismatch_err, 1 },
658 { C::bitwise_sel_tag_ff_err, 0 },
659 { C::bitwise_err, 1 },
660 { C::bitwise_last, 1 },
661 { C::bitwise_sel_get_ctr, 0 }, // start*(1-err) = 1*0 = 0
662 { C::bitwise_ctr, 0 },
663 // Inverses for tag check constraints
664 { C::bitwise_tag_a_inv, FF(MEM_TAG_U64).invert() },
665 { C::bitwise_tag_ab_diff_inv, FF(MEM_TAG_U64 - MEM_TAG_U32).invert() },
666 // FAKE XOR computation - not constrained when sel=0!
667 { C::bitwise_op_id, FF(AVM_BITWISE_XOR_OP_ID) },
668 { C::bitwise_acc_ia, fake_input_a },
669 { C::bitwise_acc_ib, fake_input_b },
670 { C::bitwise_acc_ic, fake_output }, // FAKE output!
671 // INIT constraints require acc_* = *_byte when last=1
672 { C::bitwise_ia_byte, fake_input_a },
673 { C::bitwise_ib_byte, fake_input_b },
674 { C::bitwise_ic_byte, fake_output },
675 // tag_c unconstrained when err=1 (RES_TAG_SHOULD_MATCH_INPUT gated by (1-err))
676 { C::bitwise_tag_c, 0 },
677 },
678 });
679
680 // VULNERABILITY DEMONSTRATION:
681 // All bitwise relation checks PASS even though this row has:
682 // - start_keccak=1 (would be matched by keccak XOR lookups using bitwise.start_keccak as destination)
683 // - Arbitrary acc_ic (fake XOR output, not enforced because sel=0 skips #[BYTE_OPERATIONS])
684 //
685 // This allows a prover to claim any XOR result for keccak permutation computations!
686 // check_relation<bitwise>(trace) should pass if the vulnerability is not fixed.
687
688 // Now that the vulnerability is fixed, we expect an error:
689 EXPECT_THROW_WITH_MESSAGE((check_relation<bitwise>(trace)), "BITW_START_ONLY_WHEN_SEL");
690}
691
692// Same vulnerability but for start_sha256 (used by SHA256 compression lookups).
693TEST(BitwiseConstrainingTest, VulnerabilityStartSha256WithoutSel)
694{
695 FF fake_input_a = FF(0xAABBCCDD);
696 FF fake_input_b = FF(0x11223344);
697 FF fake_output = FF(0x99999999); // NOT the real XOR!
698
699 TestTraceContainer trace({
700 {
701 { C::bitwise_sel, 0 },
702 { C::bitwise_start, 1 },
703 { C::bitwise_start_sha256, 1 },
704 { C::bitwise_tag_a, FF(MEM_TAG_U32) }, // SHA256 uses U32
705 { C::bitwise_tag_b, FF(MEM_TAG_U8) }, // != tag_a, triggers mismatch
706 { C::bitwise_sel_tag_mismatch_err, 1 },
707 { C::bitwise_sel_tag_ff_err, 0 },
708 { C::bitwise_err, 1 },
709 { C::bitwise_last, 1 },
710 { C::bitwise_sel_get_ctr, 0 },
711 { C::bitwise_ctr, 0 },
712 { C::bitwise_tag_a_inv, FF(MEM_TAG_U32).invert() },
713 { C::bitwise_tag_ab_diff_inv, FF(MEM_TAG_U32 - MEM_TAG_U8).invert() },
714 { C::bitwise_op_id, FF(AVM_BITWISE_XOR_OP_ID) },
715 { C::bitwise_acc_ia, fake_input_a },
716 { C::bitwise_acc_ib, fake_input_b },
717 { C::bitwise_acc_ic, fake_output },
718 { C::bitwise_ia_byte, fake_input_a },
719 { C::bitwise_ib_byte, fake_input_b },
720 { C::bitwise_ic_byte, fake_output },
721 { C::bitwise_tag_c, 0 },
722 },
723 });
724
725 // Now that the vulnerability is fixed, we expect an error:
726 EXPECT_THROW_WITH_MESSAGE((check_relation<bitwise>(trace)), "BITW_START_ONLY_WHEN_SEL");
727}
728
729// This test demonstrates a full exploit: forging a keccak XOR result.
730// It generates a valid keccak trace, mutates an intermediate XOR output to a fake value,
731// and adds a ghost row in bitwise to satisfy the lookup.
732// Both source (keccak) and destination (bitwise) pass check_relation, and the exploited
733// lookup passes check_interaction.
734TEST(BitwiseConstrainingTest, VulnerabilityFakeKeccakXorOutput)
735{
736 // =========================================================================
737 // STEP 1: Generate a valid keccak + bitwise trace
738 // =========================================================================
739 TestTraceContainer trace;
740 const MemoryAddress src_addr = 0;
741 const MemoryAddress dst_addr = 200;
742 testing::generate_keccak_trace(trace, { dst_addr }, { src_addr }, /*space_id=*/23);
743
744 // =========================================================================
745 // STEP 2: Verify the trace is valid before attack
746 // =========================================================================
747 check_relation<keccakf1600>(trace);
748 check_relation<bitwise>(trace);
749
750 // =========================================================================
751 // STEP 3: Find the keccak start row and read the real intermediate values
752 // =========================================================================
753 uint32_t keccak_start_row = 0;
754 for (uint32_t i = 0; i < trace.get_num_rows(); i++) {
755 if (trace.get(C::keccakf1600_start, i) == FF(1)) {
756 keccak_start_row = i;
757 break;
758 }
759 }
760 ASSERT_EQ(trace.get(C::keccakf1600_start, keccak_start_row), FF(1));
761 ASSERT_EQ(trace.get(C::keccakf1600_sel_no_error, keccak_start_row), FF(1));
762
763 FF real_state_in_00 = trace.get(C::keccakf1600_state_in_00, keccak_start_row);
764 FF real_state_in_01 = trace.get(C::keccakf1600_state_in_01, keccak_start_row);
765 FF real_theta_xor_01 = trace.get(C::keccakf1600_theta_xor_01, keccak_start_row);
766
767 // =========================================================================
768 // STEP 4: ATTACK - Mutate theta_xor_01 to a FAKE value
769 // =========================================================================
770 // theta_xor_01 is a committed column only constrained by the THETA_XOR_01 lookup.
771 // No PIL relation directly enforces theta_xor_01 = state_in_00 XOR state_in_01.
772 FF fake_theta_xor_01 = FF(0xFA0E0BAD0DEADULL);
773 ASSERT_NE(fake_theta_xor_01, real_theta_xor_01);
774 trace.set(C::keccakf1600_theta_xor_01, keccak_start_row, fake_theta_xor_01);
775
776 // =========================================================================
777 // STEP 5: Add FORGED ghost row in bitwise to satisfy the lookup
778 // =========================================================================
779 uint32_t forged_row = trace.get_num_rows();
780 trace.set(forged_row,
781 { {
782 { C::bitwise_sel, 0 }, // INACTIVE — constraints don't apply!
783 { C::bitwise_start, 1 }, // But can be matched by keccak lookup!
784 { C::bitwise_start_keccak, 1 }, // Destination selector for keccak XOR lookups
785 { C::bitwise_op_id, FF(AVM_BITWISE_XOR_OP_ID) },
786 { C::bitwise_acc_ia, real_state_in_00 }, // Real input A
787 { C::bitwise_acc_ib, real_state_in_01 }, // Real input B
788 { C::bitwise_acc_ic, fake_theta_xor_01 }, // FAKE output!
789 { C::bitwise_ia_byte, real_state_in_00 },
790 { C::bitwise_ib_byte, real_state_in_01 },
791 { C::bitwise_ic_byte, fake_theta_xor_01 },
792 { C::bitwise_tag_a, FF(MEM_TAG_U64) },
793 { C::bitwise_tag_b, FF(MEM_TAG_U32) }, // != tag_a → mismatch
794 { C::bitwise_sel_tag_mismatch_err, 1 },
795 { C::bitwise_sel_tag_ff_err, 0 },
796 { C::bitwise_err, 1 },
797 { C::bitwise_last, 1 },
798 { C::bitwise_sel_get_ctr, 0 },
799 { C::bitwise_ctr, 0 },
800 { C::bitwise_tag_a_inv, FF(MEM_TAG_U64).invert() },
801 { C::bitwise_tag_ab_diff_inv, FF(MEM_TAG_U64 - MEM_TAG_U32).invert() },
802 { C::bitwise_tag_c, 0 },
803 } });
804
805 // =========================================================================
806 // STEP 6: Verify ALL relations pass
807 // =========================================================================
808 // Keccak relations pass because theta_xor_01 is committed, not relationally constrained
809 check_relation<keccakf1600>(trace);
810 // Bitwise relations pass because ghost row satisfies all constraints with sel=0
811 // Commented out as fixed: check_relation<bitwise>(trace);
812
813 // =========================================================================
814 // STEP 7: Verify the exploited lookup passes
815 // =========================================================================
816 // The THETA_XOR_01 lookup:
817 // Source: sel_no_error { xor_op_id, state_in_00, state_in_01, theta_xor_01, tag_u64 }
818 // Dest: bitwise.start_keccak { op_id, acc_ia, acc_ib, acc_ic, tag_a }
819 //
820 // Source tuple: (2, real_state_in_00, real_state_in_01, FAKE, 5)
821 // Dest tuple: (2, real_state_in_00, real_state_in_01, FAKE, 5) ← ghost row matches!
822 check_interaction<KeccakF1600TraceBuilder, lookup_keccakf1600_theta_xor_01_settings>(trace);
823
824 // =========================================================================
825 // VULNERABILITY DEMONSTRATED: KECCAK XOR FORGERY
826 // =========================================================================
827 // The attacker has successfully proven:
828 // state_in_00 XOR state_in_01 = fake_theta_xor_01
829 //
830 // When the TRUE relationship is:
831 // state_in_00 XOR state_in_01 = real_theta_xor_01
832 //
833 // IMPACT: The keccak permutation is COMPLETELY BROKEN. By forging intermediate
834 // XOR results, an attacker can produce arbitrary keccak hash outputs, breaking
835 // all security guarantees of the hash function.
836
837 // Now that the vulnerability is fixed, we expect an error:
838 EXPECT_THROW_WITH_MESSAGE((check_relation<bitwise>(trace)), "BITW_START_ONLY_WHEN_SEL");
839}
840
841// This test demonstrates a full exploit: forging a SHA256 XOR result.
842// Same vulnerability class as the keccak test but exploiting start_sha256.
843TEST(BitwiseConstrainingTest, VulnerabilityFakeSha256XorOutput)
844{
845 // =========================================================================
846 // STEP 1: Generate a valid SHA256 + bitwise trace
847 // =========================================================================
848 MemoryStore mem;
849 StrictMock<MockExecutionIdManager> execution_id_manager;
850 EXPECT_CALL(execution_id_manager, get_execution_id()).WillRepeatedly(Return(1));
851
852 EventEmitter<BitwiseEvent> bitwise_event_emitter;
853 EventEmitter<GreaterThanEvent> gt_event_emitter;
854 simulation::DeduplicatingEventEmitter<FieldGreaterThanEvent> field_gt_event_emitter;
855 EventEmitter<RangeCheckEvent> range_check_event_emitter;
856
858 FieldGreaterThan field_gt(range_check, field_gt_event_emitter);
859 GreaterThan gt(field_gt, range_check, gt_event_emitter);
860 Bitwise bitwise_sim(bitwise_event_emitter);
861
862 EventEmitter<Sha256CompressionEvent> sha256_event_emitter;
863 Sha256 sha256_gadget(execution_id_manager, bitwise_sim, gt, sha256_event_emitter);
864
865 std::array<uint32_t, 8> state = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
866 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
867 MemoryAddress state_addr = 0;
868 for (uint32_t i = 0; i < 8; ++i) {
869 mem.set(state_addr + i, MemoryValue::from<uint32_t>(state[i]));
870 }
871
872 std::array<uint32_t, 16> input = { 0x61626380, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x18 };
873 MemoryAddress input_addr = 8;
874 for (uint32_t i = 0; i < 16; ++i) {
875 mem.set(input_addr + i, MemoryValue::from<uint32_t>(input[i]));
876 }
877 MemoryAddress output_addr = 25;
878
879 sha256_gadget.compression(mem, state_addr, input_addr, output_addr);
880
881 TestTraceContainer trace;
882 trace.set(C::precomputed_first_row, 0, 1);
883
884 Sha256TraceBuilder sha256_builder;
885 sha256_builder.process(sha256_event_emitter.get_events(), trace);
886
887 BitwiseTraceBuilder bitwise_builder;
888 bitwise_builder.process(bitwise_event_emitter.dump_events(), trace);
889
890 // =========================================================================
891 // STEP 2: Verify the trace is valid before attack
892 // =========================================================================
893 check_relation<sha256_relation>(trace);
894 check_relation<bitwise>(trace);
895
896 // =========================================================================
897 // STEP 3: Find a sha256 row with sel_compute_w=1 and read intermediates
898 // =========================================================================
899 uint32_t sha256_row = 0;
900 bool found = false;
901 for (uint32_t i = 0; i < trace.get_num_rows(); i++) {
902 if (trace.get(C::sha256_sel_compute_w, i) == FF(1)) {
903 sha256_row = i;
904 found = true;
905 break;
906 }
907 }
908 ASSERT_TRUE(found) << "Could not find sha256 row with sel_compute_w=1";
909
910 FF real_w_15_rotr_7 = trace.get(C::sha256_w_15_rotr_7, sha256_row);
911 FF real_w_15_rotr_18 = trace.get(C::sha256_w_15_rotr_18, sha256_row);
912 FF real_xor_output = trace.get(C::sha256_w_15_rotr_7_xor_w_15_rotr_18, sha256_row);
913
914 // =========================================================================
915 // STEP 4: ATTACK - Mutate the XOR intermediate to a FAKE value
916 // =========================================================================
917 FF fake_xor_output = FF(0xDEADBEEF);
918 ASSERT_NE(fake_xor_output, real_xor_output);
919 trace.set(C::sha256_w_15_rotr_7_xor_w_15_rotr_18, sha256_row, fake_xor_output);
920
921 // =========================================================================
922 // STEP 5: Add FORGED ghost row in bitwise to satisfy the lookup
923 // =========================================================================
924 uint32_t forged_row = trace.get_num_rows();
925 trace.set(forged_row,
926 { {
927 { C::bitwise_sel, 0 }, // INACTIVE — constraints don't apply!
928 { C::bitwise_start, 1 },
929 { C::bitwise_start_sha256, 1 }, // Destination selector for sha256 lookups
930 { C::bitwise_op_id, FF(AVM_BITWISE_XOR_OP_ID) },
931 { C::bitwise_acc_ia, real_w_15_rotr_7 }, // Real input A
932 { C::bitwise_acc_ib, real_w_15_rotr_18 }, // Real input B
933 { C::bitwise_acc_ic, fake_xor_output }, // FAKE output!
934 { C::bitwise_ia_byte, real_w_15_rotr_7 },
935 { C::bitwise_ib_byte, real_w_15_rotr_18 },
936 { C::bitwise_ic_byte, fake_xor_output },
937 { C::bitwise_tag_a, FF(MEM_TAG_U32) }, // SHA256 uses U32
938 { C::bitwise_tag_b, FF(MEM_TAG_U8) }, // != tag_a → mismatch
939 { C::bitwise_sel_tag_mismatch_err, 1 },
940 { C::bitwise_sel_tag_ff_err, 0 },
941 { C::bitwise_err, 1 },
942 { C::bitwise_last, 1 },
943 { C::bitwise_sel_get_ctr, 0 },
944 { C::bitwise_ctr, 0 },
945 { C::bitwise_tag_a_inv, FF(MEM_TAG_U32).invert() },
946 { C::bitwise_tag_ab_diff_inv, FF(MEM_TAG_U32 - MEM_TAG_U8).invert() },
947 { C::bitwise_tag_c, 0 },
948 } });
949
950 // =========================================================================
951 // STEP 6: Verify ALL relations pass
952 // =========================================================================
953 // SHA256 relations pass because w_15_rotr_7_xor_w_15_rotr_18 is committed,
954 // not relationally constrained
955 check_relation<sha256_relation>(trace);
956 // Bitwise relations pass because ghost row satisfies all constraints with sel=0
957 // Commented out as fixed: check_relation<bitwise>(trace);
958
959 // =========================================================================
960 // STEP 7: Verify the exploited lookup passes
961 // =========================================================================
962 // The W_S_0_XOR_0 lookup:
963 // Source: sel_compute_w { w_15_rotr_7, w_15_rotr_18, w_15_rotr_7_xor_w_15_rotr_18, xor_sel, u32_tag }
964 // Dest: bitwise.start_sha256 { acc_ia, acc_ib, acc_ic, op_id, tag_a }
965 //
966 // Source tuple: (real_rotr_7, real_rotr_18, FAKE, XOR_OP, U32)
967 // Dest tuple: (real_rotr_7, real_rotr_18, FAKE, XOR_OP, U32) ← ghost row matches!
968 //
969 // NOTE: We can't use check_interaction<Sha256TraceBuilder, ...> because Sha256TraceBuilder
970 // registers this lookup with Column::bitwise_sel as the outer destination selector (production
971 // optimization). Our ghost row has sel=0, so it wouldn't be indexed. KeccakF1600TraceBuilder
972 // uses Column::bitwise_start instead, which is why the keccak test can use check_interaction
973 // directly. Here we use bitwise_start to match the keccak pattern.
974 {
975 tracegen::SharedIndexCache cache;
976 tracegen::LookupIntoDynamicTableGeneric<lookup_sha256_w_s_0_xor_0_settings> lookup(cache, C::bitwise_start);
977 lookup.process(trace);
978 }
979
980 // =========================================================================
981 // VULNERABILITY DEMONSTRATED: SHA256 XOR FORGERY
982 // =========================================================================
983 // The attacker has successfully proven a fake XOR result in the SHA256
984 // message schedule computation. By forging intermediate XOR results,
985 // an attacker can produce arbitrary SHA256 compression outputs.
986
987 // Now that the vulnerability is fixed, we expect an error:
988 EXPECT_THROW_WITH_MESSAGE((check_relation<bitwise>(trace)), "BITW_START_ONLY_WHEN_SEL");
989}
990
991} // namespace
992} // namespace bb::avm2::constraining
FieldGreaterThan field_gt
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:193
#define MEM_TAG_U32
#define MEM_TAG_U8
#define AVM_BITWISE_XOR_OP_ID
#define MEM_TAG_U64
static TaggedValue from(T value)
static TaggedValue from_tag(ValueTag tag, FF value)
static constexpr size_t SR_BITW_CTR_DECREMENT
Definition bitwise.hpp:46
static constexpr size_t SR_BITW_LAST_FOR_CTR_ONE
Definition bitwise.hpp:48
static constexpr size_t SR_BITW_OP_ID_REL
Definition bitwise.hpp:45
static constexpr size_t SR_BITW_ACC_REL_C
Definition bitwise.hpp:54
static constexpr size_t SR_BITW_ACC_REL_B
Definition bitwise.hpp:53
static constexpr size_t SR_BITW_ACC_REL_A
Definition bitwise.hpp:52
static constexpr size_t SR_BITW_INIT_C
Definition bitwise.hpp:51
static constexpr size_t SR_BITW_INIT_B
Definition bitwise.hpp:50
static constexpr size_t SR_BITW_INIT_A
Definition bitwise.hpp:49
static constexpr size_t SR_BITW_SEL_CTR_NON_ZERO
Definition bitwise.hpp:47
void set(MemoryAddress index, MemoryValue value) override
void process(const simulation::EventEmitterInterface< simulation::AluEvent >::Container &events, TraceContainer &trace)
Process the ALU events and populate the ALU relevant columns in the trace.
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
EventEmitter< GreaterThanEvent > gt_event_emitter
ExecutionIdManager execution_id_manager
MemoryStore mem
EventEmitter< RangeCheckEvent > range_check_event_emitter
uint32_t dst_addr
RangeCheck range_check
GreaterThan gt
TestTraceContainer trace
FF a
FF b
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
void generate_keccak_trace(TestTraceContainer &trace, const std::vector< MemoryAddress > &dst_addresses, const std::vector< MemoryAddress > &src_addresses, uint16_t space_id)
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
TaggedValue MemoryValue
AvmFlavorSettings::FF FF
Definition field.hpp:10
uint32_t MemoryAddress
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event
unsigned __int128 uint128_t
Definition serialize.hpp:45
Bitwise bitwise
NoopEventEmitter< FieldGreaterThanEvent > field_gt_event_emitter
NoopEventEmitter< BitwiseEvent > bitwise_event_emitter
constexpr field invert() const noexcept