1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
25using tracegen::BytecodeTraceBuilder;
26using tracegen::PrecomputedTraceBuilder;
27using tracegen::RangeCheckTraceBuilder;
28using tracegen::TestTraceContainer;
33using instr_fetching = instr_fetching<FF>;
35using simulation::BytecodeDecompositionEvent;
37using simulation::Instruction;
38using simulation::InstructionFetchingEvent;
40using simulation::RangeCheckEvent;
42TEST(InstrFetchingConstrainingTest, EmptyRow)
48TEST(InstrFetchingConstrainingTest, Add8WithTraceGen)
50 TestTraceContainer
trace;
57 .operands = { Operand::from<uint8_t>(0x34), Operand::from<uint8_t>(0x35), Operand::from<uint8_t>(0x36) },
60 std::vector<uint8_t>
bytecode = add_8_instruction.serialize();
62 builder.process_instruction_fetching({ { .bytecode_id = 1,
64 .instruction = add_8_instruction,
70 check_relation<instr_fetching>(trace);
75TEST(InstrFetchingConstrainingTest, EcaddWithTraceGen)
77 TestTraceContainer
trace;
83 .addressing_mode = 0x1f1f,
84 .operands = { Operand::from<uint16_t>(0x1279),
85 Operand::from<uint16_t>(0x127a),
86 Operand::from<uint16_t>(0x127b),
87 Operand::from<uint16_t>(0x127c),
88 Operand::from<uint16_t>(0x127d),
89 Operand::from<uint16_t>(0x127e),
90 Operand::from<uint16_t>(0x127f) },
93 std::vector<uint8_t>
bytecode = ecadd_instruction.serialize();
94 builder.process_instruction_fetching({ { .bytecode_id = 1,
96 .instruction = ecadd_instruction,
102 check_relation<instr_fetching>(trace);
112 instructions.reserve(num_opcodes);
115 for (
size_t i = 0; i < num_opcodes; i++) {
116 pc_positions.at(i) =
static_cast<uint32_t
>(
bytecode.size());
118 instructions.emplace_back(instr);
119 const auto instruction_bytes = instr.serialize();
129 instr_events.reserve(num_opcodes);
130 for (
size_t i = 0; i < num_opcodes; i++) {
131 instr_events.emplace_back(InstructionFetchingEvent{
132 .bytecode_id = 1, .pc = pc_positions.at(i), .instruction = instructions.at(i), .bytecode = bytecode_ptr });
139TEST(InstrFetchingConstrainingTest, EachOpcodeWithTraceGen)
141 TestTraceContainer
trace;
145 builder.process_instruction_fetching(gen_instr_events_each_opcode(), trace);
150 check_relation<instr_fetching>(trace);
156TEST(InstrFetchingConstrainingTest, NegativeWrongOperand)
162 std::vector<size_t> sub_relations = {
174 C::instr_fetching_addressing_mode,
175 C::instr_fetching_op1,
176 C::instr_fetching_op2,
177 C::instr_fetching_op3,
178 C::instr_fetching_op4,
179 C::instr_fetching_op5,
180 C::instr_fetching_op6,
181 C::instr_fetching_op7,
184 for (
const auto& opcode : opcodes) {
185 TestTraceContainer
trace;
187 builder.process_instruction_fetching(
188 { { .bytecode_id = 1,
190 .instruction = instr,
195 check_relation<instr_fetching>(trace);
199 for (
size_t i = 0; i < operand_cols.size(); i++) {
200 auto mutated_trace =
trace;
201 const FF mutated_operand =
trace.
get(operand_cols.at(i), 0) + 1;
202 mutated_trace.set(operand_cols.at(i), 0, mutated_operand);
212TEST(InstrFetchingConstrainingTest, WireInstructionSpecInteractions)
214 TestTraceContainer
trace;
215 BytecodeTraceBuilder bytecode_builder;
220 bytecode_builder.process_instruction_fetching(gen_instr_events_each_opcode(), trace);
225 check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_wire_instruction_info_settings>(trace);
226 check_relation<instr_fetching>(trace);
232 range_check_events.reserve(instr_events.size());
234 for (
const auto& instr_event : instr_events) {
235 range_check_events.emplace_back(RangeCheckEvent{
237 (instr_event.error.has_value() && instr_event.error == InstrDeserializationEventError::PC_OUT_OF_RANGE)
238 ? instr_event.pc - instr_event.bytecode->size()
239 : instr_event.bytecode->size() - instr_event.pc - 1,
243 return range_check_events;
248TEST(InstrFetchingConstrainingTest, BcDecompositionInteractions)
250 TestTraceContainer
trace;
251 BytecodeTraceBuilder bytecode_builder;
254 const auto instr_fetch_events = gen_instr_events_each_opcode();
255 bytecode_builder.process_instruction_fetching(instr_fetch_events, trace);
256 bytecode_builder.process_decomposition({ {
257 .bytecode_id = instr_fetch_events.at(0).bytecode_id,
258 .
bytecode = instr_fetch_events.at(0).bytecode,
270 check_relation<instr_fetching>(trace);
277 TestTraceContainer
trace;
278 BytecodeTraceBuilder bytecode_builder;
286 bytecode_builder.process_instruction_fetching(instr_events, trace);
301 check_relation<instr_fetching>(trace);
307 TestTraceContainer
trace;
308 BytecodeTraceBuilder bytecode_builder;
314 bytecode_builder.process_instruction_fetching(instr_events, trace);
327 check_relation<instr_fetching>(trace);
333TEST(InstrFetchingConstrainingTest, MultipleBytecodes)
335 const auto instr_fetch_events = gen_instr_events_each_opcode();
336 constexpr size_t num_of_bytecodes = 5;
340 for (
size_t i = 0; i < num_of_bytecodes; i++) {
342 const auto num_of_instr = i * 6;
344 for (
size_t j = 0; j < num_of_instr; j++) {
345 const auto& instr = instr_fetch_events.at(j).instruction;
346 const auto instruction_bytes = instr.serialize();
354 for (
size_t j = 0; j < num_of_instr; j++) {
355 auto instr_event = instr_fetch_events.at(j);
356 instr_event.bytecode_id =
static_cast<BytecodeId>(i);
357 instr_event.bytecode = bytecode_ptr;
358 instr_events.emplace_back(instr_event);
373TEST(InstrFetchingConstrainingTest, SingleInstructionOutOfRange)
377 .addressing_mode = 3,
378 .operands = { Operand::from<uint8_t>(0x34), Operand::from<uint8_t>(0x35), Operand::from<uint8_t>(0x36) },
381 std::vector<uint8_t>
bytecode = add_8_instruction.serialize();
389 .bytecode = bytecode_ptr,
390 .error = InstrDeserializationEventError::INSTRUCTION_OUT_OF_RANGE,
397 .bytecode = bytecode_ptr,
408TEST(InstrFetchingConstrainingTest, SingleInstructionOutOfRangeSplitOperand)
412 .addressing_mode = 0x01,
413 .operands = { Operand::from<uint16_t>(0x1279),
418 std::vector<uint8_t>
bytecode = set_ff_instruction.serialize();
426 .bytecode = bytecode_ptr,
427 .error = InstrDeserializationEventError::INSTRUCTION_OUT_OF_RANGE,
434 .bytecode = bytecode_ptr,
442TEST(InstrFetchingConstrainingTest, SingleInstructionPcOutOfRange)
446 .addressing_mode = 3,
447 .operands = { Operand::from<uint8_t>(0x34), Operand::from<uint8_t>(0x35), Operand::from<uint8_t>(0x36) },
450 std::vector<uint8_t>
bytecode = add_8_instruction.serialize();
458 .instruction = add_8_instruction,
459 .bytecode = bytecode_ptr,
463 .pc =
static_cast<uint32_t
>(bytecode_ptr->size() + 1),
465 .error = InstrDeserializationEventError::PC_OUT_OF_RANGE,
472 .bytecode = bytecode_ptr,
482TEST(InstrFetchingConstrainingTest, SingleInstructionOpcodeOutOfRange)
486 .addressing_mode = 0,
487 .operands = { Operand::from<uint16_t>(0x1234),
489 Operand::from<uint128_t>(
static_cast<uint128_t>(0xFF) << 120) },
492 std::vector<uint8_t>
bytecode = set_128_instruction.serialize();
499 .instruction = set_128_instruction,
500 .bytecode = bytecode_ptr,
505 .bytecode = bytecode_ptr,
506 .error = InstrDeserializationEventError::OPCODE_OUT_OF_RANGE,
513 .bytecode = bytecode_ptr,
523TEST(InstrFetchingConstrainingTest, SingleInstructionTagOutOfRange)
527 .addressing_mode = 0,
528 .operands = { Operand::from<uint16_t>(0x1234), Operand::from<uint8_t>(12), Operand::from<uint16_t>(0x5678) },
531 std::vector<uint8_t>
bytecode = set_16_instruction.serialize();
538 .instruction = set_16_instruction,
539 .bytecode = bytecode_ptr,
540 .error = InstrDeserializationEventError::TAG_OUT_OF_RANGE,
547 .bytecode = bytecode_ptr,
555TEST(InstrFetchingConstrainingTest, NegativeWrongWireInstructionSpecInteractions)
557 BytecodeTraceBuilder bytecode_builder;
564 for (
const auto& opcode : opcodes) {
565 TestTraceContainer
trace;
567 bytecode_builder.process_instruction_fetching(
568 { { .bytecode_id = 1,
570 .instruction = instr,
577 check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_wire_instruction_info_settings>(trace);
579 ASSERT_EQ(
trace.
get(C::lookup_instr_fetching_wire_instruction_info_counts,
static_cast<uint32_t
>(opcode)), 1);
582 C::instr_fetching_exec_opcode, C::instr_fetching_instr_size, C::instr_fetching_sel_has_tag,
583 C::instr_fetching_sel_tag_is_op2, C::instr_fetching_sel_op_dc_0, C::instr_fetching_sel_op_dc_1,
584 C::instr_fetching_sel_op_dc_2, C::instr_fetching_sel_op_dc_3, C::instr_fetching_sel_op_dc_4,
585 C::instr_fetching_sel_op_dc_5, C::instr_fetching_sel_op_dc_6, C::instr_fetching_sel_op_dc_7,
586 C::instr_fetching_sel_op_dc_8, C::instr_fetching_sel_op_dc_9, C::instr_fetching_sel_op_dc_10,
587 C::instr_fetching_sel_op_dc_11, C::instr_fetching_sel_op_dc_12, C::instr_fetching_sel_op_dc_13,
588 C::instr_fetching_sel_op_dc_14, C::instr_fetching_sel_op_dc_15, C::instr_fetching_sel_op_dc_16,
592 for (
const auto& col : mutated_cols) {
593 auto mutated_trace =
trace;
594 const FF mutated_value =
trace.
get(col, 1) + 1;
595 mutated_trace.set(col, 1, mutated_value);
598 (check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_wire_instruction_info_settings>(
600 "Failed.*LOOKUP_INSTR_FETCHING_WIRE_INSTRUCTION_INFO.*Could not find tuple in destination.");
606TEST(InstrFetchingConstrainingTest, NegativeWrongBcDecompositionInteractions)
608 TestTraceContainer
trace;
609 BytecodeTraceBuilder bytecode_builder;
615 for (
const auto& opcode : opcodes) {
616 TestTraceContainer
trace;
619 bytecode_builder.process_instruction_fetching({ {
622 .instruction = instr,
623 .bytecode = bytecode_ptr,
626 bytecode_builder.process_decomposition({ {
628 .bytecode = bytecode_ptr,
632 auto valid_trace =
trace;
633 check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_bytes_from_bc_dec_settings>(valid_trace);
636 C::instr_fetching_pc, C::instr_fetching_bytecode_id, C::instr_fetching_bd0, C::instr_fetching_bd1,
637 C::instr_fetching_bd2, C::instr_fetching_bd3, C::instr_fetching_bd4, C::instr_fetching_bd5,
638 C::instr_fetching_bd6, C::instr_fetching_bd7, C::instr_fetching_bd8, C::instr_fetching_bd9,
639 C::instr_fetching_bd10, C::instr_fetching_bd11, C::instr_fetching_bd12, C::instr_fetching_bd13,
640 C::instr_fetching_bd14, C::instr_fetching_bd15, C::instr_fetching_bd16, C::instr_fetching_bd17,
641 C::instr_fetching_bd18, C::instr_fetching_bd19, C::instr_fetching_bd20, C::instr_fetching_bd21,
642 C::instr_fetching_bd22, C::instr_fetching_bd23, C::instr_fetching_bd24, C::instr_fetching_bd25,
643 C::instr_fetching_bd26, C::instr_fetching_bd27, C::instr_fetching_bd28, C::instr_fetching_bd29,
644 C::instr_fetching_bd30, C::instr_fetching_bd31, C::instr_fetching_bd32, C::instr_fetching_bd33,
645 C::instr_fetching_bd34, C::instr_fetching_bd35, C::instr_fetching_bd36,
649 for (
const auto& col : mutated_cols) {
650 auto mutated_trace =
trace;
651 const FF mutated_value =
trace.
get(col, 1) + 1;
652 mutated_trace.set(col, 1, mutated_value);
655 (check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_bytes_from_bc_dec_settings>(
657 "Failed.*BYTES_FROM_BC_DEC. Could not find tuple in destination.");
664TEST(InstrFetchingConstrainingTest, NegativeWrongBytecodeSizeBcDecompositionInteractions)
666 TestTraceContainer
trace;
667 BytecodeTraceBuilder bytecode_builder;
670 const uint32_t pc = 15;
671 std::vector<uint8_t>
bytecode(pc, 0x23);
677 for (
const auto& opcode : opcodes) {
678 TestTraceContainer
trace;
681 const auto instr_bytecode = instr.serialize();
687 bytecode_builder.process_instruction_fetching({ {
690 .instruction = instr,
691 .bytecode = bytecode_ptr,
694 bytecode_builder.process_decomposition({ {
696 .bytecode = bytecode_ptr,
701 auto valid_trace =
trace;
702 check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_bytecode_size_from_bc_dec_settings>(valid_trace);
704 auto mutated_trace =
trace;
705 const FF mutated_value =
trace.
get(C::instr_fetching_bytecode_size, 1) + 1;
706 mutated_trace.set(C::instr_fetching_bytecode_size, 1, mutated_value);
709 (check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_bytecode_size_from_bc_dec_settings>(
711 "Failed.*BYTECODE_SIZE_FROM_BC_DEC. Could not find tuple in destination.");
715TEST(InstrFetchingConstrainingTest, NegativeWrongTagValidationInteractions)
717 TestTraceContainer
trace;
718 BytecodeTraceBuilder bytecode_builder;
725 for (
const auto& opcode : opcodes) {
726 TestTraceContainer
trace;
728 bytecode_builder.process_instruction_fetching(
729 { { .bytecode_id = 1,
731 .instruction = instr,
738 check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_tag_value_validation_settings>(trace);
740 auto valid_trace =
trace;
743 auto mutated_trace =
trace;
744 ASSERT_EQ(
trace.
get(C::instr_fetching_tag_out_of_range, 1), 0);
745 mutated_trace.set(C::instr_fetching_tag_out_of_range, 1, 1);
748 (check_interaction<BytecodeTraceBuilder, lookup_instr_fetching_tag_value_validation_settings>(
750 "Failed.*LOOKUP_INSTR_FETCHING_TAG_VALUE_VALIDATION.*Could not find tuple in destination.");
755TEST(InstrFetchingConstrainingTest, NegativeNotTogglingInstrOutOfRange)
757 TestTraceContainer
trace({
758 { { C::precomputed_first_row, 1 } },
760 { C::instr_fetching_bytes_to_read, 11 },
761 { C::instr_fetching_instr_abs_diff, 0 },
762 { C::instr_fetching_instr_out_of_range, 1 },
763 { C::instr_fetching_instr_size, 12 },
764 { C::instr_fetching_sel, 1 },
770 trace.
set(C::instr_fetching_instr_out_of_range, 1, 0);
773 "INSTR_OUT_OF_RANGE_TOGGLE");
777TEST(InstrFetchingConstrainingTest, NegativeTogglingInstrInRange)
779 TestTraceContainer
trace({
780 { { C::precomputed_first_row, 1 } },
782 { C::instr_fetching_bytes_to_read, 12 },
783 { C::instr_fetching_instr_abs_diff, 0 },
784 { C::instr_fetching_instr_out_of_range, 0 },
785 { C::instr_fetching_instr_size, 12 },
786 { C::instr_fetching_sel, 1 },
792 trace.
set(C::instr_fetching_instr_out_of_range, 1, 1);
795 "INSTR_OUT_OF_RANGE_TOGGLE");
799TEST(InstrFetchingConstrainingTest, NegativeNotTogglingPcOutOfRange)
801 TestTraceContainer
trace({
802 { { C::precomputed_first_row, 1 } },
804 { C::instr_fetching_bytecode_size, 12 },
805 { C::instr_fetching_pc, 12 },
806 { C::instr_fetching_pc_abs_diff, 0 },
807 { C::instr_fetching_pc_out_of_range, 1 },
808 { C::instr_fetching_sel, 1 },
814 trace.
set(C::instr_fetching_pc_out_of_range, 1, 0);
817 "PC_OUT_OF_RANGE_TOGGLE");
821TEST(InstrFetchingConstrainingTest, NegativeTogglingPcInRange)
823 TestTraceContainer
trace({
824 { { C::precomputed_first_row, 1 } },
826 { C::instr_fetching_bytecode_size, 12 },
827 { C::instr_fetching_pc, 11 },
828 { C::instr_fetching_pc_abs_diff, 0 },
829 { C::instr_fetching_pc_out_of_range, 0 },
830 { C::instr_fetching_sel, 1 },
836 trace.
set(C::instr_fetching_pc_out_of_range, 1, 1);
839 "PC_OUT_OF_RANGE_TOGGLE");
842TEST(InstrFetchingConstrainingTest, ErrorFlagSetButSelParsingErrIsZero)
847 TestTraceContainer
trace({
848 { { C::precomputed_first_row, 1 } },
850 { C::instr_fetching_sel, 1 },
852 { C::instr_fetching_pc_out_of_range, 1 },
853 { C::instr_fetching_opcode_out_of_range, 0 },
854 { C::instr_fetching_instr_out_of_range, 0 },
855 { C::instr_fetching_tag_out_of_range, 0 },
857 { C::instr_fetching_sel_parsing_err, 0 },
861 { C::instr_fetching_bytecode_size, 10 },
862 { C::instr_fetching_pc, 15 },
863 { C::instr_fetching_pc_abs_diff, 5 },
864 { C::instr_fetching_pc_size_in_bits, 32 },
869 { C::instr_fetching_bytes_to_read, 10 },
870 { C::instr_fetching_instr_size, 5 },
871 { C::instr_fetching_instr_abs_diff, 5 },
876 "Relation instr_fetching, subrelation 5 failed at row 1");
883TEST(InstrFetchingConstrainingTest, CorrectBehavior_SelParsingErrMatchesErrors)
885 TestTraceContainer
trace({
886 { { C::precomputed_first_row, 1 } },
888 { C::instr_fetching_sel, 1 },
889 { C::instr_fetching_pc_out_of_range, 1 },
890 { C::instr_fetching_opcode_out_of_range, 0 },
891 { C::instr_fetching_instr_out_of_range, 0 },
892 { C::instr_fetching_tag_out_of_range, 0 },
893 { C::instr_fetching_sel_parsing_err, 1 },
895 { C::instr_fetching_bytecode_size, 10 },
896 { C::instr_fetching_pc, 15 },
897 { C::instr_fetching_pc_abs_diff, 5 },
898 { C::instr_fetching_pc_size_in_bits, 32 },
899 { C::instr_fetching_bytes_to_read, 10 },
900 { C::instr_fetching_instr_size, 5 },
901 { C::instr_fetching_instr_abs_diff, 5 },
906 check_relation<instr_fetching>(trace);
912TEST(InstrFetchingConstrainingTest, CorrectBehavior_NoErrorsMeansSelParsingErrIsZero)
914 TestTraceContainer
trace({
915 { { C::precomputed_first_row, 1 } },
917 { C::instr_fetching_sel, 1 },
918 { C::instr_fetching_pc_out_of_range, 0 },
919 { C::instr_fetching_opcode_out_of_range, 0 },
920 { C::instr_fetching_instr_out_of_range, 0 },
921 { C::instr_fetching_tag_out_of_range, 0 },
922 { C::instr_fetching_sel_parsing_err, 0 },
923 { C::instr_fetching_sel_pc_in_range, 1 },
927 { C::instr_fetching_bytecode_size, 20 },
928 { C::instr_fetching_pc, 5 },
929 { C::instr_fetching_pc_abs_diff, 14 },
930 { C::instr_fetching_pc_size_in_bits, 32 },
932 { C::instr_fetching_bytes_to_read, 15 },
933 { C::instr_fetching_instr_size, 10 },
934 { C::instr_fetching_instr_abs_diff, 5 },
939 check_relation<instr_fetching>(trace);
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
std::shared_ptr< Napi::ThreadSafeFunction > bytecode
#define AVM_PC_SIZE_IN_BITS
EventEmitter< BytecodeDecompositionEvent > decomposition_events
static constexpr size_t SR_OP1_BYTES_DECOMPOSITION
static constexpr size_t SR_OP3_BYTES_DECOMPOSITION
static constexpr size_t SR_OP6_BYTES_DECOMPOSITION
static constexpr size_t SR_OP4_BYTES_DECOMPOSITION
static constexpr size_t SR_ADDRESSING_MODE_BYTES_DECOMPOSITION
static constexpr size_t SR_INSTR_OUT_OF_RANGE_TOGGLE
static std::string get_subrelation_label(size_t index)
static constexpr size_t SR_OP7_BYTES_DECOMPOSITION
static constexpr size_t SR_OP5_BYTES_DECOMPOSITION
static constexpr size_t SR_PC_OUT_OF_RANGE_TOGGLE
static constexpr size_t SR_OP2_BYTES_DECOMPOSITION
void process_wire_instruction_spec(TraceContainer &trace)
void process_memory_tag_range(TraceContainer &trace)
void process_misc(TraceContainer &trace, const uint32_t num_rows=MAX_AVM_TRACE_SIZE)
void process_sel_range_16(TraceContainer &trace)
void process_sel_range_8(TraceContainer &trace)
void process(const simulation::EventEmitterInterface< simulation::RangeCheckEvent >::Container &events, 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)
RangeCheckTraceBuilder range_check_builder
PrecomputedTraceBuilder precomputed_builder
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
InstrDeserializationEventError
Instruction random_instruction(WireOpCode w_opcode)
TestTraceContainer empty_trace()
lookup_settings< lookup_instr_fetching_wire_instruction_info_settings_ > lookup_instr_fetching_wire_instruction_info_settings
lookup_settings< lookup_instr_fetching_bytecode_size_from_bc_dec_settings_ > lookup_instr_fetching_bytecode_size_from_bc_dec_settings
lookup_settings< lookup_instr_fetching_bytes_from_bc_dec_settings_ > lookup_instr_fetching_bytes_from_bc_dec_settings
lookup_settings< lookup_instr_fetching_instr_abs_diff_positive_settings_ > lookup_instr_fetching_instr_abs_diff_positive_settings
lookup_settings< lookup_instr_fetching_pc_abs_diff_positive_settings_ > lookup_instr_fetching_pc_abs_diff_positive_settings
lookup_settings< lookup_instr_fetching_tag_value_validation_settings_ > lookup_instr_fetching_tag_value_validation_settings
Instruction
Enumeration of VM instructions that can be executed.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
unsigned __int128 uint128_t
static constexpr uint256_t modulus_minus_two