Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
merkle_check.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cmath>
5#include <cstdint>
6
22
23namespace bb::avm2::constraining {
24namespace {
25
26using ::testing::NiceMock;
27
28using simulation::EventEmitter;
29using simulation::MerkleCheck;
30using simulation::MerkleCheckEvent;
31using simulation::MockExecutionIdManager;
32using simulation::MockGreaterThan;
33using simulation::NoopEventEmitter;
34using simulation::Poseidon2;
35using simulation::Poseidon2HashEvent;
36using simulation::Poseidon2PermutationEvent;
37using simulation::Poseidon2PermutationMemoryEvent;
39
40using tracegen::MerkleCheckTraceBuilder;
41using tracegen::Poseidon2TraceBuilder;
42using tracegen::TestTraceContainer;
43
45using C = Column;
46using merkle_check = bb::avm2::merkle_check<FF>;
48
49TEST(MerkleCheckConstrainingTest, EmptyRow)
50{
51 check_relation<merkle_check>(testing::empty_trace());
52}
53
54TEST(MerkleCheckConstrainingTest, ComputationCannotBeStoppedPrematurely)
55{
56 TestTraceContainer trace({
57 { { C::precomputed_first_row, 1 }, { C::merkle_check_sel, 0 } },
58 { { C::merkle_check_sel, 1 } },
59 { { C::merkle_check_sel, 1 } },
60 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 } },
61 { { C::merkle_check_sel, 0 } },
62 });
63
64 check_relation<merkle_check>(
66
67 const uint32_t last_row_idx = 3;
68 // Negative test - now modify to an incorrect value
69 trace.set(C::merkle_check_end, last_row_idx, 0); // This should fail - end went from 1 back to 0
70
72 "COMPUTATION_FINISH_AT_END");
73}
74
75TEST(MerkleCheckConstrainingTest, EndCannotBeOneOnFirstRow)
76{
77 // First create a valid trace
78 TestTraceContainer trace({
79 // end is correctly 0 on first row
80 { { C::precomputed_first_row, 1 }, { C::merkle_check_sel, 0 }, { C::merkle_check_end, 0 } },
81 });
82
83 // Verify it works with correct values
84 check_relation<merkle_check>(trace);
85
86 // Negative test - now modify to an invalid value
87 trace.set(C::merkle_check_sel, 0, 1);
88 trace.set(C::merkle_check_end, 0, 1); // This should fail - end can't be 1 on first row
89
90 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace), "Relation merkle_check");
91}
92
93TEST(MerkleCheckConstrainingTest, SelectorOnEnd)
94{
95 // Test constraint: (start + end) * (1 - sel) = 0
96 // If end=1, sel must be 1
97 TestTraceContainer trace({
98 { { C::merkle_check_end, 1 }, { C::merkle_check_sel, 1 } }, // sel=1 when end=1 is correct
99 });
100
101 check_relation<merkle_check>(trace, merkle_check::SR_SELECTOR_ON_START_OR_END);
102
103 // Negative test - now modify to an incorrect value
104 trace.set(C::merkle_check_sel, 0, 0); // This should fail - sel cannot be 0 when end=1
105
106 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_SELECTOR_ON_START_OR_END),
107 "SELECTOR_ON_START_OR_END");
108}
109
110TEST(MerkleCheckConstrainingTest, SelectorOnStart)
111{
112 // Test constraint: (start + end) * (1 - sel) = 0
113 // If start=1, sel must be 1
114 TestTraceContainer trace({
115 { { C::merkle_check_start, 1 }, { C::merkle_check_sel, 1 } }, // sel=1 when start=1 is correct
116 });
117
118 check_relation<merkle_check>(trace, merkle_check::SR_SELECTOR_ON_START_OR_END);
119
120 // Negative test - now modify to an incorrect value
121 trace.set(C::merkle_check_sel, 0, 0); // This should fail - sel cannot be 0 when start=1
122
123 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_SELECTOR_ON_START_OR_END),
124 "SELECTOR_ON_START_OR_END");
125}
126
127TEST(MerkleCheckConstrainingTest, PropagateReadRoot)
128{
129 // Test constraint: NOT_END * (root' - root) = 0
130 // Root should stay the same in the next row unless it's an end row
131 // When end=1, the next root can be different
132 TestTraceContainer trace({
133 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_read_root, 123 } },
134 // Same leaf value is correct when NOT_END=1
135 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_read_root, 123 } },
136 // Different leaf value is allowed after end row
137 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_read_root, 456 } },
138 });
139
140 check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_READ_ROOT);
141
142 // Negative test - now modify to an incorrect value
143 trace.set(C::merkle_check_read_root, 1, 456); // This should fail - root should stay the same when NOT_END=1
144
145 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_READ_ROOT),
146 "PROPAGATE_READ_ROOT");
147}
148
149TEST(MerkleCheckConstrainingTest, PropagateWriteRoot)
150{
151 // Test constraint: NOT_END * (write_root' - write_root) = 0
152 // write_root should stay the same in the next row unless it's an end row
153 // When end=1, the next root can be different
154 TestTraceContainer trace({
155 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_write_root, 123 } },
156 // Same leaf value is correct when NOT_END=1
157 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write_root, 123 } },
158 // Different leaf value is allowed after end row
159 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write_root, 456 } },
160 });
161
162 check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_WRITE_ROOT);
163
164 // Negative test - now modify to an incorrect value
165 trace.set(C::merkle_check_write_root, 1, 456); // This should fail - root should stay the same when NOT_END=1
166
167 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_WRITE_ROOT),
168 "PROPAGATE_WRITE_ROOT");
169}
170
171TEST(MerkleCheckConstrainingTest, PropagateWrite)
172{
173 // Test constraint: NOT_END * (write' - write) = 0
174 // write should stay the same in the next row unless it's an end row
175 // When end=1, the next write flag can be different
176 TestTraceContainer trace({
177 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_write, 1 } },
178 // Same leaf value is correct when NOT_END=1
179 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write, 1 } },
180 // Different leaf value is allowed after end row
181 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write, 0 } },
182 });
183
184 check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_WRITE);
185
186 // Negative test - now modify to an incorrect value
187 trace.set(C::merkle_check_write, 1, 0); // This should fail - write should stay the same when NOT_END=1
188
189 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_WRITE), "PROPAGATE_WRITE");
190}
191
192TEST(MerkleCheckConstrainingTest, PathLenDecrements)
193{
194 TestTraceContainer trace({
195 // Decrements until path_len=0
196 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_path_len, 3 } },
197 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_path_len, 2 } },
198 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_path_len, 1 } },
199 // Path len can be different after end=1
200 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_path_len, 5 } },
201 });
202
203 check_relation<merkle_check>(trace, merkle_check::SR_PATH_LEN_DECREMENTS);
204
205 // Negative test - now modify to an incorrect value and verify it fails
206 trace.set(C::merkle_check_path_len, 1, 1); // Should be 2, change to 1
207
208 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_PATH_LEN_DECREMENTS),
209 "PATH_LEN_DECREMENTS");
210}
211
212TEST(MerkleCheckConstrainingTest, EndWhenPathLenOne)
213{
214 TestTraceContainer trace({
215 { { C::merkle_check_sel, 1 },
216 { C::merkle_check_path_len, 2 },
217 { C::merkle_check_path_len_min_one_inv, FF(1).invert() },
218 { C::merkle_check_end, 0 } },
219 { { C::merkle_check_sel, 1 },
220 { C::merkle_check_path_len, 1 },
221 { C::merkle_check_path_len_min_one_inv, 0 },
222 { C::merkle_check_end, 1 } },
223 });
224
225 check_relation<merkle_check>(trace, merkle_check::SR_END_IFF_REM_PATH_EMPTY);
226
227 // Negative test - now modify to an incorrect value and verify it fails
228 trace.set(C::merkle_check_end, 1, 0); // Should be 1, change to 0
229
230 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_END_IFF_REM_PATH_EMPTY),
231 "END_IFF_REM_PATH_EMPTY");
232}
233
234TEST(MerkleCheckConstrainingTest, NextIndexIsHalved)
235{
236 TestTraceContainer trace({
237 { { C::merkle_check_sel, 1 },
238 { C::merkle_check_end, 0 },
239 { C::merkle_check_index, 6 },
240 { C::merkle_check_index_is_even, 1 } },
241 { { C::merkle_check_sel, 1 },
242 { C::merkle_check_end, 0 },
243 { C::merkle_check_index, 3 }, // 6/2 = 3
244 { C::merkle_check_index_is_even, 0 } },
245 { { C::merkle_check_sel, 1 },
246 { C::merkle_check_end, 1 }, // Set end=1 for final row
247 { C::merkle_check_index, 1 }, // 3/2 = 1
248 { C::merkle_check_index_is_even, 0 } },
249 });
250
251 check_relation<merkle_check>(trace, merkle_check::SR_NEXT_INDEX_IS_HALVED);
252
253 // Test with odd index
254 TestTraceContainer trace2({
255 { { C::merkle_check_sel, 1 },
256 { C::merkle_check_end, 0 },
257 { C::merkle_check_index, 7 },
258 { C::merkle_check_index_is_even, 0 } },
259 { { C::merkle_check_sel, 1 },
260 { C::merkle_check_end, 0 },
261 { C::merkle_check_index, 3 }, // (7-1)/2 = 3
262 { C::merkle_check_index_is_even, 0 } },
263 { { C::merkle_check_sel, 1 },
264 { C::merkle_check_end, 1 }, // Set end=1 for final row
265 { C::merkle_check_index, 1 }, // 6/2 = 3
266 { C::merkle_check_index_is_even, 0 } },
267 });
268
269 check_relation<merkle_check>(trace2, merkle_check::SR_NEXT_INDEX_IS_HALVED);
270
271 // Negative test - now modify to an incorrect value and verify it fails
272 trace2.set(C::merkle_check_index, 1, 4); // Should be 3, change to 4
273
274 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace2, merkle_check::SR_NEXT_INDEX_IS_HALVED),
275 "NEXT_INDEX_IS_HALVED");
276}
277
278TEST(MerkleCheckConstrainingTest, AssignReadNodesEven)
279{
280 // Test even index (current_node goes to left_node and sibling goes to right_node)
281 TestTraceContainer trace({
282 {
283 { C::merkle_check_sel, 1 },
284 { C::merkle_check_index_is_even, 1 },
285 { C::merkle_check_read_node, 123 },
286 { C::merkle_check_sibling, 456 },
287 { C::merkle_check_read_left_node, 123 },
288 { C::merkle_check_read_right_node, 456 },
289 },
290 });
291
292 check_relation<merkle_check>(trace, merkle_check::SR_READ_LEFT_NODE, merkle_check::SR_READ_RIGHT_NODE);
293
294 // Negative test - swap values of read_left_node and read_right_node
295 trace.set(C::merkle_check_read_left_node, 0, 456);
296 trace.set(C::merkle_check_read_right_node, 0, 123);
297
298 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_READ_RIGHT_NODE), "READ_RIGHT_NODE");
299 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_READ_LEFT_NODE), "READ_LEFT_NODE");
300}
301
302TEST(MerkleCheckConstrainingTest, AssignReadNodesOdd)
303{
304 // Test odd index (current_node goes to right_node and sibling goes to left_node)
305 TestTraceContainer trace({
306 {
307 { C::merkle_check_sel, 1 },
308 { C::merkle_check_index_is_even, 0 },
309 { C::merkle_check_read_node, 123 },
310 { C::merkle_check_sibling, 456 },
311 { C::merkle_check_read_left_node, 456 },
312 { C::merkle_check_read_right_node, 123 },
313 },
314 });
315
316 check_relation<merkle_check>(trace, merkle_check::SR_READ_LEFT_NODE, merkle_check::SR_READ_RIGHT_NODE);
317
318 // Negative test - swap values of read_left_node and read_right_node
319 trace.set(C::merkle_check_read_left_node, 0, 123);
320 trace.set(C::merkle_check_read_right_node, 0, 456);
321
322 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_READ_RIGHT_NODE), "READ_RIGHT_NODE");
323 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_READ_LEFT_NODE), "READ_LEFT_NODE");
324}
325
326TEST(MerkleCheckConstrainingTest, AssignWriteNodesEven)
327{
328 // Test even index (current_node goes to left_node and sibling goes to right_node)
329 TestTraceContainer trace({
330 {
331 { C::merkle_check_sel, 1 },
332 { C::merkle_check_write, 1 },
333 { C::merkle_check_index_is_even, 1 },
334 { C::merkle_check_write_node, 123 },
335 { C::merkle_check_sibling, 456 },
336 { C::merkle_check_write_left_node, 123 },
337 { C::merkle_check_write_right_node, 456 },
338 },
339 });
340
341 check_relation<merkle_check>(trace, merkle_check::SR_WRITE_LEFT_NODE, merkle_check::SR_WRITE_RIGHT_NODE);
342
343 // Negative test - swap values of write_left_node and write_right_node
344 trace.set(C::merkle_check_write_left_node, 0, 456);
345 trace.set(C::merkle_check_write_right_node, 0, 123);
346
347 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_WRITE_RIGHT_NODE),
348 "WRITE_RIGHT_NODE");
349 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_WRITE_LEFT_NODE), "WRITE_LEFT_NODE");
350}
351
352TEST(MerkleCheckConstrainingTest, AssignWriteNodesOdd)
353{
354 // Test odd index (current_node goes to right_node and sibling goes to left_node)
355 TestTraceContainer trace({
356 {
357 { C::merkle_check_sel, 1 },
358 { C::merkle_check_write, 1 },
359 { C::merkle_check_index_is_even, 0 },
360 { C::merkle_check_write_node, 123 },
361 { C::merkle_check_sibling, 456 },
362 { C::merkle_check_write_left_node, 456 },
363 { C::merkle_check_write_right_node, 123 },
364 },
365 });
366
367 check_relation<merkle_check>(trace, merkle_check::SR_WRITE_LEFT_NODE, merkle_check::SR_WRITE_RIGHT_NODE);
368
369 // Negative test - swap values of write_left_node and write_right_node
370 trace.set(C::merkle_check_write_left_node, 0, 123);
371 trace.set(C::merkle_check_write_right_node, 0, 456);
372
373 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_WRITE_RIGHT_NODE),
374 "WRITE_RIGHT_NODE");
375 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_WRITE_LEFT_NODE), "WRITE_LEFT_NODE");
376}
377
378TEST(MerkleCheckConstrainingTest, ReadOutputHashIsNextRowsNode)
379{
380 FF left_node = FF(123);
381 FF right_node = FF(456);
382 FF output_hash = UnconstrainedPoseidon2::hash({ left_node, right_node });
383
384 TestTraceContainer trace({
385 { { C::merkle_check_sel, 1 },
386 { C::merkle_check_end, 0 },
387 { C::merkle_check_read_node, left_node },
388 { C::merkle_check_read_right_node, right_node },
389 { C::merkle_check_read_output_hash, output_hash } },
390 { { C::merkle_check_sel, 1 },
391 { C::merkle_check_end, 1 }, // Set end=1 for final row
392 { C::merkle_check_read_node, output_hash } },
393 });
394
395 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE);
396
397 // Negative test - now modify to an incorrect value and verify it fails
398 trace.set(C::merkle_check_read_node, 1, output_hash + 1); // Should be output_hash
399
401 "OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE");
402}
403
404TEST(MerkleCheckConstrainingTest, WriteOutputHashIsNextRowsNode)
405{
406 FF left_node = FF(123);
407 FF right_node = FF(456);
408 FF output_hash = UnconstrainedPoseidon2::hash({ left_node, right_node });
409
410 TestTraceContainer trace({
411 { { C::merkle_check_sel, 1 },
412 { C::merkle_check_end, 0 },
413 { C::merkle_check_write_node, left_node },
414 { C::merkle_check_write_right_node, right_node },
415 { C::merkle_check_write_output_hash, output_hash } },
416 { { C::merkle_check_sel, 1 },
417 { C::merkle_check_end, 1 }, // Set end=1 for final row
418 { C::merkle_check_write_node, output_hash } },
419 });
420
421 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE);
422
423 // Negative test - now modify to an incorrect value and verify it fails
424 trace.set(C::merkle_check_write_node, 1, output_hash + 1); // Should be output_hash
425
427 "OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE");
428}
429
430TEST(MerkleCheckConstrainingTest, OutputHashIsNotNextRowsCurrentNodeValueForLastRow)
431{
432 FF output_hash = FF(456);
433 FF next_current_node = FF(789);
434
435 TestTraceContainer trace({
436 { { C::merkle_check_sel, 1 },
437 { C::merkle_check_end, 1 },
438 { C::merkle_check_read_output_hash, output_hash },
439 { C::merkle_check_write_output_hash, output_hash } },
440 { { C::merkle_check_sel, 1 },
441 { C::merkle_check_read_node, next_current_node },
442 { C::merkle_check_write_node, next_current_node } },
443 });
444
445 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE);
446 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE);
447}
448
449TEST(MerkleCheckConstrainingTest, ReadWithTracegen)
450{
451 TestTraceContainer trace({
452 { { C::precomputed_first_row, 1 } },
453 });
454 MerkleCheckTraceBuilder builder;
455
456 // Create a Merkle tree path with 3 levels
457 FF leaf_value = FF(123);
458 uint64_t leaf_index = 5;
459
460 // Create a sibling path of length 3
461 std::vector<FF> sibling_path = { FF(456), FF(789), FF(3333) };
462
463 // Compute expected root
464 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
465
466 MerkleCheckEvent event = {
467 .leaf_value = leaf_value, .leaf_index = leaf_index, .sibling_path = sibling_path, .root = root
468 };
469
470 builder.process({ event }, trace);
471
472 // Check the relation for all rows
473 check_relation<merkle_check>(trace);
474
475 // Negative test - now corrupt the trace and verify it fails
476 uint32_t last_row = static_cast<uint32_t>(trace.get_num_rows() - 1);
477 // Corrupt the last row
478 trace.set(C::merkle_check_path_len, last_row, 66);
479
480 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace), "Relation merkle_check");
481}
482
483TEST(MerkleCheckConstrainingTest, WriteWithTracegen)
484{
485 TestTraceContainer trace({
486 { { C::precomputed_first_row, 1 } },
487 });
488 MerkleCheckTraceBuilder builder;
489
490 // Create a Merkle tree path with 3 levels
491 FF leaf_value = FF(123);
492 FF new_leaf_value = FF(456);
493 uint64_t leaf_index = 5;
494
495 // Create a sibling path of length 3
496 std::vector<FF> sibling_path = { FF(456), FF(789), FF(3333) };
497
498 // Compute read root
499 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
500 // Compute new root
501 FF new_root = unconstrained_root_from_path(new_leaf_value, leaf_index, sibling_path);
502
503 MerkleCheckEvent event = { .leaf_value = leaf_value,
504 .new_leaf_value = new_leaf_value,
505 .leaf_index = leaf_index,
506 .sibling_path = sibling_path,
507 .root = root,
508 .new_root = new_root };
509
510 builder.process({ event }, trace);
511
512 // Check the relation for all rows
513 check_relation<merkle_check>(trace);
514}
515
516class MerkleCheckPoseidon2Test : public ::testing::Test {
517 protected:
518 MerkleCheckPoseidon2Test() = default;
519
520 EventEmitter<Poseidon2HashEvent> hash_event_emitter;
521 NoopEventEmitter<Poseidon2PermutationEvent> perm_event_emitter;
522 NoopEventEmitter<Poseidon2PermutationMemoryEvent> perm_mem_event_emitter;
523
524 NiceMock<MockExecutionIdManager> execution_id_manager;
525 NiceMock<MockGreaterThan> mock_gt;
527 Poseidon2(execution_id_manager, mock_gt, hash_event_emitter, perm_event_emitter, perm_mem_event_emitter);
528};
529
530TEST_F(MerkleCheckPoseidon2Test, ReadWithInteractions)
531{
532 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
533 MerkleCheck merkle_check_sim(poseidon2, merkle_event_emitter);
534
535 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
536 Poseidon2TraceBuilder poseidon2_builder;
537 MerkleCheckTraceBuilder merkle_check_builder;
538
539 FF leaf_value = 333;
540 uint64_t leaf_index = 30;
541 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
542 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
543 merkle_check_sim.assert_membership(leaf_value, leaf_index, sibling_path, root);
544
546 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
547
548 check_interaction<MerkleCheckTraceBuilder,
551
552 check_relation<merkle_check>(trace);
553
554 // Negative test - now corrupt the trace and verify it fails
555 trace.set(Column::merkle_check_read_output_hash, static_cast<uint32_t>(sibling_path.size()), 66);
556
558 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_read_settings>(trace)),
559 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2.* Could not find tuple in destination");
560 check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_write_settings>(trace);
561}
562
563TEST_F(MerkleCheckPoseidon2Test, WriteWithInteractions)
564{
565 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
566 MerkleCheck merkle_check_sim(poseidon2, merkle_event_emitter);
567
568 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
569 Poseidon2TraceBuilder poseidon2_builder;
570 MerkleCheckTraceBuilder merkle_check_builder;
571
572 FF leaf_value = 333;
573 FF new_leaf_value = 444;
574 uint64_t leaf_index = 30;
575 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
576 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
577 FF expected_new_root = unconstrained_root_from_path(new_leaf_value, leaf_index, sibling_path);
578
579 FF new_root = merkle_check_sim.write(leaf_value, new_leaf_value, leaf_index, sibling_path, root);
580
581 EXPECT_EQ(new_root, expected_new_root);
582
584 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
585
586 check_interaction<MerkleCheckTraceBuilder,
589
590 check_relation<merkle_check>(trace);
591
592 // Negative test - now corrupt the trace and verify it fails
593 trace.set(Column::merkle_check_read_output_hash, static_cast<uint32_t>(sibling_path.size()), 66);
594 trace.set(Column::merkle_check_write_output_hash, static_cast<uint32_t>(sibling_path.size()), 77);
595
597 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_read_settings>(trace)),
598 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2.* Could not find tuple in destination");
599
601 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_write_settings>(trace)),
602 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2_WRITE.* Could not find tuple in "
603 "destination");
604}
605
606TEST_F(MerkleCheckPoseidon2Test, MultipleWithTracegen)
607{
608 TestTraceContainer trace({
609 { { C::precomputed_first_row, 1 } },
610 });
611 MerkleCheckTraceBuilder builder;
612
613 FF leaf_value = 333;
614 uint64_t leaf_index = 30;
615 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
616 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
617 MerkleCheckEvent event = {
618 .leaf_value = leaf_value, .leaf_index = leaf_index, .sibling_path = sibling_path, .root = root
619 };
620
621 FF leaf_value2 = 444;
622 FF new_leaf_value2 = 555;
623 uint64_t leaf_index2 = 40;
624 std::vector<FF> sibling_path2 = { 11, 22, 33, 44, 55, 66 };
625 FF root2 = unconstrained_root_from_path(leaf_value2, leaf_index2, sibling_path2);
626 FF new_root2 = unconstrained_root_from_path(new_leaf_value2, leaf_index2, sibling_path2);
627 MerkleCheckEvent event2 = { .leaf_value = leaf_value2,
628 .new_leaf_value = new_leaf_value2,
629 .leaf_index = leaf_index2,
630 .sibling_path = sibling_path2,
631 .root = root2,
632 .new_root = new_root2 };
633
634 builder.process({ event, event2 }, trace);
635
636 // Empty row after last real merkle row
637 uint32_t after_last_row_index = 1 + static_cast<uint32_t>(sibling_path.size() + sibling_path2.size());
638 trace.set(Column::merkle_check_sel, after_last_row_index, 0);
639 trace.set(Column::merkle_check_write, after_last_row_index, 0);
640 trace.set(Column::merkle_check_read_node, after_last_row_index, 0);
641 trace.set(Column::merkle_check_write_node, after_last_row_index, 0);
642 trace.set(Column::merkle_check_index, after_last_row_index, 0);
643 trace.set(Column::merkle_check_path_len, after_last_row_index, 0);
644 trace.set(Column::merkle_check_path_len_min_one_inv, after_last_row_index, 0);
645 trace.set(Column::merkle_check_read_root, after_last_row_index, 0);
646 trace.set(Column::merkle_check_write_root, after_last_row_index, 0);
647 trace.set(Column::merkle_check_sibling, after_last_row_index, 0);
648 trace.set(Column::merkle_check_start, after_last_row_index, 0);
649 trace.set(Column::merkle_check_end, after_last_row_index, 0);
650 trace.set(Column::merkle_check_index_is_even, after_last_row_index, 0);
651 trace.set(Column::merkle_check_read_left_node, after_last_row_index, 0);
652 trace.set(Column::merkle_check_read_right_node, after_last_row_index, 0);
653 trace.set(Column::merkle_check_write_left_node, after_last_row_index, 0);
654 trace.set(Column::merkle_check_write_right_node, after_last_row_index, 0);
655 trace.set(Column::merkle_check_read_output_hash, after_last_row_index, 0);
656 trace.set(Column::merkle_check_write_output_hash, after_last_row_index, 0);
657
658 check_relation<merkle_check>(trace);
659}
660
661TEST_F(MerkleCheckPoseidon2Test, MultipleWithInteractions)
662{
663 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
664 MerkleCheck merkle_check_sim(poseidon2, merkle_event_emitter);
665
666 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
667 MerkleCheckTraceBuilder merkle_check_builder;
668 Poseidon2TraceBuilder poseidon2_builder;
669
670 FF leaf_value = 333;
671 uint64_t leaf_index = 30;
672 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
673 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
674
675 merkle_check_sim.assert_membership(leaf_value, leaf_index, sibling_path, root);
676
677 FF leaf_value2 = 444;
678 FF new_leaf_value2 = 555;
679 uint64_t leaf_index2 = 40;
680 std::vector<FF> sibling_path2 = { 11, 22, 33, 44, 55, 66 };
681 FF root2 = unconstrained_root_from_path(leaf_value2, leaf_index2, sibling_path2);
682 FF expected_new_root2 = unconstrained_root_from_path(new_leaf_value2, leaf_index2, sibling_path2);
683
684 FF new_root2 = merkle_check_sim.write(leaf_value2, new_leaf_value2, leaf_index2, sibling_path2, root2);
685 EXPECT_EQ(new_root2, expected_new_root2);
686
688 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
689
690 check_interaction<MerkleCheckTraceBuilder,
693
694 check_relation<merkle_check>(trace);
695}
696
697} // namespace
698} // namespace bb::avm2::constraining
StrictMock< MockGreaterThan > mock_gt
EventEmitter< Poseidon2PermutationMemoryEvent > perm_mem_event_emitter
EventEmitter< Poseidon2PermutationEvent > perm_event_emitter
EventEmitter< Poseidon2HashEvent > hash_event_emitter
Poseidon2TraceBuilder poseidon2_builder
static constexpr size_t SR_READ_RIGHT_NODE
static constexpr size_t SR_OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE
static constexpr size_t SR_READ_LEFT_NODE
static constexpr size_t SR_PROPAGATE_READ_ROOT
static constexpr size_t SR_PROPAGATE_WRITE
static constexpr size_t SR_WRITE_RIGHT_NODE
static constexpr size_t SR_NEXT_INDEX_IS_HALVED
static constexpr size_t SR_PROPAGATE_WRITE_ROOT
static constexpr size_t SR_SELECTOR_ON_START_OR_END
static constexpr size_t SR_PATH_LEN_DECREMENTS
static constexpr size_t SR_WRITE_LEFT_NODE
static constexpr size_t SR_OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE
static constexpr size_t SR_END_IFF_REM_PATH_EMPTY
static constexpr size_t SR_COMPUTATION_FINISH_AT_END
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_hash(const simulation::EventEmitterInterface< simulation::Poseidon2HashEvent >::Container &hash_events, TraceContainer &trace)
void set(Column col, uint32_t row, const FF &value)
Implements a parallelized batch insertion indexed tree Accepts template argument of the type of store...
AluTraceBuilder builder
Definition alu.test.cpp:124
ExecutionIdManager execution_id_manager
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TEST_F(AvmRecursiveTests, GoblinRecursion)
A test of the Goblinized AVM recursive verifier.
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:441
FF unconstrained_root_from_path(const FF &leaf_value, const uint64_t leaf_index, std::span< const FF > path)
Definition merkle.cpp:12
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
lookup_settings< lookup_merkle_check_merkle_poseidon2_read_settings_ > lookup_merkle_check_merkle_poseidon2_read_settings
lookup_settings< lookup_merkle_check_merkle_poseidon2_write_settings_ > lookup_merkle_check_merkle_poseidon2_write_settings
AvmFlavorSettings::FF FF
Definition field.hpp:10
simulation::PublicDataTreeReadWriteEvent event