2#include <gmock/gmock.h>
3#include <gtest/gtest.h>
5#include "barretenberg/aztec/aztec_constants.hpp"
34using ::testing::Return;
35using ::testing::StrictMock;
37using tracegen::ExecutionTraceBuilder;
38using tracegen::GreaterThanTraceBuilder;
39using tracegen::MemoryTraceBuilder;
40using tracegen::PrecomputedTraceBuilder;
41using tracegen::TestTraceContainer;
42using tracegen::ToRadixTraceBuilder;
48using ToRadixSimulator = simulation::ToRadix;
50using simulation::EventEmitter;
51using simulation::GreaterThan;
52using simulation::GreaterThanEvent;
53using simulation::MockExecutionIdManager;
54using simulation::MockFieldGreaterThan;
55using simulation::NoopEventEmitter;
56using simulation::PureGreaterThan;
57using simulation::RangeCheck;
58using simulation::RangeCheckEvent;
59using simulation::ToRadixEvent;
60using simulation::ToRadixMemoryEvent;
62constexpr uint64_t MAX_MEM = AVM_MEMORY_SIZE;
64TEST(ToRadixConstrainingTest, EmptyRow)
69TEST(ToRadixConstrainingTest, ToLeBitsBasicTest)
71 EventEmitter<ToRadixEvent> to_radix_event_emitter;
72 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
76 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
78 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::one(), 254);
80 EXPECT_EQ(bits.size(), 254);
81 EXPECT_FALSE(truncated);
83 TestTraceContainer
trace({
84 { { C::precomputed_first_row, 1 } },
90 check_relation<to_radix>(trace);
93TEST(ToRadixConstrainingTest, ToLeBitsPMinusOne)
95 EventEmitter<ToRadixEvent> to_radix_event_emitter;
96 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
100 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
102 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::neg_one(), 254);
104 EXPECT_EQ(bits.size(), 254);
105 EXPECT_FALSE(truncated);
107 TestTraceContainer
trace({
108 { { C::precomputed_first_row, 1 } },
114 check_relation<to_radix>(trace);
117TEST(ToRadixConstrainingTest, ToLeBitsShortest)
119 EventEmitter<ToRadixEvent> to_radix_event_emitter;
120 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
124 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
126 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::one(), 1);
128 EXPECT_EQ(bits.size(), 1);
129 EXPECT_FALSE(truncated);
131 TestTraceContainer
trace({
132 { { C::precomputed_first_row, 1 } },
138 check_relation<to_radix>(trace);
141TEST(ToRadixConstrainingTest, ToLeBitsPadded)
143 EventEmitter<ToRadixEvent> to_radix_event_emitter;
144 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
148 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
150 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::one(), 500);
152 EXPECT_EQ(bits.size(), 500);
153 EXPECT_FALSE(truncated);
155 TestTraceContainer
trace({
156 { { C::precomputed_first_row, 1 } },
162 check_relation<to_radix>(trace);
165TEST(ToRadixConstrainingTest, ToLeRadixBasic)
167 EventEmitter<ToRadixEvent> to_radix_event_emitter;
168 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
172 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
175 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
value, 32, 256);
179 std::reverse(expected_bytes.begin(), expected_bytes.end());
180 EXPECT_EQ(bytes, expected_bytes);
181 EXPECT_FALSE(truncated);
183 TestTraceContainer
trace({
184 { { C::precomputed_first_row, 1 } },
190 check_relation<to_radix>(trace);
193TEST(ToRadixConstrainingTest, ToLeRadixPMinusOne)
195 EventEmitter<ToRadixEvent> to_radix_event_emitter;
196 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
200 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
203 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
value, 32, 256);
207 std::reverse(expected_bytes.begin(), expected_bytes.end());
208 EXPECT_EQ(bytes, expected_bytes);
209 EXPECT_FALSE(truncated);
211 TestTraceContainer
trace({
212 { { C::precomputed_first_row, 1 } },
218 check_relation<to_radix>(trace);
221TEST(ToRadixConstrainingTest, ToLeRadixOneByte)
223 EventEmitter<ToRadixEvent> to_radix_event_emitter;
224 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
228 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
230 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
FF::one(), 1, 256);
232 std::vector<uint8_t> expected_bytes = { 1 };
233 EXPECT_EQ(bytes, expected_bytes);
234 EXPECT_FALSE(truncated);
236 TestTraceContainer
trace({
237 { { C::precomputed_first_row, 1 } },
243 check_relation<to_radix>(trace);
246TEST(ToRadixConstrainingTest, ToLeRadixPadded)
248 EventEmitter<ToRadixEvent> to_radix_event_emitter;
249 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
253 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
256 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
value, 64, 256);
260 std::reverse(expected_bytes.begin(), expected_bytes.end());
261 expected_bytes.resize(64);
262 EXPECT_EQ(bytes, expected_bytes);
263 EXPECT_FALSE(truncated);
265 TestTraceContainer
trace({
266 { { C::precomputed_first_row, 1 } },
272 check_relation<to_radix>(trace);
275TEST(ToRadixConstrainingTest, ToLeBitsInteractions)
277 EventEmitter<ToRadixEvent> to_radix_event_emitter;
278 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
282 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
286 TestTraceContainer
trace({
287 { { C::precomputed_first_row, 1 } },
290 ToRadixTraceBuilder to_radix_builder;
291 to_radix_builder.process(to_radix_event_emitter.dump_events(), trace);
305 check_relation<to_radix>(trace);
308TEST(ToRadixConstrainingTest, ToLeRadixInteractions)
310 EventEmitter<ToRadixEvent> to_radix_event_emitter;
311 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
315 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
317 to_radix_simulator.to_le_radix(
FF::neg_one(), 32, 256);
319 TestTraceContainer
trace({
320 { { C::precomputed_first_row, 1 } },
323 ToRadixTraceBuilder to_radix_builder;
324 to_radix_builder.process(to_radix_event_emitter.dump_events(), trace);
339 check_relation<to_radix>(trace);
342TEST(ToRadixConstrainingTest, NegativeOverflowCheck)
344 TestTraceContainer
trace({
345 { { C::precomputed_first_row, 1 } },
348 std::vector<uint8_t> modulus_le_bits(256, 0);
349 for (
size_t i = 0; i < 256; i++) {
353 ToRadixEvent
event = { .value =
FF::zero(), .radix = 2, .limbs = modulus_le_bits };
363TEST(ToRadixConstrainingTest, NegativeConsistency)
365 EventEmitter<ToRadixEvent> to_radix_event_emitter;
366 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
370 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
372 to_radix_simulator.to_le_radix(
FF(256), 32, 256);
374 TestTraceContainer
trace({
375 { { C::precomputed_first_row, 1 } },
382 trace.
set(Column::to_radix_sel, 6, 0);
388 trace.
set(Column::to_radix_radix, 5, 200);
394 trace.
set(Column::to_radix_value, 4, 27);
400 trace.
set(Column::to_radix_safe_limbs, 3, 200);
410TEST(ToRadixMemoryConstrainingTest, EmptyRow)
415TEST(ToRadixMemoryConstrainingTest, BasicTest)
420 uint32_t num_limbs = 4;
423 TestTraceContainer
trace = TestTraceContainer({
426 { C::precomputed_first_row, 1 },
429 { C::gt_input_a,
dst_addr + num_limbs },
430 { C::gt_input_b, MAX_MEM },
436 { C::execution_sel, 1 },
437 { C::execution_sel_exec_dispatch_to_radix, 1 },
438 { C::execution_register_0_,
value },
439 { C::execution_register_1_, radix },
440 { C::execution_register_2_, num_limbs },
441 { C::execution_register_3_, 0 },
444 { C::to_radix_mem_sel, 1 },
445 { C::to_radix_mem_max_mem_size, MAX_MEM },
446 { C::to_radix_mem_two, 2 },
447 { C::to_radix_mem_two_five_six, 256 },
449 { C::to_radix_mem_execution_clk, 0 },
450 { C::to_radix_mem_space_id, 0 },
451 { C::to_radix_mem_dst_addr,
dst_addr },
452 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
454 { C::to_radix_mem_value_to_decompose,
value },
455 { C::to_radix_mem_radix, radix },
456 { C::to_radix_mem_num_limbs, num_limbs },
457 { C::to_radix_mem_is_output_bits, 0 },
459 { C::to_radix_mem_start, 1 },
460 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
462 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
463 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
464 { C::to_radix_mem_sel_value_is_zero, 0 },
466 { C::to_radix_mem_sel_radix_eq_2, 0 },
467 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
469 { C::to_radix_mem_limb_value, 1 },
470 { C::to_radix_mem_sel_should_decompose, 1 },
471 { C::to_radix_mem_sel_should_write_mem, 1 },
472 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
473 { C::to_radix_mem_value_found, 1 },
474 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
478 { C::gt_input_a, 2 },
479 { C::gt_input_b, radix },
484 { C::to_radix_mem_sel, 1 },
486 { C::to_radix_mem_execution_clk, 0 },
487 { C::to_radix_mem_space_id, 0 },
488 { C::to_radix_mem_dst_addr,
dst_addr + 1 },
490 { C::to_radix_mem_value_to_decompose,
value },
491 { C::to_radix_mem_radix, radix },
492 { C::to_radix_mem_num_limbs, num_limbs - 1 },
493 { C::to_radix_mem_is_output_bits, 0 },
496 { C::to_radix_mem_num_limbs_minus_one_inv,
FF(num_limbs - 2).
invert() },
498 { C::to_radix_mem_limb_value, 3 },
499 { C::to_radix_mem_sel_should_decompose, 1 },
500 { C::to_radix_mem_sel_should_write_mem, 1 },
501 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 2 },
502 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
505 { C::gt_input_a, radix },
506 { C::gt_input_b, 256 },
511 { C::to_radix_mem_sel, 1 },
513 { C::to_radix_mem_execution_clk, 0 },
514 { C::to_radix_mem_space_id, 0 },
515 { C::to_radix_mem_dst_addr,
dst_addr + 2 },
517 { C::to_radix_mem_value_to_decompose,
value },
518 { C::to_radix_mem_radix, radix },
519 { C::to_radix_mem_num_limbs, num_limbs - 2 },
520 { C::to_radix_mem_is_output_bits, 0 },
523 { C::to_radix_mem_num_limbs_minus_one_inv,
FF(num_limbs - 3).
invert() },
525 { C::to_radix_mem_limb_value, 3 },
526 { C::to_radix_mem_sel_should_decompose, 1 },
527 { C::to_radix_mem_sel_should_write_mem, 1 },
528 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 3 },
529 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
533 { C::to_radix_mem_sel, 1 },
535 { C::to_radix_mem_execution_clk, 0 },
536 { C::to_radix_mem_space_id, 0 },
537 { C::to_radix_mem_dst_addr, 13 },
539 { C::to_radix_mem_value_to_decompose,
value },
540 { C::to_radix_mem_radix, radix },
541 { C::to_radix_mem_num_limbs, num_limbs - 3 },
542 { C::to_radix_mem_is_output_bits, 0 },
544 { C::to_radix_mem_last, 1 },
546 { C::to_radix_mem_limb_value, 7 },
547 { C::to_radix_mem_sel_should_decompose, 1 },
548 { C::to_radix_mem_sel_should_write_mem, 1 },
549 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 4 },
550 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
561 { value_addr, MemoryValue::from<FF>(
value) },
562 { radix_addr, MemoryValue::from<uint32_t>(radix) },
563 { num_limbs_addr, MemoryValue::from<uint32_t>(num_limbs) },
564 { is_output_bits_addr, MemoryValue::from<uint1_t>(
false) },
565 {
dst_addr, MemoryValue::from<uint8_t>(1) },
566 {
dst_addr + 1, MemoryValue::from<uint8_t>(3) },
567 {
dst_addr + 2, MemoryValue::from<uint8_t>(3) },
568 {
dst_addr + 3, MemoryValue::from<uint8_t>(7) },
571 for (uint32_t i = 0; i < memory_values.size(); ++i) {
572 const auto& [addr,
value] = memory_values[i];
575 { { C::memory_sel, 1 },
576 { C::memory_space_id, 0 },
577 { C::memory_address, addr },
578 { C::memory_value,
value.as_ff() },
579 { C::memory_tag,
static_cast<uint8_t
>(
value.get_tag()) },
580 { C::memory_rw, i > 3 ? 1 : 0 } },
584 EventEmitter<ToRadixEvent> to_radix_event_emitter;
585 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
589 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
592 to_radix_simulator.to_le_radix(
value, num_limbs, radix);
595 auto events = to_radix_event_emitter.get_events();
603 check_relation<to_radix_mem>(trace);
604 check_all_interactions<ToRadixTraceBuilder>(trace);
607 trace.
set(Column::to_radix_mem_sel_should_write_mem, 2, 0);
612 trace.
set(Column::to_radix_mem_sel_should_decompose, 2, 0);
617TEST(ToRadixMemoryConstrainingTest, DstOutOfRange)
622 uint32_t num_limbs = 2;
623 auto dst_addr =
static_cast<uint64_t
>(MAX_MEM - 1);
625 TestTraceContainer
trace = TestTraceContainer({
628 { C::precomputed_first_row, 1 },
631 { C::gt_input_a,
dst_addr + num_limbs },
632 { C::gt_input_b, MAX_MEM },
638 { C::execution_sel, 1 },
639 { C::execution_sel_exec_dispatch_to_radix, 1 },
640 { C::execution_register_0_,
value },
641 { C::execution_register_1_, radix },
642 { C::execution_register_2_, num_limbs },
643 { C::execution_register_3_, 0 },
645 { C::execution_sel_opcode_error, 1 },
648 { C::to_radix_mem_sel, 1 },
649 { C::to_radix_mem_max_mem_size, MAX_MEM },
650 { C::to_radix_mem_two, 2 },
651 { C::to_radix_mem_two_five_six, 256 },
653 { C::to_radix_mem_execution_clk, 0 },
654 { C::to_radix_mem_space_id, 0 },
655 { C::to_radix_mem_dst_addr,
dst_addr },
656 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
658 { C::to_radix_mem_value_to_decompose,
value },
659 { C::to_radix_mem_radix, radix },
660 { C::to_radix_mem_num_limbs, num_limbs },
661 { C::to_radix_mem_is_output_bits, 0 },
663 { C::to_radix_mem_sel_dst_out_of_range_err, 1 },
664 { C::to_radix_mem_input_validation_error, 1 },
665 { C::to_radix_mem_err, 1 },
667 { C::to_radix_mem_start, 1 },
668 { C::to_radix_mem_last, 1 },
669 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
671 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
672 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
673 { C::to_radix_mem_sel_value_is_zero, 0 },
675 { C::to_radix_mem_sel_radix_eq_2, 0 },
676 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
680 check_relation<to_radix_mem>(trace);
681 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_dst_addr_in_range_settings>(trace);
682 check_interaction<ExecutionTraceBuilder, perm_execution_dispatch_to_to_radix_settings>(trace);
685TEST(ToRadixMemoryConstrainingTest, InvalidRadix)
690 uint32_t num_limbs = 2;
693 TestTraceContainer
trace = TestTraceContainer({
696 { C::precomputed_first_row, 1 },
699 { C::gt_input_a, 2 },
700 { C::gt_input_b, radix },
705 { C::to_radix_mem_sel, 1 },
706 { C::to_radix_mem_max_mem_size, MAX_MEM },
707 { C::to_radix_mem_two, 2 },
708 { C::to_radix_mem_two_five_six, 256 },
710 { C::to_radix_mem_execution_clk, 0 },
711 { C::to_radix_mem_space_id, 0 },
712 { C::to_radix_mem_dst_addr,
dst_addr },
713 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
715 { C::to_radix_mem_value_to_decompose,
value },
716 { C::to_radix_mem_radix, radix },
717 { C::to_radix_mem_num_limbs, num_limbs },
718 { C::to_radix_mem_is_output_bits, 0 },
720 { C::to_radix_mem_sel_radix_lt_2_err, 1 },
721 { C::to_radix_mem_input_validation_error, 1 },
722 { C::to_radix_mem_err, 1 },
724 { C::to_radix_mem_start, 1 },
725 { C::to_radix_mem_last, 1 },
726 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
728 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
729 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
730 { C::to_radix_mem_sel_value_is_zero, 0 },
732 { C::to_radix_mem_sel_radix_eq_2, 0 },
733 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
736 check_relation<to_radix_mem>(trace);
737 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
740TEST(ToRadixMemoryConstrainingTest, InvalidBitwiseRadix)
745 uint32_t num_limbs = 2;
749 TestTraceContainer
trace = TestTraceContainer({
752 { C::precomputed_first_row, 1 },
755 { C::gt_input_a, 2 },
756 { C::gt_input_b, radix },
761 { C::to_radix_mem_sel, 1 },
762 { C::to_radix_mem_max_mem_size, MAX_MEM },
763 { C::to_radix_mem_two, 2 },
764 { C::to_radix_mem_two_five_six, 256 },
766 { C::to_radix_mem_execution_clk, 0 },
767 { C::to_radix_mem_space_id, 0 },
768 { C::to_radix_mem_dst_addr,
dst_addr },
769 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
771 { C::to_radix_mem_value_to_decompose,
value },
772 { C::to_radix_mem_radix, radix },
773 { C::to_radix_mem_num_limbs, num_limbs },
776 { C::to_radix_mem_sel_invalid_bitwise_radix, 1 },
777 { C::to_radix_mem_input_validation_error, 1 },
778 { C::to_radix_mem_err, 1 },
780 { C::to_radix_mem_start, 1 },
781 { C::to_radix_mem_last, 1 },
782 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
784 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
785 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
786 { C::to_radix_mem_sel_value_is_zero, 0 },
788 { C::to_radix_mem_sel_radix_eq_2, 0 },
789 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
792 check_relation<to_radix_mem>(trace);
793 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
796TEST(ToRadixMemoryConstrainingTest, InvalidNumLimbsForValue)
801 uint32_t num_limbs = 0;
805 TestTraceContainer
trace = TestTraceContainer({
808 { C::precomputed_first_row, 1 },
811 { C::gt_input_a, 2 },
812 { C::gt_input_b, radix },
817 { C::to_radix_mem_sel, 1 },
818 { C::to_radix_mem_max_mem_size, MAX_MEM },
819 { C::to_radix_mem_two, 2 },
820 { C::to_radix_mem_two_five_six, 256 },
822 { C::to_radix_mem_execution_clk, 0 },
823 { C::to_radix_mem_space_id, 0 },
824 { C::to_radix_mem_dst_addr,
dst_addr },
825 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
827 { C::to_radix_mem_value_to_decompose,
value },
828 { C::to_radix_mem_radix, radix },
829 { C::to_radix_mem_num_limbs, num_limbs },
832 { C::to_radix_mem_input_validation_error, 1 },
833 { C::to_radix_mem_err, 1 },
835 { C::to_radix_mem_start, 1 },
836 { C::to_radix_mem_last, 1 },
837 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
839 { C::to_radix_mem_sel_num_limbs_is_zero, 1 },
840 { C::to_radix_mem_num_limbs_inv, 0 },
841 { C::to_radix_mem_sel_value_is_zero, 0 },
843 { C::to_radix_mem_sel_radix_eq_2, 0 },
844 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
847 check_relation<to_radix_mem>(trace);
848 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
851TEST(ToRadixMemoryConstrainingTest, TruncationError)
856 uint32_t num_limbs = 3;
860 TestTraceContainer
trace = TestTraceContainer({
863 { C::precomputed_first_row, 1 },
866 { C::gt_input_a, 2 },
867 { C::gt_input_b, radix },
872 { C::to_radix_mem_sel, 1 },
873 { C::to_radix_mem_max_mem_size, MAX_MEM },
874 { C::to_radix_mem_two, 2 },
875 { C::to_radix_mem_two_five_six, 256 },
877 { C::to_radix_mem_execution_clk, 0 },
878 { C::to_radix_mem_space_id, 0 },
879 { C::to_radix_mem_dst_addr,
dst_addr },
880 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
882 { C::to_radix_mem_value_to_decompose,
value },
883 { C::to_radix_mem_radix, radix },
884 { C::to_radix_mem_num_limbs, num_limbs },
887 { C::to_radix_mem_err, 1 },
889 { C::to_radix_mem_start, 1 },
890 { C::to_radix_mem_last, 1 },
891 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
893 { C::to_radix_mem_sel_should_decompose, 1 },
894 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
895 { C::to_radix_mem_limb_value, 3 },
896 { C::to_radix_mem_value_found, 0 },
898 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
899 { C::to_radix_mem_sel_value_is_zero, 0 },
901 { C::to_radix_mem_sel_radix_eq_2, 0 },
902 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
905 check_relation<to_radix_mem>(trace);
906 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
909 trace.
set(C::to_radix_mem_err, 1, 0);
912 trace.
set(C::to_radix_mem_err, 1, 1);
915 trace.
set(C::to_radix_mem_value_found, 1, 1);
920TEST(ToRadixMemoryConstrainingTest, ZeroNumLimbsAndZeroValueIsNoop)
925 uint32_t num_limbs = 0;
929 TestTraceContainer
trace = TestTraceContainer({
932 { C::precomputed_first_row, 1 },
935 { C::gt_input_a, 2 },
936 { C::gt_input_b, radix },
941 { C::to_radix_mem_sel, 1 },
942 { C::to_radix_mem_max_mem_size, MAX_MEM },
943 { C::to_radix_mem_two, 2 },
944 { C::to_radix_mem_two_five_six, 256 },
946 { C::to_radix_mem_execution_clk, 0 },
947 { C::to_radix_mem_space_id, 0 },
948 { C::to_radix_mem_dst_addr,
dst_addr },
949 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
951 { C::to_radix_mem_value_to_decompose,
value },
952 { C::to_radix_mem_radix, radix },
953 { C::to_radix_mem_num_limbs, num_limbs },
956 { C::to_radix_mem_start, 1 },
957 { C::to_radix_mem_last, 1 },
958 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
960 { C::to_radix_mem_sel_num_limbs_is_zero, 1 },
961 { C::to_radix_mem_num_limbs_inv, 0 },
962 { C::to_radix_mem_sel_value_is_zero, 1 },
963 { C::to_radix_mem_value_inv, 0 },
964 { C::to_radix_mem_sel_radix_eq_2, 0 },
965 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
968 check_relation<to_radix_mem>(trace);
969 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
972TEST(ToRadixMemoryConstrainingTest, ComplexTest)
974 EventEmitter<ToRadixEvent> to_radix_event_emitter;
975 EventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
979 simulation::MemoryStore
memory;
981 StrictMock<MockFieldGreaterThan>
field_gt;
985 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
989 uint32_t num_limbs = 256;
994 to_radix_simulator.to_be_radix(
995 memory,
FF(1337), 10, 6,
false, 0xdeadbeef);
997 TestTraceContainer
trace;
1000 builder.process_with_memory(to_radix_mem_event_emitter.dump_events(), trace);
1010 check_relation<to_radix>(trace);
1011 check_relation<to_radix_mem>(trace);
1034TEST(ToRadixMemoryConstrainingTest, NegativeGhostRowMemoryWrite_RelationsOnly)
1038 TestTraceContainer
trace({
1040 { C::precomputed_first_row, 1 },
1043 { C::to_radix_mem_sel, 0 },
1044 { C::to_radix_mem_sel_should_write_mem, 1 },
1045 { C::to_radix_mem_execution_clk, 1 },
1046 { C::to_radix_mem_space_id, 1 },
1047 { C::to_radix_mem_dst_addr, 100 },
1048 { C::to_radix_mem_limb_value, 999 },
1049 { C::to_radix_mem_output_tag, 2 },
1065TEST(ToRadixMemoryConstrainingTest, NegativeGhostRowInjectionBlocked)
1067 TestTraceContainer
trace;
1068 MemoryTraceBuilder memory_trace_builder;
1069 PrecomputedTraceBuilder precomputed_trace_builder;
1072 uint32_t malicious_clk = 42;
1073 uint16_t malicious_space_id = 1;
1075 uint8_t malicious_limb_value = 0x99;
1081 .execution_clk = malicious_clk,
1083 .addr = malicious_addr,
1085 .space_id = malicious_space_id,
1090 precomputed_trace_builder.process_sel_range_8(trace);
1091 precomputed_trace_builder.process_sel_range_16(trace);
1092 precomputed_trace_builder.process_misc(trace, 1 << 16);
1093 precomputed_trace_builder.process_tag_parameters(trace);
1094 memory_trace_builder.process(mem_events, trace);
1097 uint32_t memory_row = 0;
1099 if (
trace.
get(C::memory_sel, row) == 1) {
1107 uint32_t ghost_row = 0;
1110 { C::precomputed_first_row, 1 },
1111 { C::execution_clk, ghost_row },
1112 { C::to_radix_mem_sel, 0 },
1113 { C::to_radix_mem_sel_should_write_mem, 1 },
1114 { C::to_radix_mem_execution_clk, malicious_clk },
1115 { C::to_radix_mem_space_id, malicious_space_id },
1116 { C::to_radix_mem_dst_addr, malicious_addr },
1117 { C::to_radix_mem_limb_value, malicious_limb_value },
1118 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(malicious_tag) },
1121 trace.
set(C::memory_sel_to_radix_write, memory_row, 1);
1129TEST(ToRadixMemoryConstrainingTest, NegativeBitwiseRadixError)
1131 TestTraceContainer
trace({
1133 { C::to_radix_mem_start, 1 },
1134 { C::to_radix_mem_sel, 1 },
1135 { C::to_radix_mem_sel_radix_eq_2, 1 },
1136 { C::to_radix_mem_is_output_bits, 1 },
1143 trace.
set(C::to_radix_mem_sel_invalid_bitwise_radix, 0, 1);
1150TEST(ToRadixMemoryConstrainingTest, NegativeBitwiseRadixNoError)
1152 TestTraceContainer
trace({
1154 { C::to_radix_mem_start, 1 },
1155 { C::to_radix_mem_sel, 1 },
1156 { C::to_radix_mem_sel_radix_eq_2, 0 },
1157 { C::to_radix_mem_is_output_bits, 1 },
1158 { C::to_radix_mem_sel_invalid_bitwise_radix, 1 },
1165 trace.
set(C::to_radix_mem_sel_invalid_bitwise_radix, 0, 0);
DeduplicatingEventEmitter< GreaterThanEvent > gt_emitter
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
FieldGreaterThan field_gt
EventEmitter< simulation::RangeCheckEvent > range_check_emitter
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_ERR_COMPUTATION
static constexpr size_t SR_SEL_SHOULD_WRITE_MEM_REQUIRES_SEL
static std::string get_subrelation_label(size_t index)
static constexpr size_t SR_IS_OUTPUT_BITS_IMPLY_RADIX_2
static constexpr size_t SR_TRACE_CONTINUITY
static constexpr size_t SR_RADIX_CONTINUITY
static constexpr size_t SR_VALUE_CONTINUITY
static constexpr size_t SR_OVERFLOW_CHECK
static std::string get_subrelation_label(size_t index)
static constexpr size_t SR_SAFE_LIMBS_CONTINUITY
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)
Process the greater-than events and populate the relevant columns in the trace.
void process_to_radix_p_decompositions(TraceContainer &trace)
Populate the TORADIXBE p-decomposition table.
void process_misc(TraceContainer &trace, const uint32_t num_rows=PRECOMPUTED_TRACE_SIZE)
Populate miscellaneous precomputed columns: first_row selector and idx (row index).
void process_to_radix_safe_limbs(TraceContainer &trace)
Populate the TORADIXBE safe-limbs table (one row per radix 0..255).
void process_sel_range_8(TraceContainer &trace)
Generate a selector column that activates the first 2^8 (256) rows.
const FF & get(Column col, uint32_t row) const
uint32_t get_num_rows() const
void set(Column col, uint32_t row, const FF &value, bool use_atomic_limbs=false)
constexpr bool get_bit(uint64_t bit_index) const
PrecomputedTraceBuilder precomputed_builder
GreaterThanTraceBuilder gt_builder
ExecutionIdManager execution_id_manager
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()
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
constexpr size_t NUM_RADIXES
lookup_settings< lookup_to_radix_mem_input_output_to_radix_settings_ > lookup_to_radix_mem_input_output_to_radix_settings
lookup_settings< lookup_to_radix_fetch_p_limb_settings_ > lookup_to_radix_fetch_p_limb_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
static constexpr field neg_one()
static constexpr field one()
static constexpr uint256_t modulus
constexpr field invert() const noexcept
BB_INLINE std::vector< uint8_t > to_buffer() const
static constexpr field zero()