Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
to_radix.test.cpp
Go to the documentation of this file.
1#include <cstdint>
2#include <gmock/gmock.h>
3#include <gtest/gtest.h>
4
28
29namespace bb::avm2::constraining {
30namespace {
31
32using ::testing::Return;
33using ::testing::StrictMock;
34
35using tracegen::ExecutionTraceBuilder;
36using tracegen::GreaterThanTraceBuilder;
37using tracegen::MemoryTraceBuilder;
38using tracegen::PrecomputedTraceBuilder;
39using tracegen::TestTraceContainer;
40using tracegen::ToRadixTraceBuilder;
41
43using C = Column;
44using to_radix = bb::avm2::to_radix<FF>;
45using to_radix_mem = bb::avm2::to_radix_mem<FF>;
46using ToRadixSimulator = simulation::ToRadix;
47
48using simulation::EventEmitter;
49using simulation::GreaterThan;
50using simulation::GreaterThanEvent;
51using simulation::MockExecutionIdManager;
52using simulation::MockFieldGreaterThan;
53using simulation::NoopEventEmitter;
54using simulation::PureGreaterThan;
55using simulation::RangeCheck;
56using simulation::RangeCheckEvent;
57using simulation::ToRadixEvent;
58using simulation::ToRadixMemoryEvent;
59
60constexpr uint64_t MAX_MEM = AVM_MEMORY_SIZE;
61
62TEST(ToRadixConstrainingTest, EmptyRow)
63{
64 check_relation<to_radix>(testing::empty_trace());
65}
66
67TEST(ToRadixConstrainingTest, ToLeBitsBasicTest)
68{
69 EventEmitter<ToRadixEvent> to_radix_event_emitter;
70 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
71
72 PureGreaterThan gt;
73 StrictMock<MockExecutionIdManager> execution_id_manager;
74 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
75
76 auto [bits, truncated] = to_radix_simulator.to_le_bits(FF::one(), 254);
77
78 EXPECT_EQ(bits.size(), 254);
79 EXPECT_FALSE(truncated);
80
81 TestTraceContainer trace({
82 { { C::precomputed_first_row, 1 } },
83 });
84
85 ToRadixTraceBuilder builder;
86 builder.process(to_radix_event_emitter.dump_events(), trace);
87 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 254);
88 check_relation<to_radix>(trace);
89}
90
91TEST(ToRadixConstrainingTest, ToLeBitsPMinusOne)
92{
93 EventEmitter<ToRadixEvent> to_radix_event_emitter;
94 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
95
96 PureGreaterThan gt;
97 StrictMock<MockExecutionIdManager> execution_id_manager;
98 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
99
100 auto [bits, truncated] = to_radix_simulator.to_le_bits(FF::neg_one(), 254);
101
102 EXPECT_EQ(bits.size(), 254);
103 EXPECT_FALSE(truncated);
104
105 TestTraceContainer trace({
106 { { C::precomputed_first_row, 1 } },
107 });
108
109 ToRadixTraceBuilder builder;
110 builder.process(to_radix_event_emitter.dump_events(), trace);
111 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 254);
112 check_relation<to_radix>(trace);
113}
114
115TEST(ToRadixConstrainingTest, ToLeBitsShortest)
116{
117 EventEmitter<ToRadixEvent> to_radix_event_emitter;
118 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
119
120 PureGreaterThan gt;
121 StrictMock<MockExecutionIdManager> execution_id_manager;
122 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
123
124 auto [bits, truncated] = to_radix_simulator.to_le_bits(FF::one(), 1);
125
126 EXPECT_EQ(bits.size(), 1);
127 EXPECT_FALSE(truncated);
128
129 TestTraceContainer trace({
130 { { C::precomputed_first_row, 1 } },
131 });
132
133 ToRadixTraceBuilder builder;
134 builder.process(to_radix_event_emitter.dump_events(), trace);
135 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 1);
136 check_relation<to_radix>(trace);
137}
138
139TEST(ToRadixConstrainingTest, ToLeBitsPadded)
140{
141 EventEmitter<ToRadixEvent> to_radix_event_emitter;
142 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
143
144 PureGreaterThan gt;
145 StrictMock<MockExecutionIdManager> execution_id_manager;
146 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
147
148 auto [bits, truncated] = to_radix_simulator.to_le_bits(FF::one(), 500);
149
150 EXPECT_EQ(bits.size(), 500);
151 EXPECT_FALSE(truncated);
152
153 TestTraceContainer trace({
154 { { C::precomputed_first_row, 1 } },
155 });
156
157 ToRadixTraceBuilder builder;
158 builder.process(to_radix_event_emitter.dump_events(), trace);
159 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 500);
160 check_relation<to_radix>(trace);
161}
162
163TEST(ToRadixConstrainingTest, ToLeRadixBasic)
164{
165 EventEmitter<ToRadixEvent> to_radix_event_emitter;
166 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
167
168 PureGreaterThan gt;
169 StrictMock<MockExecutionIdManager> execution_id_manager;
170 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
171
172 FF value = FF::one();
173 auto [bytes, truncated] = to_radix_simulator.to_le_radix(value, 32, 256);
174
175 auto expected_bytes = value.to_buffer();
176 // to_buffer is BE
177 std::reverse(expected_bytes.begin(), expected_bytes.end());
178 EXPECT_EQ(bytes, expected_bytes);
179 EXPECT_FALSE(truncated);
180
181 TestTraceContainer trace({
182 { { C::precomputed_first_row, 1 } },
183 });
184
185 ToRadixTraceBuilder builder;
186 builder.process(to_radix_event_emitter.dump_events(), trace);
187 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 32);
188 check_relation<to_radix>(trace);
189}
190
191TEST(ToRadixConstrainingTest, ToLeRadixPMinusOne)
192{
193 EventEmitter<ToRadixEvent> to_radix_event_emitter;
194 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
195
196 PureGreaterThan gt;
197 StrictMock<MockExecutionIdManager> execution_id_manager;
198 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
199
200 FF value = FF::neg_one();
201 auto [bytes, truncated] = to_radix_simulator.to_le_radix(value, 32, 256);
202
203 auto expected_bytes = value.to_buffer();
204 // to_buffer is BE
205 std::reverse(expected_bytes.begin(), expected_bytes.end());
206 EXPECT_EQ(bytes, expected_bytes);
207 EXPECT_FALSE(truncated);
208
209 TestTraceContainer trace({
210 { { C::precomputed_first_row, 1 } },
211 });
212
213 ToRadixTraceBuilder builder;
214 builder.process(to_radix_event_emitter.dump_events(), trace);
215 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 32);
216 check_relation<to_radix>(trace);
217}
218
219TEST(ToRadixConstrainingTest, ToLeRadixOneByte)
220{
221 EventEmitter<ToRadixEvent> to_radix_event_emitter;
222 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
223
224 PureGreaterThan gt;
225 StrictMock<MockExecutionIdManager> execution_id_manager;
226 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
227
228 auto [bytes, truncated] = to_radix_simulator.to_le_radix(FF::one(), 1, 256);
229
230 std::vector<uint8_t> expected_bytes = { 1 };
231 EXPECT_EQ(bytes, expected_bytes);
232 EXPECT_FALSE(truncated);
233
234 TestTraceContainer trace({
235 { { C::precomputed_first_row, 1 } },
236 });
237
238 ToRadixTraceBuilder builder;
239 builder.process(to_radix_event_emitter.dump_events(), trace);
240 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 1);
241 check_relation<to_radix>(trace);
242}
243
244TEST(ToRadixConstrainingTest, ToLeRadixPadded)
245{
246 EventEmitter<ToRadixEvent> to_radix_event_emitter;
247 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
248
249 PureGreaterThan gt;
250 StrictMock<MockExecutionIdManager> execution_id_manager;
251 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
252
253 FF value = FF::neg_one();
254 auto [bytes, truncated] = to_radix_simulator.to_le_radix(value, 64, 256);
255
256 auto expected_bytes = value.to_buffer();
257 // to_buffer is BE
258 std::reverse(expected_bytes.begin(), expected_bytes.end());
259 expected_bytes.resize(64);
260 EXPECT_EQ(bytes, expected_bytes);
261 EXPECT_FALSE(truncated);
262
263 TestTraceContainer trace({
264 { { C::precomputed_first_row, 1 } },
265 });
266
267 ToRadixTraceBuilder builder;
268 builder.process(to_radix_event_emitter.dump_events(), trace);
269 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 64);
270 check_relation<to_radix>(trace);
271}
272
273TEST(ToRadixConstrainingTest, ToLeBitsInteractions)
274{
275 EventEmitter<ToRadixEvent> to_radix_event_emitter;
276 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
277
278 PureGreaterThan gt;
279 StrictMock<MockExecutionIdManager> execution_id_manager;
280 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
281
282 to_radix_simulator.to_le_bits(FF::neg_one(), 254);
283
284 TestTraceContainer trace({
285 { { C::precomputed_first_row, 1 } },
286 });
287
288 ToRadixTraceBuilder to_radix_builder;
289 to_radix_builder.process(to_radix_event_emitter.dump_events(), trace);
290 tracegen::PrecomputedTraceBuilder precomputed_builder;
295
296 check_interaction<ToRadixTraceBuilder,
302
303 check_relation<to_radix>(trace);
304}
305
306TEST(ToRadixConstrainingTest, ToLeRadixInteractions)
307{
308 EventEmitter<ToRadixEvent> to_radix_event_emitter;
309 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
310
311 PureGreaterThan gt;
312 StrictMock<MockExecutionIdManager> execution_id_manager;
313 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
314
315 to_radix_simulator.to_le_radix(FF::neg_one(), 32, 256);
316
317 TestTraceContainer trace({
318 { { C::precomputed_first_row, 1 } },
319 });
320
321 ToRadixTraceBuilder to_radix_builder;
322 to_radix_builder.process(to_radix_event_emitter.dump_events(), trace);
323 tracegen::PrecomputedTraceBuilder precomputed_builder;
324
329
330 check_interaction<ToRadixTraceBuilder,
336
337 check_relation<to_radix>(trace);
338}
339
340TEST(ToRadixConstrainingTest, NegativeOverflowCheck)
341{
342 TestTraceContainer trace({
343 { { C::precomputed_first_row, 1 } },
344 });
345
346 std::vector<uint8_t> modulus_le_bits(256, 0);
347 for (size_t i = 0; i < 256; i++) {
348 modulus_le_bits[i] = static_cast<uint8_t>(FF::modulus.get_bit(i));
349 }
350
351 ToRadixEvent event = { .value = FF::zero(), .radix = 2, .limbs = modulus_le_bits };
352 std::vector<ToRadixEvent> events = { event };
353
354 ToRadixTraceBuilder builder;
355 builder.process(events, trace);
356
357 EXPECT_THROW_WITH_MESSAGE(check_relation<to_radix>(trace, to_radix::SR_OVERFLOW_CHECK), "OVERFLOW_CHECK");
358}
359
360TEST(ToRadixConstrainingTest, NegativeConsistency)
361{
362 EventEmitter<ToRadixEvent> to_radix_event_emitter;
363 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
364
365 PureGreaterThan gt;
366 StrictMock<MockExecutionIdManager> execution_id_manager;
367 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
368
369 to_radix_simulator.to_le_radix(FF(256), 32, 256);
370
371 TestTraceContainer trace({
372 { { C::precomputed_first_row, 1 } },
373 });
374
375 ToRadixTraceBuilder builder;
376 builder.process(to_radix_event_emitter.dump_events(), trace);
377
378 // Disable the selector in the middle
379 trace.set(Column::to_radix_sel, 6, 0);
380
381 EXPECT_THROW_WITH_MESSAGE(check_relation<to_radix>(trace, to_radix::SR_SELECTOR_CONSISTENCY),
382 "SELECTOR_CONSISTENCY");
383
384 // Mutate the radix
385 trace.set(Column::to_radix_radix, 5, 200);
386
388 "CONSTANT_CONSISTENCY_RADIX");
389
390 // Mutate the value
391 trace.set(Column::to_radix_value, 4, 27);
392
394 "CONSTANT_CONSISTENCY_VALUE");
395
396 // Mutate the safe_limbs
397 trace.set(Column::to_radix_safe_limbs, 3, 200);
398
400 "CONSTANT_CONSISTENCY_SAFE_LIMBS");
401}
402
404// ToRadix Memory Tests
406
407TEST(ToRadixMemoryConstrainingTest, EmptyRow)
408{
409 check_relation<to_radix_mem>(testing::empty_trace());
410}
411
412TEST(ToRadixMemoryConstrainingTest, BasicTest)
413{
414 // Values
415 FF value = FF(1337);
416 uint32_t radix = 10;
417 uint32_t num_limbs = 4;
418 uint32_t dst_addr = 10;
419
420 TestTraceContainer trace = TestTraceContainer({
421 // Row 0
422 {
423 { C::precomputed_first_row, 1 },
424 // GT check - Dst > MAX_MEM = false
425 { C::gt_sel, 1 },
426 { C::gt_input_a, dst_addr + num_limbs },
427 { C::gt_input_b, MAX_MEM },
428 { C::gt_res, 0 }, // GT should return true
429 // Execution Trace (No gas)
430 { C::execution_sel, 1 },
431 { C::execution_sel_exec_dispatch_to_radix, 1 },
432 { C::execution_register_0_, value },
433 { C::execution_register_1_, radix },
434 { C::execution_register_2_, num_limbs },
435 { C::execution_register_3_, 0 }, // is_output_bits
436 { C::execution_rop_4_, dst_addr },
437
438 },
439 // Row 1
440 {
441 // To Radix Mem
442 { C::to_radix_mem_sel, 1 },
443 { C::to_radix_mem_max_mem_size, MAX_MEM },
444 { C::to_radix_mem_two, 2 },
445 { C::to_radix_mem_two_five_six, 256 },
446 // Memory Inputs
447 { C::to_radix_mem_execution_clk, 0 },
448 { C::to_radix_mem_space_id, 0 },
449 { C::to_radix_mem_dst_addr, dst_addr },
450 { C::to_radix_mem_write_addr_upper_bound, dst_addr + num_limbs },
451 // To Radix Inputs
452 { C::to_radix_mem_value_to_decompose, value },
453 { C::to_radix_mem_radix, radix },
454 { C::to_radix_mem_num_limbs, num_limbs },
455 { C::to_radix_mem_is_output_bits, 0 },
456 // Control Flow
457 { C::to_radix_mem_start, 1 },
458 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 : FF(num_limbs - 1).invert() },
459 // Helpers
460 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
461 { C::to_radix_mem_num_limbs_inv, FF(num_limbs).invert() },
462 { C::to_radix_mem_sel_value_is_zero, 0 },
463 { C::to_radix_mem_value_inv, value.invert() },
464 // Output
465 { C::to_radix_mem_limb_value, 1 },
466 { C::to_radix_mem_sel_should_decompose, 1 },
467 { C::to_radix_mem_sel_should_write_mem, 1 },
468 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
469 { C::to_radix_mem_value_found, 1 },
470 { C::to_radix_mem_output_tag, static_cast<uint8_t>(MemoryTag::U8) },
471
472 // GT check - 2 > radix = false
473 { C::gt_sel, 1 },
474 { C::gt_input_a, 2 },
475 { C::gt_input_b, radix },
476 { C::gt_res, 0 }, // GT should return false
477 },
478 // Row 2
479 {
480 { C::to_radix_mem_sel, 1 },
481 // Memory Inputs
482 { C::to_radix_mem_execution_clk, 0 },
483 { C::to_radix_mem_space_id, 0 },
484 { C::to_radix_mem_dst_addr, dst_addr + 1 },
485 // To Radix Inputs
486 { C::to_radix_mem_value_to_decompose, value },
487 { C::to_radix_mem_radix, radix },
488 { C::to_radix_mem_num_limbs, num_limbs - 1 },
489 { C::to_radix_mem_is_output_bits, 0 },
490 // Control Flow
491 // num_limbs_minus_one = (num_limbs - 1) - 1)
492 { C::to_radix_mem_num_limbs_minus_one_inv, FF(num_limbs - 2).invert() },
493 // Output
494 { C::to_radix_mem_limb_value, 3 },
495 { C::to_radix_mem_sel_should_decompose, 1 },
496 { C::to_radix_mem_sel_should_write_mem, 1 },
497 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 2 },
498 { C::to_radix_mem_output_tag, static_cast<uint8_t>(MemoryTag::U8) },
499 // GT check - Radix > 256 = false
500 { C::gt_sel, 1 },
501 { C::gt_input_a, radix },
502 { C::gt_input_b, 256 },
503 { C::gt_res, 0 }, // GT should return false
504 },
505 // Row 3
506 {
507 { C::to_radix_mem_sel, 1 },
508 // Memory Inputs
509 { C::to_radix_mem_execution_clk, 0 },
510 { C::to_radix_mem_space_id, 0 },
511 { C::to_radix_mem_dst_addr, dst_addr + 2 },
512 // To Radix Inputs
513 { C::to_radix_mem_value_to_decompose, value },
514 { C::to_radix_mem_radix, radix },
515 { C::to_radix_mem_num_limbs, num_limbs - 2 },
516 { C::to_radix_mem_is_output_bits, 0 },
517 // Control Flow
518 // num_limbs_minus_one = (num_limbs - 2) - 1)
519 { C::to_radix_mem_num_limbs_minus_one_inv, FF(num_limbs - 3).invert() },
520 // Output
521 { C::to_radix_mem_limb_value, 3 },
522 { C::to_radix_mem_sel_should_decompose, 1 },
523 { C::to_radix_mem_sel_should_write_mem, 1 },
524 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 3 },
525 { C::to_radix_mem_output_tag, static_cast<uint8_t>(MemoryTag::U8) },
526 },
527 // Row 4
528 {
529 { C::to_radix_mem_sel, 1 },
530 // Memory Inputs
531 { C::to_radix_mem_execution_clk, 0 },
532 { C::to_radix_mem_space_id, 0 },
533 { C::to_radix_mem_dst_addr, 13 },
534 // To Radix Inputs
535 { C::to_radix_mem_value_to_decompose, value },
536 { C::to_radix_mem_radix, radix },
537 { C::to_radix_mem_num_limbs, num_limbs - 3 },
538 { C::to_radix_mem_is_output_bits, 0 },
539 // Control Flow
540 { C::to_radix_mem_last, 1 },
541 // Output
542 { C::to_radix_mem_limb_value, 7 },
543 { C::to_radix_mem_sel_should_decompose, 1 },
544 { C::to_radix_mem_sel_should_write_mem, 1 },
545 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 4 },
546 { C::to_radix_mem_output_tag, static_cast<uint8_t>(MemoryTag::U8) },
547 },
548 });
549
550 // Set the memory values and addresses
551 MemoryAddress value_addr = 0xdeadbeef;
552 MemoryAddress radix_addr = 0x12345678;
553 MemoryAddress num_limbs_addr = 0xc0ffee;
554 MemoryAddress is_output_bits_addr = 0xfeedface;
555
557 { value_addr, MemoryValue::from<FF>(value) },
558 { radix_addr, MemoryValue::from<uint32_t>(radix) },
559 { num_limbs_addr, MemoryValue::from<uint32_t>(num_limbs) },
560 { is_output_bits_addr, MemoryValue::from<uint1_t>(false) },
561 { dst_addr, MemoryValue::from<uint8_t>(1) },
562 { dst_addr + 1, MemoryValue::from<uint8_t>(3) },
563 { dst_addr + 2, MemoryValue::from<uint8_t>(3) },
564 { dst_addr + 3, MemoryValue::from<uint8_t>(7) },
565 };
566
567 for (uint32_t i = 0; i < memory_values.size(); ++i) {
568 const auto& [addr, value] = memory_values[i];
569 trace.set(i,
570 {
571 { { C::memory_sel, 1 },
572 { C::memory_space_id, 0 },
573 { C::memory_address, addr },
574 { C::memory_value, value.as_ff() },
575 { C::memory_tag, static_cast<uint8_t>(value.get_tag()) },
576 { C::memory_rw, i > 3 ? 1 : 0 } },
577 });
578 }
579
580 EventEmitter<ToRadixEvent> to_radix_event_emitter;
581 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
582
583 PureGreaterThan gt;
584 StrictMock<MockExecutionIdManager> execution_id_manager;
585 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
586
587 // Generate the events for the to_radix subtrace
588 to_radix_simulator.to_le_radix(value, num_limbs, radix);
589
590 ToRadixTraceBuilder builder;
591 auto events = to_radix_event_emitter.get_events();
592 builder.process(to_radix_event_emitter.dump_events(), trace);
593
594 PrecomputedTraceBuilder precomputed_builder;
597 precomputed_builder.process_misc(trace, 257); // Needed for precomputed safe limbs table
598
599 check_relation<to_radix_mem>(trace);
600 check_all_interactions<ToRadixTraceBuilder>(trace);
601
602 // Negative test: disable memory write after the start row:
603 trace.set(Column::to_radix_mem_sel_should_write_mem, 2, 0);
605 "SEL_SHOULD_WRITE_MEM_CONTINUITY");
606
607 // Negative test: disable decomposition after the start row:
608 trace.set(Column::to_radix_mem_sel_should_decompose, 2, 0);
610 "SEL_SHOULD_DECOMPOSE_CONTINUITY");
611}
612
613TEST(ToRadixMemoryConstrainingTest, DstOutOfRange)
614{
615 // Values
616 FF value = FF(1337);
617 uint32_t radix = 10;
618 uint32_t num_limbs = 2;
619 auto dst_addr = static_cast<uint64_t>(MAX_MEM - 1); // This will cause an out-of-bounds error
620
621 TestTraceContainer trace = TestTraceContainer({
622 // Row 0
623 {
624 { C::precomputed_first_row, 1 },
625 // GT check
626 { C::gt_sel, 1 },
627 { C::gt_input_a, dst_addr + num_limbs },
628 { C::gt_input_b, MAX_MEM },
629 { C::gt_res, 1 }, // GT should return true
630 },
631 // Row 1
632 {
633 // Execution Trace (No gas)
634 { C::execution_sel, 1 },
635 { C::execution_sel_exec_dispatch_to_radix, 1 },
636 { C::execution_register_0_, value },
637 { C::execution_register_1_, radix },
638 { C::execution_register_2_, num_limbs },
639 { C::execution_register_3_, 0 }, // is_output_bits
640 { C::execution_rop_4_, dst_addr },
641 { C::execution_sel_opcode_error, 1 },
642
643 // To Radix Mem
644 { C::to_radix_mem_sel, 1 },
645 { C::to_radix_mem_max_mem_size, MAX_MEM },
646 { C::to_radix_mem_two, 2 },
647 { C::to_radix_mem_two_five_six, 256 },
648 // Memory Inputs
649 { C::to_radix_mem_execution_clk, 0 },
650 { C::to_radix_mem_space_id, 0 },
651 { C::to_radix_mem_dst_addr, dst_addr },
652 { C::to_radix_mem_write_addr_upper_bound, dst_addr + num_limbs },
653 // To Radix Inputs
654 { C::to_radix_mem_value_to_decompose, value },
655 { C::to_radix_mem_radix, radix },
656 { C::to_radix_mem_num_limbs, num_limbs },
657 { C::to_radix_mem_is_output_bits, 0 },
658 // Errors
659 { C::to_radix_mem_sel_dst_out_of_range_err, 1 },
660 { C::to_radix_mem_input_validation_error, 1 },
661 { C::to_radix_mem_err, 1 },
662 // Control Flow
663 { C::to_radix_mem_start, 1 },
664 { C::to_radix_mem_last, 1 },
665 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 : FF(num_limbs - 1).invert() },
666 // Helpers
667 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
668 { C::to_radix_mem_num_limbs_inv, FF(num_limbs).invert() },
669 { C::to_radix_mem_sel_value_is_zero, 0 },
670 { C::to_radix_mem_value_inv, value.invert() },
671 },
672 });
673
674 check_relation<to_radix_mem>(trace);
675 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_dst_addr_in_range_settings>(trace);
676 check_interaction<ExecutionTraceBuilder, perm_execution_dispatch_to_to_radix_settings>(trace);
677}
678
679TEST(ToRadixMemoryConstrainingTest, InvalidRadix)
680{
681 // Values
682 FF value = FF(1337);
683 uint32_t radix = 0; // Invalid radix
684 uint32_t num_limbs = 2;
685 uint32_t dst_addr = 10;
686
687 TestTraceContainer trace = TestTraceContainer({
688 // Row 0
689 {
690 { C::precomputed_first_row, 1 },
691 // GT check
692 { C::gt_sel, 1 },
693 { C::gt_input_a, 2 },
694 { C::gt_input_b, radix },
695 { C::gt_res, 1 }, // GT should return true
696 },
697 // Row 1
698 {
699 { C::to_radix_mem_sel, 1 },
700 { C::to_radix_mem_max_mem_size, MAX_MEM },
701 { C::to_radix_mem_two, 2 },
702 { C::to_radix_mem_two_five_six, 256 },
703 // Memory Inputs
704 { C::to_radix_mem_execution_clk, 0 },
705 { C::to_radix_mem_space_id, 0 },
706 { C::to_radix_mem_dst_addr, dst_addr },
707 { C::to_radix_mem_write_addr_upper_bound, dst_addr + num_limbs },
708 // To Radix Inputs
709 { C::to_radix_mem_value_to_decompose, value },
710 { C::to_radix_mem_radix, radix },
711 { C::to_radix_mem_num_limbs, num_limbs },
712 { C::to_radix_mem_is_output_bits, 0 },
713 // Errors
714 { C::to_radix_mem_sel_radix_lt_2_err, 1 },
715 { C::to_radix_mem_input_validation_error, 1 },
716 { C::to_radix_mem_err, 1 },
717 // Control Flow
718 { C::to_radix_mem_start, 1 },
719 { C::to_radix_mem_last, 1 },
720 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 : FF(num_limbs - 1).invert() },
721 // Helpers
722 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
723 { C::to_radix_mem_num_limbs_inv, FF(num_limbs).invert() },
724 { C::to_radix_mem_sel_value_is_zero, 0 },
725 { C::to_radix_mem_value_inv, value.invert() },
726 },
727 });
728 check_relation<to_radix_mem>(trace);
729 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
730}
731
732TEST(ToRadixMemoryConstrainingTest, InvalidBitwiseRadix)
733{
734 // Values
735 FF value = FF(1337);
736 uint32_t radix = 3; // Invalid radix since is_output_bits is true
737 uint32_t num_limbs = 2;
738 uint32_t dst_addr = 10;
739 bool is_output_bits = true;
740
741 TestTraceContainer trace = TestTraceContainer({
742 // Row 0
743 {
744 { C::precomputed_first_row, 1 },
745 // GT check
746 { C::gt_sel, 1 },
747 { C::gt_input_a, 2 },
748 { C::gt_input_b, radix },
749 { C::gt_res, 0 }, // GT should return false
750 },
751 // Row 1
752 {
753 { C::to_radix_mem_sel, 1 },
754 { C::to_radix_mem_max_mem_size, MAX_MEM },
755 { C::to_radix_mem_two, 2 },
756 { C::to_radix_mem_two_five_six, 256 },
757 // Memory Inputs
758 { C::to_radix_mem_execution_clk, 0 },
759 { C::to_radix_mem_space_id, 0 },
760 { C::to_radix_mem_dst_addr, dst_addr },
761 { C::to_radix_mem_write_addr_upper_bound, dst_addr + num_limbs },
762 // To Radix Inputs
763 { C::to_radix_mem_value_to_decompose, value },
764 { C::to_radix_mem_radix, radix },
765 { C::to_radix_mem_num_limbs, num_limbs },
766 { C::to_radix_mem_is_output_bits, is_output_bits ? 1 : 0 },
767 // Errors
768 { C::to_radix_mem_sel_invalid_bitwise_radix, 1 }, // Invalid bitwise radix
769 { C::to_radix_mem_input_validation_error, 1 },
770 { C::to_radix_mem_err, 1 },
771 // Control Flow
772 { C::to_radix_mem_start, 1 },
773 { C::to_radix_mem_last, 1 },
774 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 : FF(num_limbs - 1).invert() },
775 // Helpers
776 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
777 { C::to_radix_mem_num_limbs_inv, FF(num_limbs).invert() },
778 { C::to_radix_mem_sel_value_is_zero, 0 },
779 { C::to_radix_mem_value_inv, value.invert() },
780 },
781 });
782 check_relation<to_radix_mem>(trace);
783 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
784}
785
786TEST(ToRadixMemoryConstrainingTest, InvalidNumLimbsForValue)
787{
788 // Values
789 FF value = FF(1337);
790 uint32_t radix = 3;
791 uint32_t num_limbs = 0; // num limbs should not be 0 if value != 0
792 uint32_t dst_addr = 10;
793 bool is_output_bits = false;
794
795 TestTraceContainer trace = TestTraceContainer({
796 // Row 0
797 {
798 { C::precomputed_first_row, 1 },
799 // GT check
800 { C::gt_sel, 1 },
801 { C::gt_input_a, 2 },
802 { C::gt_input_b, radix },
803 { C::gt_res, 0 }, // GT should return false
804 },
805 // Row 1
806 {
807 { C::to_radix_mem_sel, 1 },
808 { C::to_radix_mem_max_mem_size, MAX_MEM },
809 { C::to_radix_mem_two, 2 },
810 { C::to_radix_mem_two_five_six, 256 },
811 // Memory Inputs
812 { C::to_radix_mem_execution_clk, 0 },
813 { C::to_radix_mem_space_id, 0 },
814 { C::to_radix_mem_dst_addr, dst_addr },
815 { C::to_radix_mem_write_addr_upper_bound, dst_addr + num_limbs },
816 // To Radix Inputs
817 { C::to_radix_mem_value_to_decompose, value },
818 { C::to_radix_mem_radix, radix },
819 { C::to_radix_mem_num_limbs, num_limbs },
820 { C::to_radix_mem_is_output_bits, is_output_bits ? 1 : 0 },
821 // Errors
822 { C::to_radix_mem_sel_invalid_num_limbs_err, 1 }, // num_limbs should not be 0 if value != 0
823 { C::to_radix_mem_input_validation_error, 1 },
824 { C::to_radix_mem_err, 1 },
825 // Control Flow
826 { C::to_radix_mem_start, 1 },
827 { C::to_radix_mem_last, 1 },
828 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 : FF(num_limbs - 1).invert() },
829 // Helpers
830 { C::to_radix_mem_sel_num_limbs_is_zero, 1 }, // num limbs is zero
831 { C::to_radix_mem_num_limbs_inv, 0 },
832 { C::to_radix_mem_sel_value_is_zero, 0 },
833 { C::to_radix_mem_value_inv, value.invert() },
834 },
835 });
836 check_relation<to_radix_mem>(trace);
837 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
838}
839
840TEST(ToRadixMemoryConstrainingTest, TruncationError)
841{
842 // Values
843 FF value = FF(1337);
844 uint32_t radix = 10;
845 uint32_t num_limbs = 3;
846 uint32_t dst_addr = 10;
847 bool is_output_bits = false;
848
849 TestTraceContainer trace = TestTraceContainer({
850 // Row 0
851 {
852 { C::precomputed_first_row, 1 },
853 // GT check
854 { C::gt_sel, 1 },
855 { C::gt_input_a, 2 },
856 { C::gt_input_b, radix },
857 { C::gt_res, 0 }, // GT should return false
858 },
859 // Row 1
860 {
861 { C::to_radix_mem_sel, 1 },
862 { C::to_radix_mem_max_mem_size, MAX_MEM },
863 { C::to_radix_mem_two, 2 },
864 { C::to_radix_mem_two_five_six, 256 },
865 // Memory Inputs
866 { C::to_radix_mem_execution_clk, 0 },
867 { C::to_radix_mem_space_id, 0 },
868 { C::to_radix_mem_dst_addr, dst_addr },
869 { C::to_radix_mem_write_addr_upper_bound, dst_addr + num_limbs },
870 // To Radix Inputs
871 { C::to_radix_mem_value_to_decompose, value },
872 { C::to_radix_mem_radix, radix },
873 { C::to_radix_mem_num_limbs, num_limbs },
874 { C::to_radix_mem_is_output_bits, is_output_bits ? 1 : 0 },
875 // Errors
876 { C::to_radix_mem_sel_truncation_error, 1 }, // found = false on the last le limb
877 { C::to_radix_mem_err, 1 },
878 // Control Flow
879 { C::to_radix_mem_start, 1 },
880 { C::to_radix_mem_last, 1 },
881 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 : FF(num_limbs - 1).invert() },
882 // Decomposition
883 { C::to_radix_mem_sel_should_decompose, 1 },
884 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
885 { C::to_radix_mem_limb_value, 3 },
886 { C::to_radix_mem_value_found, 0 },
887 // Helpers
888 { C::to_radix_mem_num_limbs_inv, FF(num_limbs).invert() },
889 { C::to_radix_mem_sel_value_is_zero, 0 },
890 { C::to_radix_mem_value_inv, value.invert() },
891 },
892 });
893 check_relation<to_radix_mem>(trace);
894 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
895
896 // Negative test: truncation error should be on if found = false on the start row
897 trace.set(C::to_radix_mem_sel_truncation_error, 1, 0);
898 EXPECT_THROW_WITH_MESSAGE(check_relation<to_radix_mem>(trace, to_radix_mem::SR_TRUNCATION_ERROR),
899 "TRUNCATION_ERROR");
900 trace.set(C::to_radix_mem_sel_truncation_error, 1, 1);
901
902 // Negative test: truncation error can't be on if found = true on the start row
903 trace.set(C::to_radix_mem_value_found, 1, 1);
904 EXPECT_THROW_WITH_MESSAGE(check_relation<to_radix_mem>(trace, to_radix_mem::SR_TRUNCATION_ERROR),
905 "TRUNCATION_ERROR");
906}
907
908TEST(ToRadixMemoryConstrainingTest, ZeroNumLimbsAndZeroValueIsNoop)
909{
910 // Values
911 FF value = FF(0);
912 uint32_t radix = 3;
913 uint32_t num_limbs = 0; // num limbs can be zero since value is zero
914 uint32_t dst_addr = 10;
915 bool is_output_bits = false;
916
917 TestTraceContainer trace = TestTraceContainer({
918 // Row 0
919 {
920 { C::precomputed_first_row, 1 },
921 // GT check
922 { C::gt_sel, 1 },
923 { C::gt_input_a, 2 },
924 { C::gt_input_b, radix },
925 { C::gt_res, 0 }, // GT should return false
926 },
927 // Row 1
928 {
929 { C::to_radix_mem_sel, 1 },
930 { C::to_radix_mem_max_mem_size, MAX_MEM },
931 { C::to_radix_mem_two, 2 },
932 { C::to_radix_mem_two_five_six, 256 },
933 // Memory Inputs
934 { C::to_radix_mem_execution_clk, 0 },
935 { C::to_radix_mem_space_id, 0 },
936 { C::to_radix_mem_dst_addr, dst_addr },
937 { C::to_radix_mem_write_addr_upper_bound, dst_addr + num_limbs },
938 // To Radix Inputs
939 { C::to_radix_mem_value_to_decompose, value },
940 { C::to_radix_mem_radix, radix },
941 { C::to_radix_mem_num_limbs, num_limbs },
942 { C::to_radix_mem_is_output_bits, is_output_bits ? 1 : 0 },
943 // Control Flow
944 { C::to_radix_mem_start, 1 },
945 { C::to_radix_mem_last, 1 },
946 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 : FF(num_limbs - 1).invert() },
947 // Helpers
948 { C::to_radix_mem_sel_num_limbs_is_zero, 1 }, // num limbs is zero
949 { C::to_radix_mem_num_limbs_inv, 0 },
950 { C::to_radix_mem_sel_value_is_zero, 1 },
951 { C::to_radix_mem_value_inv, 0 },
952 },
953 });
954 check_relation<to_radix_mem>(trace);
955 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
956}
957
958TEST(ToRadixMemoryConstrainingTest, ComplexTest)
959{
960 EventEmitter<ToRadixEvent> to_radix_event_emitter;
961 EventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
962 EventEmitter<RangeCheckEvent> range_check_emitter;
963 EventEmitter<GreaterThanEvent> gt_emitter;
964
965 simulation::MemoryStore memory;
966 StrictMock<MockExecutionIdManager> execution_id_manager;
967 StrictMock<MockFieldGreaterThan> field_gt;
969 GreaterThan gt(field_gt, range_check, gt_emitter);
970 EXPECT_CALL(execution_id_manager, get_execution_id()).WillOnce(Return(0)).WillOnce(Return(1));
971 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
972
973 FF value = FF::neg_one();
974 uint32_t radix = 2;
975 uint32_t num_limbs = 256;
977 bool is_output_bits = true;
978 // Two calls to test transitions between contiguous chunks of computation
979 to_radix_simulator.to_be_radix(memory, value, radix, num_limbs, is_output_bits, dst_addr);
980 to_radix_simulator.to_be_radix(
981 memory, /*value=*/FF(1337), /*radix=*/10, /*num_limbs=*/6, /*is_output_bits=*/false, /*dst_addr=*/0xdeadbeef);
982
983 TestTraceContainer trace;
984 ToRadixTraceBuilder builder;
985 builder.process(to_radix_event_emitter.dump_events(), trace);
986 builder.process_with_memory(to_radix_mem_event_emitter.dump_events(), trace);
987
988 GreaterThanTraceBuilder gt_builder;
989 gt_builder.process(gt_emitter.dump_events(), trace);
990
991 PrecomputedTraceBuilder precomputed_builder;
994 precomputed_builder.process_misc(trace, 257); // Needed for precomputed safe limbs table
995
996 check_relation<to_radix>(trace);
997 check_relation<to_radix_mem>(trace);
998 // Skip the memory writes
999 check_interaction<ToRadixTraceBuilder,
1010}
1011
1012// =====================================================================
1013// Ghost Row Injection Vulnerability Tests
1014// =====================================================================
1015// These tests verify that ghost rows (sel=0) cannot fire permutations.
1016// The fix: sel_should_write_mem * (1 - sel) = 0 ensures sel_should_write_mem
1017// is forced to 0 when sel=0, preventing ghost rows from firing permutations.
1018
1019// Test that ghost rows (sel=0) cannot set sel_should_write_mem=1
1020TEST(ToRadixMemoryConstrainingTest, NegativeGhostRowMemoryWrite_RelationsOnly)
1021{
1022 // Try to create a ghost row (sel=0) with sel_should_write_mem=1
1023 // which would fire the #[WRITE_MEM] permutation
1024 TestTraceContainer trace({
1025 {
1026 { C::precomputed_first_row, 1 },
1027 },
1028 {
1029 { C::to_radix_mem_sel, 0 }, // Ghost row: gadget not active
1030 { C::to_radix_mem_sel_should_write_mem, 1 }, // Try to fire memory write anyway
1031 { C::to_radix_mem_execution_clk, 1 },
1032 { C::to_radix_mem_space_id, 1 },
1033 { C::to_radix_mem_dst_addr, 100 },
1034 { C::to_radix_mem_limb_value, 999 }, // Arbitrary limb value
1035 { C::to_radix_mem_output_tag, 2 }, // U8 tag
1036 },
1037 });
1038
1039 // The fix: sel_should_write_mem * (1 - sel) = 0
1040 // When sel=0 and sel_should_write_mem=1: 1 * (1-0) = 1 != 0 -> FAILS
1042 "SEL_SHOULD_WRITE_MEM_REQUIRES_SEL");
1043}
1044
1045// Test that the fix blocks ghost row injection attacks with full traces.
1046// Attack pattern:
1047// 1. Create legitimate memory WRITE events (destination side)
1048// 2. Build memory trace from those events
1049// 3. Inject ghost to_radix_mem row with sel=0 but sel_should_write_mem=1
1050// 4. The fix should cause the relation check to fail
1051TEST(ToRadixMemoryConstrainingTest, NegativeGhostRowInjectionBlocked)
1052{
1053 TestTraceContainer trace;
1054 MemoryTraceBuilder memory_trace_builder;
1055 PrecomputedTraceBuilder precomputed_trace_builder;
1056
1057 // Attacker-controlled values
1058 uint32_t malicious_clk = 42;
1059 uint16_t malicious_space_id = 1;
1060 MemoryAddress malicious_addr = 0xDEAD;
1061 uint8_t malicious_limb_value = 0x99;
1062 MemoryTag malicious_tag = MemoryTag::U8;
1063
1064 // Create legitimate memory events
1066 {
1067 .execution_clk = malicious_clk,
1069 .addr = malicious_addr,
1070 .value = MemoryValue::from_tag(malicious_tag, malicious_limb_value),
1071 .space_id = malicious_space_id,
1072 },
1073 };
1074
1075 // Build memory trace (destination side)
1076 precomputed_trace_builder.process_sel_range_8(trace);
1077 precomputed_trace_builder.process_sel_range_16(trace);
1078 precomputed_trace_builder.process_misc(trace, 1 << 16);
1079 precomputed_trace_builder.process_tag_parameters(trace);
1080 memory_trace_builder.process(mem_events, trace);
1081
1082 // Find where the memory row was placed
1083 uint32_t memory_row = 0;
1084 for (uint32_t row = 0; row < trace.get_num_rows(); row++) {
1085 if (trace.get(C::memory_sel, row) == 1) {
1086 memory_row = row;
1087 break;
1088 }
1089 }
1090
1091 // Inject ghost to_radix_mem row
1092 // Ghost row: sel = 0, but sel_should_write_mem = 1 (attack attempt)
1093 uint32_t ghost_row = 0;
1094 trace.set(ghost_row,
1095 std::vector<std::pair<Column, FF>>{
1096 { C::precomputed_first_row, 1 },
1097 { C::precomputed_clk, ghost_row },
1098 { C::to_radix_mem_sel, 0 },
1099 { C::to_radix_mem_sel_should_write_mem, 1 },
1100 { C::to_radix_mem_execution_clk, malicious_clk },
1101 { C::to_radix_mem_space_id, malicious_space_id },
1102 { C::to_radix_mem_dst_addr, malicious_addr },
1103 { C::to_radix_mem_limb_value, malicious_limb_value },
1104 { C::to_radix_mem_output_tag, static_cast<uint8_t>(malicious_tag) },
1105 });
1106
1107 trace.set(C::memory_sel_to_radix_write, memory_row, 1);
1108
1109 // The fix: sel_should_write_mem * (1 - sel) = 0 should cause the relation check to fail
1110 EXPECT_THROW_WITH_MESSAGE(check_relation<to_radix_mem>(trace), "SEL_SHOULD_WRITE_MEM_REQUIRES_SEL");
1111}
1112
1113} // namespace
1114
1115} // namespace bb::avm2::constraining
DeduplicatingEventEmitter< GreaterThanEvent > gt_emitter
FieldGreaterThan field_gt
DeduplicatingEventEmitter< RangeCheckEvent > range_check_emitter
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:193
#define AVM_MEMORY_SIZE
static TaggedValue from_tag(ValueTag tag, FF value)
static constexpr size_t SR_SEL_SHOULD_WRITE_MEM_CONTINUITY
static constexpr size_t SR_SEL_SHOULD_DECOMPOSE_CONTINUITY
static constexpr size_t SR_TRUNCATION_ERROR
static constexpr size_t SR_SEL_SHOULD_WRITE_MEM_REQUIRES_SEL
static constexpr size_t SR_SELECTOR_CONSISTENCY
Definition to_radix.hpp:42
static constexpr size_t SR_OVERFLOW_CHECK
Definition to_radix.hpp:43
static constexpr size_t SR_CONSTANT_CONSISTENCY_SAFE_LIMBS
Definition to_radix.hpp:46
static constexpr size_t SR_CONSTANT_CONSISTENCY_RADIX
Definition to_radix.hpp:44
static constexpr size_t SR_CONSTANT_CONSISTENCY_VALUE
Definition to_radix.hpp:45
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(const simulation::EventEmitterInterface< simulation::GreaterThanEvent >::Container &events, TraceContainer &trace)
Definition gt_trace.cpp:11
void process_to_radix_p_decompositions(TraceContainer &trace)
void process_to_radix_safe_limbs(TraceContainer &trace)
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)
constexpr bool get_bit(uint64_t bit_index) const
PrecomputedTraceBuilder precomputed_builder
Definition alu.test.cpp:120
AluTraceBuilder builder
Definition alu.test.cpp:124
GreaterThanTraceBuilder gt_builder
Definition alu.test.cpp:123
ExecutionIdManager execution_id_manager
uint32_t dst_addr
RangeCheck range_check
GreaterThan gt
TestTraceContainer trace
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
lookup_settings< lookup_to_radix_limb_less_than_radix_range_settings_ > lookup_to_radix_limb_less_than_radix_range_settings
lookup_settings< lookup_to_radix_limb_p_diff_range_settings_ > lookup_to_radix_limb_p_diff_range_settings
lookup_settings< lookup_to_radix_mem_check_dst_addr_in_range_settings_ > lookup_to_radix_mem_check_dst_addr_in_range_settings
lookup_settings< lookup_to_radix_mem_check_radix_lt_2_settings_ > lookup_to_radix_mem_check_radix_lt_2_settings
lookup_settings< lookup_to_radix_limb_range_settings_ > lookup_to_radix_limb_range_settings
lookup_settings< lookup_to_radix_mem_check_radix_gt_256_settings_ > lookup_to_radix_mem_check_radix_gt_256_settings
lookup_settings< lookup_to_radix_fetch_safe_limbs_settings_ > lookup_to_radix_fetch_safe_limbs_settings
lookup_settings< lookup_to_radix_mem_input_output_to_radix_settings_ > lookup_to_radix_mem_input_output_to_radix_settings
uint32_t MemoryAddress
lookup_settings< lookup_to_radix_fetch_p_limb_settings_ > lookup_to_radix_fetch_p_limb_settings
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
MemoryStore memory
static constexpr uint256_t modulus
constexpr field invert() const noexcept
BB_INLINE std::vector< uint8_t > to_buffer() const