1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
29using ::testing::StrictMock;
35using simulation::EventEmitter;
36using simulation::MockExecutionIdManager;
37using simulation::MockGreaterThan;
38using simulation::Poseidon2;
39using simulation::Poseidon2HashEvent;
40using simulation::Poseidon2PermutationEvent;
41using simulation::Poseidon2PermutationMemoryEvent;
42using tracegen::BytecodeTraceBuilder;
43using tracegen::Poseidon2TraceBuilder;
44using tracegen::PrecomputedTraceBuilder;
45using tracegen::TestTraceContainer;
53class BytecodeHashingConstrainingTest :
public ::testing::Test {
67class BytecodeHashingConstrainingTestTraceHelper :
public BytecodeHashingConstrainingTest {
69 TestTraceContainer process_bc_hashing_trace(std::vector<std::vector<FF>> all_bytecode_fields,
70 std::vector<FF> bytecode_ids,
71 std::vector<size_t> bytecode_size_in_bytes)
76 TestTraceContainer
trace({
77 { { C::precomputed_first_row, 1 } },
80 for (uint32_t j = 0; j < all_bytecode_fields.size(); j++) {
81 uint32_t pc_index = 0;
82 auto bytecode_fields = all_bytecode_fields[j];
83 auto bytecode_id = bytecode_ids[j];
84 bytecode_fields.insert(bytecode_fields.begin(),
87 auto bytecode_field_at = [&bytecode_fields](
size_t i) ->
FF {
88 return i < bytecode_fields.size() ? bytecode_fields[i] : 0;
90 auto padding_amount = (3 - (bytecode_fields.size() % 3)) % 3;
91 auto num_rounds = (bytecode_fields.size() + padding_amount) / 3;
92 for (uint32_t i = 0; i < bytecode_fields.size(); i += 3) {
94 bool end = i + 3 >= bytecode_fields.size();
95 auto pc_index_1 = start ? 0 : pc_index + 31;
98 { C::bc_hashing_bytecode_id, bytecode_id },
99 { C::bc_hashing_end, end },
100 { C::bc_hashing_size_in_bytes, bytecode_size_in_bytes[j] },
101 { C::bc_hashing_input_len, bytecode_fields.size() },
102 { C::bc_hashing_rounds_rem, num_rounds },
103 { C::bc_hashing_packed_fields_0, bytecode_field_at(i) },
104 { C::bc_hashing_packed_fields_1, bytecode_field_at(i + 1) },
105 { C::bc_hashing_packed_fields_2, bytecode_field_at(i + 2) },
106 { C::bc_hashing_pc_index, pc_index },
107 { C::bc_hashing_pc_index_1, pc_index_1 },
108 { C::bc_hashing_pc_index_2, pc_index_1 + 31 },
109 { C::bc_hashing_sel, 1 },
110 { C::bc_hashing_sel_not_padding_1, end && padding_amount == 2 ? 0 : 1 },
111 { C::bc_hashing_sel_not_padding_2, end && padding_amount > 0 ? 0 : 1 },
112 { C::bc_hashing_padding, padding_amount },
113 { C::bc_hashing_sel_not_start, !start },
114 { C::bc_hashing_start, start },
118 pc_index = pc_index_1 + 62;
127TEST_F(BytecodeHashingConstrainingTest, EmptyRow)
132TEST_F(BytecodeHashingConstrainingTest, SingleBytecodeHashOneRow)
136 std::vector<FF> bytecode_fields = { 1, 2 };
139 for (
auto bytecode_field : bytecode_fields) {
147 auto trace = TestTraceContainer({
148 { { C::precomputed_first_row, 1 } },
150 { C::bc_hashing_size_in_bytes,
bytecode.size() },
151 { C::bc_hashing_input_len, 3 },
152 { C::bc_hashing_end, 1 },
153 { C::bc_hashing_packed_fields_0, sep },
154 { C::bc_hashing_packed_fields_1, 1 },
155 { C::bc_hashing_packed_fields_2, 2 },
156 { C::bc_hashing_pc_index_1, 0 },
157 { C::bc_hashing_pc_index_2, 31 },
158 { C::bc_hashing_sel_not_padding_1, 1 },
159 { C::bc_hashing_sel_not_padding_2, 1 },
160 { C::bc_hashing_bytecode_id, hash },
161 { C::bc_hashing_pc_index, 0 },
162 { C::bc_hashing_rounds_rem, 1 },
163 { C::bc_hashing_sel, 1 },
164 { C::bc_hashing_start, 1 },
173 check_relation<bc_hashing>(trace);
174 check_all_interactions<BytecodeTraceBuilder>(trace);
177TEST_F(BytecodeHashingConstrainingTestTraceHelper, SingleBytecodeHash100Fields)
180 FF hash =
FF(
"0x09348974e76c3602893d7a4b4bb52c2ec746f1ade5004ac471d0fbb4587a81a6");
182 std::vector<FF> bytecode_fields = {};
183 for (uint32_t i = 1; i < 100; i++) {
184 bytecode_fields.push_back(
FF(i));
187 for (
auto bytecode_field : bytecode_fields) {
192 TestTraceContainer
trace = process_bc_hashing_trace({ bytecode_fields }, { hash }, {
bytecode.size() });
197 check_relation<bc_hashing>(trace);
198 check_all_interactions<BytecodeTraceBuilder>(trace);
201TEST_F(BytecodeHashingConstrainingTestTraceHelper, SingleBytecodeHashMax)
203 std::vector<uint8_t>
bytecode =
random_bytes(
static_cast<size_t>(31 * MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS));
206 prepended_fields.insert(prepended_fields.end(), bytecode_fields.begin(), bytecode_fields.end());
209 TestTraceContainer
trace = process_bc_hashing_trace({ bytecode_fields }, { hash }, {
bytecode.size() });
213 check_relation<bc_hashing>(trace);
214 check_all_interactions<BytecodeTraceBuilder>(trace);
217TEST_F(BytecodeHashingConstrainingTestTraceHelper, MultipleBytecodeHash)
224 std::vector<FF> hashes;
225 std::vector<size_t> byte_sizes;
226 for (uint32_t i = 0; i < all_bytecode.size(); i++) {
229 prepended_fields.insert(prepended_fields.end(), all_bytecode_fields[i].begin(), all_bytecode_fields[i].end());
231 byte_sizes.push_back(all_bytecode[i].size());
234 TestTraceContainer
trace = process_bc_hashing_trace(all_bytecode_fields, hashes, byte_sizes);
237 for (uint32_t j = 0; j < all_bytecode.size(); j++) {
238 const auto&
bytecode = all_bytecode[j];
239 decomp_events.push_back(simulation::BytecodeDecompositionEvent{
242 builder.process_decomposition({ decomp_events },
trace);
244 check_relation<bc_hashing>(trace);
245 check_all_interactions<BytecodeTraceBuilder>(trace);
248TEST_F(BytecodeHashingConstrainingTest, BytecodeInteractions)
250 TestTraceContainer
trace({
251 { { C::precomputed_first_row, 1 } },
257 prepended_fields.insert(prepended_fields.end(), fields.begin(), fields.end());
260 builder.process_hashing({ { .bytecode_id = hash,
261 .bytecode_length_in_bytes =
static_cast<uint32_t
>(
bytecode.size()),
262 .bytecode_fields = fields } },
270 perm_builder(C::bc_decomposition_sel_packed);
271 perm_builder.process(trace);
277 check_relation<bc_hashing>(trace);
278 check_relation<bb::avm2::bc_decomposition<FF>>(
trace);
282TEST_F(BytecodeHashingConstrainingTest, NegativeLatchNotSel)
284 TestTraceContainer
trace;
287 { C::bc_hashing_end, 1 },
288 { C::bc_hashing_sel, 1 },
297TEST_F(BytecodeHashingConstrainingTest, NegativeInvalidStartAfterLatch)
299 TestTraceContainer
trace({
300 { { C::precomputed_first_row, 1 } },
303 { { .bytecode_id = 1, .bytecode_length_in_bytes = 62, .bytecode_fields =
random_fields(2) },
304 { .bytecode_id = 2, .bytecode_length_in_bytes = 93, .bytecode_fields =
random_fields(3) } },
309 trace.
set(Column::bc_hashing_start, 2, 0);
314TEST_F(BytecodeHashingConstrainingTest, NegativeInvalidPCIncrement)
316 TestTraceContainer
trace({
317 { { C::precomputed_first_row, 1 } },
321 { .bytecode_id = 1, .bytecode_length_in_bytes = 124, .bytecode_fields =
random_fields(4) },
329 trace.
set(Column::bc_hashing_pc_index, 2, 10);
332 trace.
set(Column::bc_hashing_pc_index, 2, 62);
333 trace.
set(Column::bc_hashing_pc_index_1, 2, 97);
336 trace.
set(Column::bc_hashing_pc_index_1, 2, 93);
339 trace.
set(Column::bc_hashing_pc_index_2, 2, 10);
344TEST_F(BytecodeHashingConstrainingTest, NegativeStartIsSeparator)
346 TestTraceContainer
trace({
347 { { C::precomputed_first_row, 1 } },
349 builder.process_hashing({ { .bytecode_id = 1, .bytecode_length_in_bytes = 62, .bytecode_fields = { 1, 2 } } },
354 trace.
set(Column::bc_hashing_packed_fields_0, 1, 1);
359TEST_F(BytecodeHashingConstrainingTest, NegativeBytecodeInteraction)
361 TestTraceContainer
trace({
362 { { C::precomputed_first_row, 1 } },
368 prepended_fields.insert(prepended_fields.end(), fields.begin(), fields.end());
371 builder.process_hashing({ { .bytecode_id = hash, .bytecode_length_in_bytes = 150, .bytecode_fields = fields } },
378 perm_builder(C::bc_decomposition_sel_packed);
379 perm_builder.process(trace);
383 trace.
set(Column::bc_hashing_pc_index, 2, 0);
388 "Failed.*GET_PACKED_FIELD_0. Could not find tuple in destination.");
389 trace.
set(Column::bc_hashing_pc_index, 2, 62);
391 trace.
set(Column::bc_hashing_packed_fields_1, 2, 0);
396 "Failed.*GET_PACKED_FIELD_1. Could not find tuple in destination.");
397 trace.
set(Column::bc_hashing_packed_fields_1, 2, prepended_fields[4]);
400 trace.
set(Column::bc_hashing_pc_index_2, 2, 0);
405 "Failed.*GET_PACKED_FIELD_2. Could not find tuple in destination.");
408 trace.
set(Column::bc_hashing_pc_index_2, 2, 124);
415 trace.
set(Column::bc_hashing_bytecode_id, 2, 0);
420 "Failed.*GET_PACKED_FIELD_.*. Could not find tuple in destination.");
423TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativePaddingSelectors)
429 TestTraceContainer
trace = process_bc_hashing_trace({ fields }, { 1 }, {
bytecode.size() });
435 trace.
set(Column::bc_hashing_end, 2, 0);
438 trace.
set(Column::bc_hashing_end, 2, 1);
441 trace.
set(Column::bc_hashing_sel_not_padding_2, 2, 1);
444 trace.
set(Column::bc_hashing_sel_not_padding_2, 2, 0);
447 trace.
set(Column::bc_hashing_packed_fields_1, 2, 1);
450 trace.
set(Column::bc_hashing_packed_fields_2, 2, 1);
455TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativePaddingUnder)
461 prepended_fields.insert(prepended_fields.end(), fields.begin(), fields.end());
464 TestTraceContainer
trace = process_bc_hashing_trace({ fields }, { hash }, {
bytecode.size() });
470 trace.
set(Column::bc_hashing_sel_not_padding_1, 2, 1);
475 trace.
set(Column::bc_hashing_padding, 2, 1);
476 trace.
set(Column::bc_hashing_padding, 1, 1);
477 trace.
set(Column::bc_hashing_input_len, 1, 5);
478 check_relation<bc_hashing>(trace);
484 "Failed.*GET_PACKED_FIELD_1. Could not find tuple in destination.");
487TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativePaddingOver)
493 prepended_fields.insert(prepended_fields.end(), fields.begin(), fields.end());
496 TestTraceContainer
trace = process_bc_hashing_trace({ fields }, { hash }, {
bytecode.size() });
502 trace.
set(Column::bc_hashing_sel_not_padding_1, 2, 0);
507 trace.
set(Column::bc_hashing_padding, 2, 2);
508 trace.
set(Column::bc_hashing_padding, 1, 2);
509 trace.
set(Column::bc_hashing_packed_fields_1, 2, 0);
510 trace.
set(Column::bc_hashing_input_len, 1, 4);
511 check_relation<bc_hashing>(trace);
525TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativeInputLen)
531 TestTraceContainer
trace = process_bc_hashing_trace({ fields }, { 1 }, {
bytecode.size() });
536 trace.
set(Column::bc_hashing_input_len, 1, 0);
538 (check_interaction<BytecodeTraceBuilder, lookup_bc_hashing_poseidon2_hash_settings>(trace)),
539 "LOOKUP_BC_HASHING_POSEIDON2_HASH");
541 trace.
set(Column::bc_hashing_input_len, 1, 4);
544 trace.
set(Column::bc_hashing_input_len, 1, 0);
549TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativeRounds)
555 TestTraceContainer
trace = process_bc_hashing_trace({ fields }, { 1 }, {
bytecode.size() });
560 trace.
set(Column::bc_hashing_rounds_rem, 1, 3);
565 trace.
set(Column::bc_hashing_rounds_rem, 2, 2);
570TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativeOutputHash)
574 prepended_fields.insert(prepended_fields.end(), bytecode_fields.begin(), bytecode_fields.end());
576 TestTraceContainer
trace = process_bc_hashing_trace({ bytecode_fields }, { hash }, { bytecode_fields.size() * 31 });
578 check_relation<bc_hashing>(trace);
579 check_interaction<BytecodeTraceBuilder, lookup_bc_hashing_poseidon2_hash_settings>(trace);
582 trace.
set(Column::bc_hashing_bytecode_id, 2, 123);
584 (check_interaction<BytecodeTraceBuilder, lookup_bc_hashing_poseidon2_hash_settings>(trace)),
585 "LOOKUP_BC_HASHING_POSEIDON2_HASH");
588TEST_F(BytecodeHashingConstrainingTest, NegativeSingleBytecodeHashIncrements)
600 auto bad_hash =
poseidon2.
hash({ sep, bytecode_fields[1], bytecode_fields[2] });
602 auto trace = TestTraceContainer({
603 { { C::precomputed_first_row, 1 } },
605 { C::bc_hashing_end, 1 },
606 { C::bc_hashing_packed_fields_0, sep },
607 { C::bc_hashing_packed_fields_1, bytecode_fields[1] },
608 { C::bc_hashing_packed_fields_2, bytecode_fields[2] },
609 { C::bc_hashing_pc_index_1, 31 },
610 { C::bc_hashing_pc_index_2, 62 },
611 { C::bc_hashing_sel_not_padding_1, 1 },
612 { C::bc_hashing_sel_not_padding_2, 1 },
613 { C::bc_hashing_bytecode_id, bad_hash },
614 { C::bc_hashing_pc_index, 31 },
615 { C::bc_hashing_sel, 1 },
616 { C::bc_hashing_sel_not_start, 0 },
617 { C::bc_hashing_start, 1 },
630TEST_F(BytecodeHashingConstrainingTest, NegativeSingleBytecodeHashLength)
641 auto bad_hash =
poseidon2.
hash({ 0xa, 0xb, 0xc, sep, bytecode_fields[0], bytecode_fields[1], bytecode_fields[2] });
643 auto trace = TestTraceContainer({
644 { { C::precomputed_first_row, 1 } },
646 { C::bc_hashing_input_len, 7 },
647 { C::bc_hashing_packed_fields_0, sep },
648 { C::bc_hashing_packed_fields_1, bytecode_fields[0] },
649 { C::bc_hashing_packed_fields_2, bytecode_fields[1] },
650 { C::bc_hashing_pc_index_1, 0 },
651 { C::bc_hashing_pc_index_2, 31 },
652 { C::bc_hashing_sel_not_padding_1, 1 },
653 { C::bc_hashing_sel_not_padding_2, 1 },
654 { C::bc_hashing_bytecode_id, bad_hash },
655 { C::bc_hashing_pc_index, 0 },
656 { C::bc_hashing_rounds_rem, 2 },
657 { C::bc_hashing_sel, 1 },
658 { C::bc_hashing_start, 1 },
661 { C::bc_hashing_input_len, 7 },
662 { C::bc_hashing_end, 1 },
663 { C::bc_hashing_packed_fields_0, bytecode_fields[2] },
664 { C::bc_hashing_packed_fields_1, 0 },
665 { C::bc_hashing_packed_fields_2, 0 },
666 { C::bc_hashing_pc_index_1, 93 },
667 { C::bc_hashing_pc_index_2, 124 },
668 { C::bc_hashing_bytecode_id, bad_hash },
669 { C::bc_hashing_pc_index, 62 },
670 { C::bc_hashing_rounds_rem, 1 },
671 { C::bc_hashing_sel, 1 },
672 { C::bc_hashing_sel_not_start, 1 },
684 (check_interaction<BytecodeTraceBuilder, lookup_bc_hashing_poseidon2_hash_settings>(trace)),
685 "LOOKUP_BC_HASHING_POSEIDON2_HASH");
691TEST_F(BytecodeHashingConstrainingTest, NegativeSingleBytecodeHashLengthBytes)
703 auto bad_hash =
poseidon2.
hash({ sep, bytecode_fields[0], bytecode_fields[1], bytecode_fields[2] });
705 auto trace = TestTraceContainer({
706 { { C::precomputed_first_row, 1 } },
708 { C::bc_hashing_size_in_bytes, 92 },
709 { C::bc_hashing_input_len, 4 },
710 { C::bc_hashing_packed_fields_0, sep },
711 { C::bc_hashing_packed_fields_1, bytecode_fields[0] },
712 { C::bc_hashing_packed_fields_2, bytecode_fields[1] },
713 { C::bc_hashing_pc_index_1, 0 },
714 { C::bc_hashing_pc_index_2, 31 },
715 { C::bc_hashing_sel_not_padding_1, 1 },
716 { C::bc_hashing_sel_not_padding_2, 1 },
717 { C::bc_hashing_bytecode_id, bad_hash },
718 { C::bc_hashing_pc_index, 0 },
719 { C::bc_hashing_rounds_rem, 2 },
720 { C::bc_hashing_padding, 2 },
721 { C::bc_hashing_sel, 1 },
722 { C::bc_hashing_start, 1 },
725 { C::bc_hashing_input_len, 4 },
726 { C::bc_hashing_end, 1 },
727 { C::bc_hashing_packed_fields_0, bytecode_fields[2] },
728 { C::bc_hashing_packed_fields_1, 0 },
729 { C::bc_hashing_packed_fields_2, 0 },
730 { C::bc_hashing_pc_index_1, 93 },
731 { C::bc_hashing_pc_index_2, 124 },
732 { C::bc_hashing_bytecode_id, bad_hash },
733 { C::bc_hashing_pc_index, 62 },
734 { C::bc_hashing_rounds_rem, 1 },
735 { C::bc_hashing_sel, 1 },
736 { C::bc_hashing_sel_not_start, 1 },
750 (check_interaction<BytecodeTraceBuilder, perm_bc_hashing_bytecode_length_bytes_settings>(trace)),
751 "PERM_BC_HASHING_BYTECODE_LENGTH_BYTES");
761TEST_F(BytecodeHashingConstrainingTest, NegativeGhostRowInjectionBlocked)
765 TestTraceContainer
trace({
766 { { C::precomputed_first_row, 1 } },
768 { C::bc_hashing_sel, 0 },
769 { C::bc_hashing_sel_not_padding_1, 1 },
770 { C::bc_hashing_sel_not_padding_2, 0 },
779 trace.
set(C::bc_hashing_sel_not_padding_1, 1, 0);
780 trace.
set(C::bc_hashing_sel_not_padding_2, 1, 1);
787TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativePaddingPropagationMultiRow)
794 TestTraceContainer
trace = process_bc_hashing_trace({ fields }, { 1 }, {
bytecode.size() });
801 trace.
set(C::bc_hashing_padding, 2, 1);
806TEST_F(BytecodeHashingConstrainingTestTraceHelper, NegativeBytecodeFieldLengthViaPadding)
815 TestTraceContainer
trace = process_bc_hashing_trace({ fields }, { 1 }, {
bytecode.size() });
823 trace.
set(C::bc_hashing_padding, 1, 0);
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
StrictMock< MockGreaterThan > mock_gt
EventEmitter< Poseidon2PermutationMemoryEvent > perm_mem_event_emitter
EventEmitter< Poseidon2PermutationEvent > perm_event_emitter
EventEmitter< Poseidon2HashEvent > hash_event_emitter
Poseidon2TraceBuilder poseidon2_builder
StrictMock< MockExecutionIdManager > mock_execution_id_manager
static std::string get_subrelation_label(size_t index)
static constexpr size_t SR_PACKED_ROW_NEEDS_PERM_SELECTOR
static constexpr size_t SR_PADDING_CONSISTENCY
static constexpr size_t SR_SEL_NOT_PADDING_REQUIRES_SEL
static constexpr size_t SR_PADDING_PROPAGATION
static constexpr size_t SR_ROUNDS_DECREMENT
static constexpr size_t SR_SEL_ON_START_OR_END
static constexpr size_t SR_PADDING_END
static constexpr size_t SR_PC_INCREMENTS_2
static constexpr size_t SR_START_IS_FIRST_FIELD
static constexpr size_t SR_START_AFTER_LATCH
static constexpr size_t SR_PADDED_BY_ZERO_2
static constexpr size_t SR_PADDING_COMPUTATION
static constexpr size_t SR_PADDED_BY_ZERO_1
static std::string get_subrelation_label(size_t index)
static constexpr size_t SR_PC_INCREMENTS
static constexpr size_t SR_BYTECODE_LENGTH_FIELDS
static constexpr size_t SR_PC_INCREMENTS_1
void process_hash(const simulation::EventEmitterInterface< simulation::Poseidon2HashEvent >::Container &hash_events, TraceContainer &trace)
Processes the hash events for the Poseidon2 hash function. It populates the columns for the poseidon2...
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 set(Column col, uint32_t row, const FF &value, bool use_atomic_limbs=false)
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
PrecomputedTraceBuilder precomputed_builder
std::vector< uint8_t > bytecode
TEST_F(AvmRecursiveTests, TwoLayerAvmRecursion)
A test of the Two Layer AVM recursive verifier.
void check_multipermutation_interaction(tracegen::TestTraceContainer &trace)
std::vector< FF > encode_bytecode(std::span< const uint8_t > bytecode)
Encodes the bytecode into a vector of field elements. Each field element represents 31 bytes of the b...
FF compute_public_bytecode_first_field(size_t bytecode_size)
std::vector< uint8_t > random_bytes(size_t n)
TestTraceContainer empty_trace()
std::vector< FF > random_fields(size_t n)
permutation_settings< perm_bc_hashing_get_packed_field_2_settings_ > perm_bc_hashing_get_packed_field_2_settings
permutation_settings< perm_bc_hashing_get_packed_field_1_settings_ > perm_bc_hashing_get_packed_field_1_settings
permutation_settings< perm_bc_hashing_get_packed_field_0_settings_ > perm_bc_hashing_get_packed_field_0_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::vector< uint8_t > to_buffer(T const &value)