2#include <gmock/gmock.h>
3#include <gtest/gtest.h>
33using ::testing::Return;
34using ::testing::StrictMock;
36using tracegen::ExecutionTraceBuilder;
37using tracegen::GreaterThanTraceBuilder;
38using tracegen::MemoryTraceBuilder;
39using tracegen::PrecomputedTraceBuilder;
40using tracegen::TestTraceContainer;
41using tracegen::ToRadixTraceBuilder;
47using ToRadixSimulator = simulation::ToRadix;
49using simulation::EventEmitter;
50using simulation::GreaterThan;
51using simulation::GreaterThanEvent;
52using simulation::MockExecutionIdManager;
53using simulation::MockFieldGreaterThan;
54using simulation::NoopEventEmitter;
55using simulation::PureGreaterThan;
56using simulation::RangeCheck;
57using simulation::RangeCheckEvent;
58using simulation::ToRadixEvent;
59using simulation::ToRadixMemoryEvent;
63TEST(ToRadixConstrainingTest, EmptyRow)
68TEST(ToRadixConstrainingTest, ToLeBitsBasicTest)
70 EventEmitter<ToRadixEvent> to_radix_event_emitter;
71 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
75 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
77 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::one(), 254);
79 EXPECT_EQ(bits.size(), 254);
80 EXPECT_FALSE(truncated);
82 TestTraceContainer
trace({
83 { { C::precomputed_first_row, 1 } },
89 check_relation<to_radix>(trace);
92TEST(ToRadixConstrainingTest, ToLeBitsPMinusOne)
94 EventEmitter<ToRadixEvent> to_radix_event_emitter;
95 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
99 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
101 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::neg_one(), 254);
103 EXPECT_EQ(bits.size(), 254);
104 EXPECT_FALSE(truncated);
106 TestTraceContainer
trace({
107 { { C::precomputed_first_row, 1 } },
113 check_relation<to_radix>(trace);
116TEST(ToRadixConstrainingTest, ToLeBitsShortest)
118 EventEmitter<ToRadixEvent> to_radix_event_emitter;
119 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
123 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
125 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::one(), 1);
127 EXPECT_EQ(bits.size(), 1);
128 EXPECT_FALSE(truncated);
130 TestTraceContainer
trace({
131 { { C::precomputed_first_row, 1 } },
137 check_relation<to_radix>(trace);
140TEST(ToRadixConstrainingTest, ToLeBitsPadded)
142 EventEmitter<ToRadixEvent> to_radix_event_emitter;
143 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
147 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
149 auto [bits, truncated] = to_radix_simulator.to_le_bits(
FF::one(), 500);
151 EXPECT_EQ(bits.size(), 500);
152 EXPECT_FALSE(truncated);
154 TestTraceContainer
trace({
155 { { C::precomputed_first_row, 1 } },
161 check_relation<to_radix>(trace);
164TEST(ToRadixConstrainingTest, ToLeRadixBasic)
166 EventEmitter<ToRadixEvent> to_radix_event_emitter;
167 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
171 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
174 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
value, 32, 256);
178 std::reverse(expected_bytes.begin(), expected_bytes.end());
179 EXPECT_EQ(bytes, expected_bytes);
180 EXPECT_FALSE(truncated);
182 TestTraceContainer
trace({
183 { { C::precomputed_first_row, 1 } },
189 check_relation<to_radix>(trace);
192TEST(ToRadixConstrainingTest, ToLeRadixPMinusOne)
194 EventEmitter<ToRadixEvent> to_radix_event_emitter;
195 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
199 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
202 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
value, 32, 256);
206 std::reverse(expected_bytes.begin(), expected_bytes.end());
207 EXPECT_EQ(bytes, expected_bytes);
208 EXPECT_FALSE(truncated);
210 TestTraceContainer
trace({
211 { { C::precomputed_first_row, 1 } },
217 check_relation<to_radix>(trace);
220TEST(ToRadixConstrainingTest, ToLeRadixOneByte)
222 EventEmitter<ToRadixEvent> to_radix_event_emitter;
223 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
227 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
229 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
FF::one(), 1, 256);
231 std::vector<uint8_t> expected_bytes = { 1 };
232 EXPECT_EQ(bytes, expected_bytes);
233 EXPECT_FALSE(truncated);
235 TestTraceContainer
trace({
236 { { C::precomputed_first_row, 1 } },
242 check_relation<to_radix>(trace);
245TEST(ToRadixConstrainingTest, ToLeRadixPadded)
247 EventEmitter<ToRadixEvent> to_radix_event_emitter;
248 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
252 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
255 auto [bytes, truncated] = to_radix_simulator.to_le_radix(
value, 64, 256);
259 std::reverse(expected_bytes.begin(), expected_bytes.end());
260 expected_bytes.resize(64);
261 EXPECT_EQ(bytes, expected_bytes);
262 EXPECT_FALSE(truncated);
264 TestTraceContainer
trace({
265 { { C::precomputed_first_row, 1 } },
271 check_relation<to_radix>(trace);
274TEST(ToRadixConstrainingTest, ToLeBitsInteractions)
276 EventEmitter<ToRadixEvent> to_radix_event_emitter;
277 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
281 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
285 TestTraceContainer
trace({
286 { { C::precomputed_first_row, 1 } },
289 ToRadixTraceBuilder to_radix_builder;
290 to_radix_builder.process(to_radix_event_emitter.dump_events(), trace);
304 check_relation<to_radix>(trace);
307TEST(ToRadixConstrainingTest, ToLeRadixInteractions)
309 EventEmitter<ToRadixEvent> to_radix_event_emitter;
310 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
314 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
316 to_radix_simulator.to_le_radix(
FF::neg_one(), 32, 256);
318 TestTraceContainer
trace({
319 { { C::precomputed_first_row, 1 } },
322 ToRadixTraceBuilder to_radix_builder;
323 to_radix_builder.process(to_radix_event_emitter.dump_events(), trace);
338 check_relation<to_radix>(trace);
341TEST(ToRadixConstrainingTest, NegativeOverflowCheck)
343 TestTraceContainer
trace({
344 { { C::precomputed_first_row, 1 } },
347 std::vector<uint8_t> modulus_le_bits(256, 0);
348 for (
size_t i = 0; i < 256; i++) {
352 ToRadixEvent
event = { .value =
FF::zero(), .radix = 2, .limbs = modulus_le_bits };
361TEST(ToRadixConstrainingTest, NegativeConsistency)
363 EventEmitter<ToRadixEvent> to_radix_event_emitter;
364 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
368 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
370 to_radix_simulator.to_le_radix(
FF(256), 32, 256);
372 TestTraceContainer
trace({
373 { { C::precomputed_first_row, 1 } },
380 trace.
set(Column::to_radix_sel, 6, 0);
385 trace.
set(Column::to_radix_radix, 5, 200);
390 trace.
set(Column::to_radix_value, 4, 27);
395 trace.
set(Column::to_radix_safe_limbs, 3, 200);
398 "SAFE_LIMBS_CONTINUITY");
405TEST(ToRadixMemoryConstrainingTest, EmptyRow)
410TEST(ToRadixMemoryConstrainingTest, BasicTest)
415 uint32_t num_limbs = 4;
418 TestTraceContainer
trace = TestTraceContainer({
421 { C::precomputed_first_row, 1 },
424 { C::gt_input_a,
dst_addr + num_limbs },
425 { C::gt_input_b, MAX_MEM },
431 { C::execution_sel, 1 },
432 { C::execution_sel_exec_dispatch_to_radix, 1 },
433 { C::execution_register_0_,
value },
434 { C::execution_register_1_, radix },
435 { C::execution_register_2_, num_limbs },
436 { C::execution_register_3_, 0 },
439 { C::to_radix_mem_sel, 1 },
440 { C::to_radix_mem_max_mem_size, MAX_MEM },
441 { C::to_radix_mem_two, 2 },
442 { C::to_radix_mem_two_five_six, 256 },
444 { C::to_radix_mem_execution_clk, 0 },
445 { C::to_radix_mem_space_id, 0 },
446 { C::to_radix_mem_dst_addr,
dst_addr },
447 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
449 { C::to_radix_mem_value_to_decompose,
value },
450 { C::to_radix_mem_radix, radix },
451 { C::to_radix_mem_num_limbs, num_limbs },
452 { C::to_radix_mem_is_output_bits, 0 },
454 { C::to_radix_mem_start, 1 },
455 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
457 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
458 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
459 { C::to_radix_mem_sel_value_is_zero, 0 },
461 { C::to_radix_mem_sel_radix_eq_2, 0 },
462 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
464 { C::to_radix_mem_limb_value, 1 },
465 { C::to_radix_mem_sel_should_decompose, 1 },
466 { C::to_radix_mem_sel_should_write_mem, 1 },
467 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
468 { C::to_radix_mem_value_found, 1 },
469 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
473 { C::gt_input_a, 2 },
474 { C::gt_input_b, radix },
479 { C::to_radix_mem_sel, 1 },
481 { C::to_radix_mem_execution_clk, 0 },
482 { C::to_radix_mem_space_id, 0 },
483 { C::to_radix_mem_dst_addr,
dst_addr + 1 },
485 { C::to_radix_mem_value_to_decompose,
value },
486 { C::to_radix_mem_radix, radix },
487 { C::to_radix_mem_num_limbs, num_limbs - 1 },
488 { C::to_radix_mem_is_output_bits, 0 },
491 { C::to_radix_mem_num_limbs_minus_one_inv,
FF(num_limbs - 2).
invert() },
493 { C::to_radix_mem_limb_value, 3 },
494 { C::to_radix_mem_sel_should_decompose, 1 },
495 { C::to_radix_mem_sel_should_write_mem, 1 },
496 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 2 },
497 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
500 { C::gt_input_a, radix },
501 { C::gt_input_b, 256 },
506 { C::to_radix_mem_sel, 1 },
508 { C::to_radix_mem_execution_clk, 0 },
509 { C::to_radix_mem_space_id, 0 },
510 { C::to_radix_mem_dst_addr,
dst_addr + 2 },
512 { C::to_radix_mem_value_to_decompose,
value },
513 { C::to_radix_mem_radix, radix },
514 { C::to_radix_mem_num_limbs, num_limbs - 2 },
515 { C::to_radix_mem_is_output_bits, 0 },
518 { C::to_radix_mem_num_limbs_minus_one_inv,
FF(num_limbs - 3).
invert() },
520 { C::to_radix_mem_limb_value, 3 },
521 { C::to_radix_mem_sel_should_decompose, 1 },
522 { C::to_radix_mem_sel_should_write_mem, 1 },
523 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 3 },
524 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
528 { C::to_radix_mem_sel, 1 },
530 { C::to_radix_mem_execution_clk, 0 },
531 { C::to_radix_mem_space_id, 0 },
532 { C::to_radix_mem_dst_addr, 13 },
534 { C::to_radix_mem_value_to_decompose,
value },
535 { C::to_radix_mem_radix, radix },
536 { C::to_radix_mem_num_limbs, num_limbs - 3 },
537 { C::to_radix_mem_is_output_bits, 0 },
539 { C::to_radix_mem_last, 1 },
541 { C::to_radix_mem_limb_value, 7 },
542 { C::to_radix_mem_sel_should_decompose, 1 },
543 { C::to_radix_mem_sel_should_write_mem, 1 },
544 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 4 },
545 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(
MemoryTag::U8) },
556 { value_addr, MemoryValue::from<FF>(
value) },
557 { radix_addr, MemoryValue::from<uint32_t>(radix) },
558 { num_limbs_addr, MemoryValue::from<uint32_t>(num_limbs) },
559 { is_output_bits_addr, MemoryValue::from<uint1_t>(
false) },
560 {
dst_addr, MemoryValue::from<uint8_t>(1) },
561 {
dst_addr + 1, MemoryValue::from<uint8_t>(3) },
562 {
dst_addr + 2, MemoryValue::from<uint8_t>(3) },
563 {
dst_addr + 3, MemoryValue::from<uint8_t>(7) },
566 for (uint32_t i = 0; i < memory_values.size(); ++i) {
567 const auto& [addr,
value] = memory_values[i];
570 { { C::memory_sel, 1 },
571 { C::memory_space_id, 0 },
572 { C::memory_address, addr },
573 { C::memory_value,
value.as_ff() },
574 { C::memory_tag,
static_cast<uint8_t
>(
value.get_tag()) },
575 { C::memory_rw, i > 3 ? 1 : 0 } },
579 EventEmitter<ToRadixEvent> to_radix_event_emitter;
580 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
584 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
587 to_radix_simulator.to_le_radix(
value, num_limbs, radix);
590 auto events = to_radix_event_emitter.get_events();
598 check_relation<to_radix_mem>(trace);
599 check_all_interactions<ToRadixTraceBuilder>(trace);
602 trace.
set(Column::to_radix_mem_sel_should_write_mem, 2, 0);
604 "SEL_SHOULD_WRITE_MEM_CONTINUITY");
607 trace.
set(Column::to_radix_mem_sel_should_decompose, 2, 0);
609 "SEL_SHOULD_DECOMPOSE_CONTINUITY");
612TEST(ToRadixMemoryConstrainingTest, DstOutOfRange)
617 uint32_t num_limbs = 2;
618 auto dst_addr =
static_cast<uint64_t
>(MAX_MEM - 1);
620 TestTraceContainer
trace = TestTraceContainer({
623 { C::precomputed_first_row, 1 },
626 { C::gt_input_a,
dst_addr + num_limbs },
627 { C::gt_input_b, MAX_MEM },
633 { C::execution_sel, 1 },
634 { C::execution_sel_exec_dispatch_to_radix, 1 },
635 { C::execution_register_0_,
value },
636 { C::execution_register_1_, radix },
637 { C::execution_register_2_, num_limbs },
638 { C::execution_register_3_, 0 },
640 { C::execution_sel_opcode_error, 1 },
643 { C::to_radix_mem_sel, 1 },
644 { C::to_radix_mem_max_mem_size, MAX_MEM },
645 { C::to_radix_mem_two, 2 },
646 { C::to_radix_mem_two_five_six, 256 },
648 { C::to_radix_mem_execution_clk, 0 },
649 { C::to_radix_mem_space_id, 0 },
650 { C::to_radix_mem_dst_addr,
dst_addr },
651 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
653 { C::to_radix_mem_value_to_decompose,
value },
654 { C::to_radix_mem_radix, radix },
655 { C::to_radix_mem_num_limbs, num_limbs },
656 { C::to_radix_mem_is_output_bits, 0 },
658 { C::to_radix_mem_sel_dst_out_of_range_err, 1 },
659 { C::to_radix_mem_input_validation_error, 1 },
660 { C::to_radix_mem_err, 1 },
662 { C::to_radix_mem_start, 1 },
663 { C::to_radix_mem_last, 1 },
664 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
666 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
667 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
668 { C::to_radix_mem_sel_value_is_zero, 0 },
670 { C::to_radix_mem_sel_radix_eq_2, 0 },
671 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
675 check_relation<to_radix_mem>(trace);
676 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_dst_addr_in_range_settings>(trace);
677 check_interaction<ExecutionTraceBuilder, perm_execution_dispatch_to_to_radix_settings>(trace);
680TEST(ToRadixMemoryConstrainingTest, InvalidRadix)
685 uint32_t num_limbs = 2;
688 TestTraceContainer
trace = TestTraceContainer({
691 { C::precomputed_first_row, 1 },
694 { C::gt_input_a, 2 },
695 { C::gt_input_b, radix },
700 { C::to_radix_mem_sel, 1 },
701 { C::to_radix_mem_max_mem_size, MAX_MEM },
702 { C::to_radix_mem_two, 2 },
703 { C::to_radix_mem_two_five_six, 256 },
705 { C::to_radix_mem_execution_clk, 0 },
706 { C::to_radix_mem_space_id, 0 },
707 { C::to_radix_mem_dst_addr,
dst_addr },
708 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
710 { C::to_radix_mem_value_to_decompose,
value },
711 { C::to_radix_mem_radix, radix },
712 { C::to_radix_mem_num_limbs, num_limbs },
713 { C::to_radix_mem_is_output_bits, 0 },
715 { C::to_radix_mem_sel_radix_lt_2_err, 1 },
716 { C::to_radix_mem_input_validation_error, 1 },
717 { C::to_radix_mem_err, 1 },
719 { C::to_radix_mem_start, 1 },
720 { C::to_radix_mem_last, 1 },
721 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
723 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
724 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
725 { C::to_radix_mem_sel_value_is_zero, 0 },
727 { C::to_radix_mem_sel_radix_eq_2, 0 },
728 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
731 check_relation<to_radix_mem>(trace);
732 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
735TEST(ToRadixMemoryConstrainingTest, InvalidBitwiseRadix)
740 uint32_t num_limbs = 2;
744 TestTraceContainer
trace = TestTraceContainer({
747 { C::precomputed_first_row, 1 },
750 { C::gt_input_a, 2 },
751 { C::gt_input_b, radix },
756 { C::to_radix_mem_sel, 1 },
757 { C::to_radix_mem_max_mem_size, MAX_MEM },
758 { C::to_radix_mem_two, 2 },
759 { C::to_radix_mem_two_five_six, 256 },
761 { C::to_radix_mem_execution_clk, 0 },
762 { C::to_radix_mem_space_id, 0 },
763 { C::to_radix_mem_dst_addr,
dst_addr },
764 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
766 { C::to_radix_mem_value_to_decompose,
value },
767 { C::to_radix_mem_radix, radix },
768 { C::to_radix_mem_num_limbs, num_limbs },
771 { C::to_radix_mem_sel_invalid_bitwise_radix, 1 },
772 { C::to_radix_mem_input_validation_error, 1 },
773 { C::to_radix_mem_err, 1 },
775 { C::to_radix_mem_start, 1 },
776 { C::to_radix_mem_last, 1 },
777 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
779 { C::to_radix_mem_sel_num_limbs_is_zero, 0 },
780 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
781 { C::to_radix_mem_sel_value_is_zero, 0 },
783 { C::to_radix_mem_sel_radix_eq_2, 0 },
784 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
787 check_relation<to_radix_mem>(trace);
788 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
791TEST(ToRadixMemoryConstrainingTest, InvalidNumLimbsForValue)
796 uint32_t num_limbs = 0;
800 TestTraceContainer
trace = TestTraceContainer({
803 { C::precomputed_first_row, 1 },
806 { C::gt_input_a, 2 },
807 { C::gt_input_b, radix },
812 { C::to_radix_mem_sel, 1 },
813 { C::to_radix_mem_max_mem_size, MAX_MEM },
814 { C::to_radix_mem_two, 2 },
815 { C::to_radix_mem_two_five_six, 256 },
817 { C::to_radix_mem_execution_clk, 0 },
818 { C::to_radix_mem_space_id, 0 },
819 { C::to_radix_mem_dst_addr,
dst_addr },
820 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
822 { C::to_radix_mem_value_to_decompose,
value },
823 { C::to_radix_mem_radix, radix },
824 { C::to_radix_mem_num_limbs, num_limbs },
827 { C::to_radix_mem_input_validation_error, 1 },
828 { C::to_radix_mem_err, 1 },
830 { C::to_radix_mem_start, 1 },
831 { C::to_radix_mem_last, 1 },
832 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
834 { C::to_radix_mem_sel_num_limbs_is_zero, 1 },
835 { C::to_radix_mem_num_limbs_inv, 0 },
836 { C::to_radix_mem_sel_value_is_zero, 0 },
838 { C::to_radix_mem_sel_radix_eq_2, 0 },
839 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
842 check_relation<to_radix_mem>(trace);
843 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
846TEST(ToRadixMemoryConstrainingTest, TruncationError)
851 uint32_t num_limbs = 3;
855 TestTraceContainer
trace = TestTraceContainer({
858 { C::precomputed_first_row, 1 },
861 { C::gt_input_a, 2 },
862 { C::gt_input_b, radix },
867 { C::to_radix_mem_sel, 1 },
868 { C::to_radix_mem_max_mem_size, MAX_MEM },
869 { C::to_radix_mem_two, 2 },
870 { C::to_radix_mem_two_five_six, 256 },
872 { C::to_radix_mem_execution_clk, 0 },
873 { C::to_radix_mem_space_id, 0 },
874 { C::to_radix_mem_dst_addr,
dst_addr },
875 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
877 { C::to_radix_mem_value_to_decompose,
value },
878 { C::to_radix_mem_radix, radix },
879 { C::to_radix_mem_num_limbs, num_limbs },
882 { C::to_radix_mem_err, 1 },
884 { C::to_radix_mem_start, 1 },
885 { C::to_radix_mem_last, 1 },
886 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
888 { C::to_radix_mem_sel_should_decompose, 1 },
889 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
890 { C::to_radix_mem_limb_value, 3 },
891 { C::to_radix_mem_value_found, 0 },
893 { C::to_radix_mem_num_limbs_inv,
FF(num_limbs).
invert() },
894 { C::to_radix_mem_sel_value_is_zero, 0 },
896 { C::to_radix_mem_sel_radix_eq_2, 0 },
897 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
900 check_relation<to_radix_mem>(trace);
901 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
904 trace.
set(C::to_radix_mem_err, 1, 0);
906 trace.
set(C::to_radix_mem_err, 1, 1);
909 trace.
set(C::to_radix_mem_value_found, 1, 1);
913TEST(ToRadixMemoryConstrainingTest, ZeroNumLimbsAndZeroValueIsNoop)
918 uint32_t num_limbs = 0;
922 TestTraceContainer
trace = TestTraceContainer({
925 { C::precomputed_first_row, 1 },
928 { C::gt_input_a, 2 },
929 { C::gt_input_b, radix },
934 { C::to_radix_mem_sel, 1 },
935 { C::to_radix_mem_max_mem_size, MAX_MEM },
936 { C::to_radix_mem_two, 2 },
937 { C::to_radix_mem_two_five_six, 256 },
939 { C::to_radix_mem_execution_clk, 0 },
940 { C::to_radix_mem_space_id, 0 },
941 { C::to_radix_mem_dst_addr,
dst_addr },
942 { C::to_radix_mem_write_addr_upper_bound,
dst_addr + num_limbs },
944 { C::to_radix_mem_value_to_decompose,
value },
945 { C::to_radix_mem_radix, radix },
946 { C::to_radix_mem_num_limbs, num_limbs },
949 { C::to_radix_mem_start, 1 },
950 { C::to_radix_mem_last, 1 },
951 { C::to_radix_mem_num_limbs_minus_one_inv, num_limbs - 1 == 0 ? 0 :
FF(num_limbs - 1).
invert() },
953 { C::to_radix_mem_sel_num_limbs_is_zero, 1 },
954 { C::to_radix_mem_num_limbs_inv, 0 },
955 { C::to_radix_mem_sel_value_is_zero, 1 },
956 { C::to_radix_mem_value_inv, 0 },
957 { C::to_radix_mem_sel_radix_eq_2, 0 },
958 { C::to_radix_mem_radix_min_two_inv, (
FF(radix) -
FF(2)).invert() },
961 check_relation<to_radix_mem>(trace);
962 check_interaction<ToRadixTraceBuilder, lookup_to_radix_mem_check_radix_lt_2_settings>(trace);
965TEST(ToRadixMemoryConstrainingTest, ComplexTest)
967 EventEmitter<ToRadixEvent> to_radix_event_emitter;
968 EventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
972 simulation::MemoryStore
memory;
974 StrictMock<MockFieldGreaterThan>
field_gt;
978 ToRadixSimulator to_radix_simulator(
execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
982 uint32_t num_limbs = 256;
987 to_radix_simulator.to_be_radix(
988 memory,
FF(1337), 10, 6,
false, 0xdeadbeef);
990 TestTraceContainer
trace;
993 builder.process_with_memory(to_radix_mem_event_emitter.dump_events(), trace);
1003 check_relation<to_radix>(trace);
1004 check_relation<to_radix_mem>(trace);
1027TEST(ToRadixMemoryConstrainingTest, NegativeGhostRowMemoryWrite_RelationsOnly)
1031 TestTraceContainer
trace({
1033 { C::precomputed_first_row, 1 },
1036 { C::to_radix_mem_sel, 0 },
1037 { C::to_radix_mem_sel_should_write_mem, 1 },
1038 { C::to_radix_mem_execution_clk, 1 },
1039 { C::to_radix_mem_space_id, 1 },
1040 { C::to_radix_mem_dst_addr, 100 },
1041 { C::to_radix_mem_limb_value, 999 },
1042 { C::to_radix_mem_output_tag, 2 },
1049 "SEL_SHOULD_WRITE_MEM_REQUIRES_SEL");
1058TEST(ToRadixMemoryConstrainingTest, NegativeGhostRowInjectionBlocked)
1060 TestTraceContainer
trace;
1061 MemoryTraceBuilder memory_trace_builder;
1062 PrecomputedTraceBuilder precomputed_trace_builder;
1065 uint32_t malicious_clk = 42;
1066 uint16_t malicious_space_id = 1;
1068 uint8_t malicious_limb_value = 0x99;
1074 .execution_clk = malicious_clk,
1076 .addr = malicious_addr,
1078 .space_id = malicious_space_id,
1083 precomputed_trace_builder.process_sel_range_8(trace);
1084 precomputed_trace_builder.process_sel_range_16(trace);
1085 precomputed_trace_builder.process_misc(trace, 1 << 16);
1086 precomputed_trace_builder.process_tag_parameters(trace);
1087 memory_trace_builder.process(mem_events, trace);
1090 uint32_t memory_row = 0;
1092 if (
trace.
get(C::memory_sel, row) == 1) {
1100 uint32_t ghost_row = 0;
1103 { C::precomputed_first_row, 1 },
1104 { C::execution_clk, ghost_row },
1105 { C::to_radix_mem_sel, 0 },
1106 { C::to_radix_mem_sel_should_write_mem, 1 },
1107 { C::to_radix_mem_execution_clk, malicious_clk },
1108 { C::to_radix_mem_space_id, malicious_space_id },
1109 { C::to_radix_mem_dst_addr, malicious_addr },
1110 { C::to_radix_mem_limb_value, malicious_limb_value },
1111 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(malicious_tag) },
1114 trace.
set(C::memory_sel_to_radix_write, memory_row, 1);
1121TEST(ToRadixMemoryConstrainingTest, NegativeBitwiseRadixError)
1123 TestTraceContainer
trace({
1125 { C::to_radix_mem_start, 1 },
1126 { C::to_radix_mem_sel, 1 },
1127 { C::to_radix_mem_sel_radix_eq_2, 1 },
1128 { C::to_radix_mem_is_output_bits, 1 },
1135 trace.
set(C::to_radix_mem_sel_invalid_bitwise_radix, 0, 1);
1138 "IS_OUTPUT_BITS_IMPLY_RADIX_2");
1142TEST(ToRadixMemoryConstrainingTest, NegativeBitwiseRadixNoError)
1144 TestTraceContainer
trace({
1146 { C::to_radix_mem_start, 1 },
1147 { C::to_radix_mem_sel, 1 },
1148 { C::to_radix_mem_sel_radix_eq_2, 0 },
1149 { C::to_radix_mem_is_output_bits, 1 },
1150 { C::to_radix_mem_sel_invalid_bitwise_radix, 1 },
1157 trace.
set(C::to_radix_mem_sel_invalid_bitwise_radix, 0, 0);
1160 "IS_OUTPUT_BITS_IMPLY_RADIX_2");
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 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 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)
void process_misc(TraceContainer &trace, const uint32_t num_rows=PRECOMPUTED_TRACE_SIZE)
void process_to_radix_safe_limbs(TraceContainer &trace)
void process_sel_range_8(TraceContainer &trace)
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)
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
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()