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, TraceContinuity)
55{
56 // Test that the trace is contiguous
57 TestTraceContainer trace({
58 { { C::precomputed_first_row, 1 }, { C::merkle_check_sel, 0 } },
59 { { C::merkle_check_sel, 1 } },
60 { { C::merkle_check_sel, 1 } },
61 { { C::merkle_check_sel, 0 } },
62 { { C::merkle_check_sel, 0 } },
63 });
64
65 check_relation<merkle_check>(trace, merkle_check::SR_TRACE_CONTINUITY);
66
67 const uint32_t last_row_idx = 4;
68 // Negative test - now modify to an incorrect value
69 trace.set(C::merkle_check_sel, last_row_idx, 1); // This should fail - sel went from 0 back to 1
70
72 "TRACE_CONTINUITY");
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, StartAfterLatch)
94{
95 // Test constraint: sel' * (start' - LATCH_CONDITION) = 0
96 // After a row with end=1, the next row with sel=1 must have start=1
97 TestTraceContainer trace({
98 { { C::merkle_check_sel, 1 },
99 { C::merkle_check_start, 0 },
100 { C::merkle_check_end, 1 } }, // end=1 triggers LATCH_CONDITION
101 { { C::merkle_check_sel, 1 }, { C::merkle_check_start, 1 } }, // start=1 after LATCH is correct
102 });
103
104 check_relation<merkle_check>(trace, merkle_check::SR_START_AFTER_LATCH);
105
106 // First row has precomputed_first_row=1, which also triggers LATCH_CONDITION
107 TestTraceContainer trace2({
108 { { C::precomputed_first_row, 1 }, { C::merkle_check_sel, 0 } },
109 { { C::merkle_check_sel, 1 }, { C::merkle_check_start, 1 } }, // start=1 after precomputed_first_row is correct
110 });
111
112 check_relation<merkle_check>(trace2, merkle_check::SR_START_AFTER_LATCH);
113
114 // Negative test - start=0 after LATCH
115 trace.set(C::merkle_check_start, 1, 0); // This should fail - start should be 1 after LATCH
116
118 "START_AFTER_LATCH");
119}
120
121TEST(MerkleCheckConstrainingTest, SelectorOnEnd)
122{
123 // Test constraint: end * (1 - sel) = 0
124 // If end=1, sel must be 1
125 TestTraceContainer trace({
126 { { C::merkle_check_end, 1 }, { C::merkle_check_sel, 1 } }, // sel=1 when end=1 is correct
127 });
128
129 check_relation<merkle_check>(trace, merkle_check::SR_SELECTOR_ON_END);
130
131 // Negative test - now modify to an incorrect value
132 trace.set(C::merkle_check_sel, 0, 0); // This should fail - sel cannot be 0 when end=1
133
134 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_SELECTOR_ON_END), "SELECTOR_ON_END");
135}
136
137TEST(MerkleCheckConstrainingTest, PropagateReadRoot)
138{
139 // Test constraint: NOT_END * (root' - root) = 0
140 // Root should stay the same in the next row unless it's an end row
141 // When end=1, the next root can be different
142 TestTraceContainer trace({
143 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_read_root, 123 } },
144 // Same leaf value is correct when NOT_END=1
145 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_read_root, 123 } },
146 // Different leaf value is allowed after end row
147 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_read_root, 456 } },
148 });
149
150 check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_READ_ROOT);
151
152 // Negative test - now modify to an incorrect value
153 trace.set(C::merkle_check_read_root, 1, 456); // This should fail - root should stay the same when NOT_END=1
154
156 "PROPAGATE_READ_ROOT");
157}
158
159TEST(MerkleCheckConstrainingTest, PropagateWriteRoot)
160{
161 // Test constraint: NOT_END * (write_root' - write_root) = 0
162 // write_root should stay the same in the next row unless it's an end row
163 // When end=1, the next root can be different
164 TestTraceContainer trace({
165 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_write_root, 123 } },
166 // Same leaf value is correct when NOT_END=1
167 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write_root, 123 } },
168 // Different leaf value is allowed after end row
169 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write_root, 456 } },
170 });
171
172 check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_WRITE_ROOT);
173
174 // Negative test - now modify to an incorrect value
175 trace.set(C::merkle_check_write_root, 1, 456); // This should fail - root should stay the same when NOT_END=1
176
178 "PROPAGATE_WRITE_ROOT");
179}
180
181TEST(MerkleCheckConstrainingTest, PropagateWrite)
182{
183 // Test constraint: NOT_END * (write' - write) = 0
184 // write should stay the same in the next row unless it's an end row
185 // When end=1, the next write flag can be different
186 TestTraceContainer trace({
187 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_write, 1 } },
188 // Same leaf value is correct when NOT_END=1
189 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write, 1 } },
190 // Different leaf value is allowed after end row
191 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write, 0 } },
192 });
193
194 check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_WRITE);
195
196 // Negative test - now modify to an incorrect value
197 trace.set(C::merkle_check_write, 1, 0); // This should fail - write should stay the same when NOT_END=1
198
199 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace, merkle_check::SR_PROPAGATE_WRITE), "PROPAGATE_WRITE");
200}
201
202TEST(MerkleCheckConstrainingTest, PathLenDecrements)
203{
204 TestTraceContainer trace({
205 // Decrements until path_len=0
206 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_path_len, 3 } },
207 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_path_len, 2 } },
208 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_path_len, 1 } },
209 // Path len can be different after end=1
210 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_path_len, 5 } },
211 });
212
213 check_relation<merkle_check>(trace, merkle_check::SR_PATH_LEN_DECREMENTS);
214
215 // Negative test - now modify to an incorrect value and verify it fails
216 trace.set(C::merkle_check_path_len, 1, 1); // Should be 2, change to 1
217
219 "PATH_LEN_DECREMENTS");
220}
221
222TEST(MerkleCheckConstrainingTest, EndWhenPathLenOne)
223{
224 TestTraceContainer trace({
225 { { C::merkle_check_sel, 1 },
226 { C::merkle_check_path_len, 2 },
227 { C::merkle_check_remaining_path_len_inv, FF(1).invert() },
228 { C::merkle_check_end, 0 } },
229 { { C::merkle_check_sel, 1 },
230 { C::merkle_check_path_len, 1 },
231 { C::merkle_check_remaining_path_len_inv, 0 },
232 { C::merkle_check_end, 1 } },
233 });
234
235 check_relation<merkle_check>(trace, merkle_check::SR_END_WHEN_PATH_EMPTY);
236
237 // Negative test - now modify to an incorrect value and verify it fails
238 trace.set(C::merkle_check_end, 1, 0); // Should be 1, change to 0
239
241 "END_WHEN_PATH_EMPTY");
242}
243
244TEST(MerkleCheckConstrainingTest, NextIndexIsHalved)
245{
246 TestTraceContainer trace({
247 { { C::merkle_check_sel, 1 },
248 { C::merkle_check_end, 0 },
249 { C::merkle_check_index, 6 },
250 { C::merkle_check_index_is_even, 1 } },
251 { { C::merkle_check_sel, 1 },
252 { C::merkle_check_end, 0 },
253 { C::merkle_check_index, 3 }, // 6/2 = 3
254 { C::merkle_check_index_is_even, 0 } },
255 { { C::merkle_check_sel, 1 },
256 { C::merkle_check_end, 1 }, // Set end=1 for final row
257 { C::merkle_check_index, 1 }, // 3/2 = 1
258 { C::merkle_check_index_is_even, 0 } },
259 });
260
261 check_relation<merkle_check>(trace, merkle_check::SR_NEXT_INDEX_IS_HALVED);
262
263 // Test with odd index
264 TestTraceContainer trace2({
265 { { C::merkle_check_sel, 1 },
266 { C::merkle_check_end, 0 },
267 { C::merkle_check_index, 7 },
268 { C::merkle_check_index_is_even, 0 } },
269 { { C::merkle_check_sel, 1 },
270 { C::merkle_check_end, 0 },
271 { C::merkle_check_index, 3 }, // (7-1)/2 = 3
272 { C::merkle_check_index_is_even, 0 } },
273 { { C::merkle_check_sel, 1 },
274 { C::merkle_check_end, 1 }, // Set end=1 for final row
275 { C::merkle_check_index, 1 }, // 6/2 = 3
276 { C::merkle_check_index_is_even, 0 } },
277 });
278
279 check_relation<merkle_check>(trace2, merkle_check::SR_NEXT_INDEX_IS_HALVED);
280
281 // Negative test - now modify to an incorrect value and verify it fails
282 trace2.set(C::merkle_check_index, 1, 4); // Should be 3, change to 4
283
284 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace2, merkle_check::SR_NEXT_INDEX_IS_HALVED),
285 "NEXT_INDEX_IS_HALVED");
286}
287
288TEST(MerkleCheckConstrainingTest, AssignCurrentReadNodeLeftOrRight)
289{
290 // Test even index (current_node goes to left_node)
291 TestTraceContainer trace({
292 { { C::merkle_check_sel, 1 },
293 { C::merkle_check_index_is_even, 1 },
294 { C::merkle_check_read_node, 123 },
295 { C::merkle_check_sibling, 456 },
296 { C::merkle_check_read_left_node, 123 },
297 { C::merkle_check_read_right_node, 456 } },
298 });
299
300 check_relation<merkle_check>(trace, merkle_check::SR_ASSIGN_NODE_LEFT_OR_RIGHT_READ);
301
302 // Test odd index (current_node goes to right_node)
303 TestTraceContainer trace2({
304 { { C::merkle_check_sel, 1 },
305 { C::merkle_check_index_is_even, 0 },
306 { C::merkle_check_read_node, 123 },
307 { C::merkle_check_sibling, 456 },
308 { C::merkle_check_read_left_node, 456 },
309 { C::merkle_check_read_right_node, 123 } },
310 });
311
312 check_relation<merkle_check>(trace2, merkle_check::SR_ASSIGN_NODE_LEFT_OR_RIGHT_READ);
313
314 // Negative test - now modify to an incorrect value and verify it fails
315 trace2.set(C::merkle_check_read_left_node, 0, 123); // Should be 456
316 trace2.set(C::merkle_check_read_right_node, 0, 456); // Should be 123
317
319 "ASSIGN_NODE_LEFT_OR_RIGHT_READ");
320}
321
322TEST(MerkleCheckConstrainingTest, AssignCurrentWriteNodeLeftOrRight)
323{
324 // Test even index (current_node goes to left_node)
325 TestTraceContainer trace({
326 { { C::merkle_check_write, 1 },
327 { C::merkle_check_index_is_even, 1 },
328 { C::merkle_check_write_node, 123 },
329 { C::merkle_check_sibling, 456 },
330 { C::merkle_check_write_left_node, 123 },
331 { C::merkle_check_write_right_node, 456 } },
332 });
333
334 check_relation<merkle_check>(trace, merkle_check::SR_ASSIGN_NODE_LEFT_OR_RIGHT_WRITE);
335
336 // Test odd index (current_node goes to right_node)
337 TestTraceContainer trace2({
338 { { C::merkle_check_write, 1 },
339 { C::merkle_check_index_is_even, 0 },
340 { C::merkle_check_write_node, 123 },
341 { C::merkle_check_sibling, 456 },
342 { C::merkle_check_write_left_node, 456 },
343 { C::merkle_check_write_right_node, 123 } },
344 });
345
346 check_relation<merkle_check>(trace2, merkle_check::SR_ASSIGN_NODE_LEFT_OR_RIGHT_WRITE);
347
348 // Negative test - now modify to an incorrect value and verify it fails
349 trace2.set(C::merkle_check_write_left_node, 0, 123); // Should be 456
350 trace2.set(C::merkle_check_write_right_node, 0, 456); // Should be 123
351
353 "ASSIGN_NODE_LEFT_OR_RIGHT_WRITE");
354}
355
356TEST(MerkleCheckConstrainingTest, AssignSiblingLeftOrRightRead)
357{
358 // Test even index (sibling goes to right_node)
359 TestTraceContainer trace({
360 { { C::merkle_check_sel, 1 },
361 { C::merkle_check_index_is_even, 1 },
362 { C::merkle_check_read_node, 123 },
363 { C::merkle_check_sibling, 456 },
364 { C::merkle_check_read_left_node, 123 },
365 { C::merkle_check_read_right_node, 456 } },
366 });
367
368 check_relation<merkle_check>(trace, merkle_check::SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_READ);
369
370 // Test odd index (sibling goes to left_node)
371 TestTraceContainer trace2({
372 { { C::merkle_check_sel, 1 },
373 { C::merkle_check_index_is_even, 0 },
374 { C::merkle_check_read_node, 123 },
375 { C::merkle_check_sibling, 456 },
376 { C::merkle_check_read_left_node, 456 },
377 { C::merkle_check_read_right_node, 123 } },
378 });
379
380 check_relation<merkle_check>(trace2, merkle_check::SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_READ);
381
382 // Negative test - now modify to an incorrect value and verify it fails
383 trace2.set(C::merkle_check_read_left_node, 0, 123); // Should be 456
384 trace2.set(C::merkle_check_read_right_node, 0, 456); // Should be 123
385
387 "ASSIGN_SIBLING_LEFT_OR_RIGHT_READ");
388}
389
390TEST(MerkleCheckConstrainingTest, AssignSiblingLeftOrRightWrite)
391{
392 // Test even index (sibling goes to right_node)
393 TestTraceContainer trace({
394 { { C::merkle_check_write, 1 },
395 { C::merkle_check_index_is_even, 1 },
396 { C::merkle_check_write_node, 123 },
397 { C::merkle_check_sibling, 456 },
398 { C::merkle_check_write_left_node, 123 },
399 { C::merkle_check_write_right_node, 456 } },
400 });
401
402 check_relation<merkle_check>(trace, merkle_check::SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_WRITE);
403
404 // Test odd index (sibling goes to left_node)
405 TestTraceContainer trace2({
406 { { C::merkle_check_write, 1 },
407 { C::merkle_check_index_is_even, 0 },
408 { C::merkle_check_write_node, 123 },
409 { C::merkle_check_sibling, 456 },
410 { C::merkle_check_write_left_node, 456 },
411 { C::merkle_check_write_right_node, 123 } },
412 });
413
414 check_relation<merkle_check>(trace2, merkle_check::SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_WRITE);
415
416 // Negative test - now modify to an incorrect value and verify it fails
417 trace2.set(C::merkle_check_write_left_node, 0, 123); // Should be 456
418 trace2.set(C::merkle_check_write_right_node, 0, 456); // Should be 123
419
421 "ASSIGN_SIBLING_LEFT_OR_RIGHT_WRITE");
422}
423
424TEST(MerkleCheckConstrainingTest, ReadOutputHashIsNextRowsNode)
425{
426 FF left_node = FF(123);
427 FF right_node = FF(456);
428 FF output_hash = UnconstrainedPoseidon2::hash({ left_node, right_node });
429
430 TestTraceContainer trace({
431 { { C::merkle_check_sel, 1 },
432 { C::merkle_check_end, 0 },
433 { C::merkle_check_read_node, left_node },
434 { C::merkle_check_read_right_node, right_node },
435 { C::merkle_check_read_output_hash, output_hash } },
436 { { C::merkle_check_sel, 1 },
437 { C::merkle_check_end, 1 }, // Set end=1 for final row
438 { C::merkle_check_read_node, output_hash } },
439 });
440
441 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE);
442
443 // Negative test - now modify to an incorrect value and verify it fails
444 trace.set(C::merkle_check_read_node, 1, output_hash + 1); // Should be output_hash
445
447 "OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE");
448}
449
450TEST(MerkleCheckConstrainingTest, WriteOutputHashIsNextRowsNode)
451{
452 FF left_node = FF(123);
453 FF right_node = FF(456);
454 FF output_hash = UnconstrainedPoseidon2::hash({ left_node, right_node });
455
456 TestTraceContainer trace({
457 { { C::merkle_check_sel, 1 },
458 { C::merkle_check_end, 0 },
459 { C::merkle_check_write_node, left_node },
460 { C::merkle_check_write_right_node, right_node },
461 { C::merkle_check_write_output_hash, output_hash } },
462 { { C::merkle_check_sel, 1 },
463 { C::merkle_check_end, 1 }, // Set end=1 for final row
464 { C::merkle_check_write_node, output_hash } },
465 });
466
467 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE);
468
469 // Negative test - now modify to an incorrect value and verify it fails
470 trace.set(C::merkle_check_write_node, 1, output_hash + 1); // Should be output_hash
471
473 "OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE");
474}
475
476TEST(MerkleCheckConstrainingTest, OutputHashIsNotNextRowsCurrentNodeValueForLastRow)
477{
478 FF output_hash = FF(456);
479 FF next_current_node = FF(789);
480
481 TestTraceContainer trace({
482 { { C::merkle_check_sel, 1 },
483 { C::merkle_check_end, 1 },
484 { C::merkle_check_read_output_hash, output_hash },
485 { C::merkle_check_write_output_hash, output_hash } },
486 { { C::merkle_check_sel, 1 },
487 { C::merkle_check_read_node, next_current_node },
488 { C::merkle_check_write_node, next_current_node } },
489 });
490
491 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE);
492 check_relation<merkle_check>(trace, merkle_check::SR_OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE);
493}
494
495TEST(MerkleCheckConstrainingTest, ReadWithTracegen)
496{
497 TestTraceContainer trace = TestTraceContainer::from_rows({
498 { .precomputed_first_row = 1 },
499 });
500 MerkleCheckTraceBuilder builder;
501
502 // Create a Merkle tree path with 3 levels
503 FF leaf_value = FF(123);
504 uint64_t leaf_index = 5;
505
506 // Create a sibling path of length 3
507 std::vector<FF> sibling_path = { FF(456), FF(789), FF(3333) };
508
509 // Compute expected root
510 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
511
512 MerkleCheckEvent event = {
513 .leaf_value = leaf_value, .leaf_index = leaf_index, .sibling_path = sibling_path, .root = root
514 };
515
516 builder.process({ event }, trace);
517
518 // Check the relation for all rows
519 check_relation<merkle_check>(trace);
520
521 // Negative test - now corrupt the trace and verify it fails
522 uint32_t last_row = static_cast<uint32_t>(trace.get_num_rows() - 1);
523 // Corrupt the last row
524 trace.set(C::merkle_check_path_len, last_row, 66);
525
526 EXPECT_THROW_WITH_MESSAGE(check_relation<merkle_check>(trace), "Relation merkle_check");
527}
528
529TEST(MerkleCheckConstrainingTest, WriteWithTracegen)
530{
531 TestTraceContainer trace = TestTraceContainer::from_rows({
532 { .precomputed_first_row = 1 },
533 });
534 MerkleCheckTraceBuilder builder;
535
536 // Create a Merkle tree path with 3 levels
537 FF leaf_value = FF(123);
538 FF new_leaf_value = FF(456);
539 uint64_t leaf_index = 5;
540
541 // Create a sibling path of length 3
542 std::vector<FF> sibling_path = { FF(456), FF(789), FF(3333) };
543
544 // Compute read root
545 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
546 // Compute new root
547 FF new_root = unconstrained_root_from_path(new_leaf_value, leaf_index, sibling_path);
548
549 MerkleCheckEvent event = { .leaf_value = leaf_value,
550 .new_leaf_value = new_leaf_value,
551 .leaf_index = leaf_index,
552 .sibling_path = sibling_path,
553 .root = root,
554 .new_root = new_root };
555
556 builder.process({ event }, trace);
557
558 // Check the relation for all rows
559 check_relation<merkle_check>(trace);
560}
561
562class MerkleCheckPoseidon2Test : public ::testing::Test {
563 protected:
564 MerkleCheckPoseidon2Test() = default;
565
566 EventEmitter<Poseidon2HashEvent> hash_event_emitter;
567 NoopEventEmitter<Poseidon2PermutationEvent> perm_event_emitter;
568 NoopEventEmitter<Poseidon2PermutationMemoryEvent> perm_mem_event_emitter;
569
570 NiceMock<MockExecutionIdManager> execution_id_manager;
571 NiceMock<MockGreaterThan> mock_gt;
573 Poseidon2(execution_id_manager, mock_gt, hash_event_emitter, perm_event_emitter, perm_mem_event_emitter);
574};
575
576TEST_F(MerkleCheckPoseidon2Test, ReadWithInteractions)
577{
578 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
579 MerkleCheck merkle_check_sim(poseidon2, merkle_event_emitter);
580
581 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
582 Poseidon2TraceBuilder poseidon2_builder;
583 MerkleCheckTraceBuilder merkle_check_builder;
584
585 FF leaf_value = 333;
586 uint64_t leaf_index = 30;
587 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
588 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
589 merkle_check_sim.assert_membership(leaf_value, leaf_index, sibling_path, root);
590
591 poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
592 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
593
594 check_interaction<MerkleCheckTraceBuilder,
597
598 check_relation<merkle_check>(trace);
599
600 // Negative test - now corrupt the trace and verify it fails
601 trace.set(Column::merkle_check_read_output_hash, static_cast<uint32_t>(sibling_path.size()), 66);
602
604 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_read_settings>(trace)),
605 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2.* Could not find tuple in destination");
606 check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_write_settings>(trace);
607}
608
609TEST_F(MerkleCheckPoseidon2Test, WriteWithInteractions)
610{
611 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
612 MerkleCheck merkle_check_sim(poseidon2, merkle_event_emitter);
613
614 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
615 Poseidon2TraceBuilder poseidon2_builder;
616 MerkleCheckTraceBuilder merkle_check_builder;
617
618 FF leaf_value = 333;
619 FF new_leaf_value = 444;
620 uint64_t leaf_index = 30;
621 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
622 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
623 FF expected_new_root = unconstrained_root_from_path(new_leaf_value, leaf_index, sibling_path);
624
625 FF new_root = merkle_check_sim.write(leaf_value, new_leaf_value, leaf_index, sibling_path, root);
626
627 EXPECT_EQ(new_root, expected_new_root);
628
629 poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
630 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
631
632 check_interaction<MerkleCheckTraceBuilder,
635
636 check_relation<merkle_check>(trace);
637
638 // Negative test - now corrupt the trace and verify it fails
639 trace.set(Column::merkle_check_read_output_hash, static_cast<uint32_t>(sibling_path.size()), 66);
640 trace.set(Column::merkle_check_write_output_hash, static_cast<uint32_t>(sibling_path.size()), 77);
641
643 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_read_settings>(trace)),
644 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2.* Could not find tuple in destination");
645
647 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_write_settings>(trace)),
648 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2_WRITE.* Could not find tuple in "
649 "destination");
650}
651
652TEST_F(MerkleCheckPoseidon2Test, MultipleWithTracegen)
653{
654 TestTraceContainer trace = TestTraceContainer::from_rows({
655 { .precomputed_first_row = 1 },
656 });
657 MerkleCheckTraceBuilder builder;
658
659 FF leaf_value = 333;
660 uint64_t leaf_index = 30;
661 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
662 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
663 MerkleCheckEvent event = {
664 .leaf_value = leaf_value, .leaf_index = leaf_index, .sibling_path = sibling_path, .root = root
665 };
666
667 FF leaf_value2 = 444;
668 FF new_leaf_value2 = 555;
669 uint64_t leaf_index2 = 40;
670 std::vector<FF> sibling_path2 = { 11, 22, 33, 44, 55, 66 };
671 FF root2 = unconstrained_root_from_path(leaf_value2, leaf_index2, sibling_path2);
672 FF new_root2 = unconstrained_root_from_path(new_leaf_value2, leaf_index2, sibling_path2);
673 MerkleCheckEvent event2 = { .leaf_value = leaf_value2,
674 .new_leaf_value = new_leaf_value2,
675 .leaf_index = leaf_index2,
676 .sibling_path = sibling_path2,
677 .root = root2,
678 .new_root = new_root2 };
679
680 builder.process({ event, event2 }, trace);
681
682 // Empty row after last real merkle row
683 uint32_t after_last_row_index = 1 + static_cast<uint32_t>(sibling_path.size() + sibling_path2.size());
684 trace.set(Column::merkle_check_sel, after_last_row_index, 0);
685 trace.set(Column::merkle_check_write, after_last_row_index, 0);
686 trace.set(Column::merkle_check_read_node, after_last_row_index, 0);
687 trace.set(Column::merkle_check_write_node, after_last_row_index, 0);
688 trace.set(Column::merkle_check_index, after_last_row_index, 0);
689 trace.set(Column::merkle_check_path_len, after_last_row_index, 0);
690 trace.set(Column::merkle_check_remaining_path_len_inv, after_last_row_index, 0);
691 trace.set(Column::merkle_check_read_root, after_last_row_index, 0);
692 trace.set(Column::merkle_check_write_root, after_last_row_index, 0);
693 trace.set(Column::merkle_check_sibling, after_last_row_index, 0);
694 trace.set(Column::merkle_check_start, after_last_row_index, 0);
695 trace.set(Column::merkle_check_end, after_last_row_index, 0);
696 trace.set(Column::merkle_check_index_is_even, after_last_row_index, 0);
697 trace.set(Column::merkle_check_read_left_node, after_last_row_index, 0);
698 trace.set(Column::merkle_check_read_right_node, after_last_row_index, 0);
699 trace.set(Column::merkle_check_write_left_node, after_last_row_index, 0);
700 trace.set(Column::merkle_check_write_right_node, after_last_row_index, 0);
701 trace.set(Column::merkle_check_constant_2, after_last_row_index, 0);
702 trace.set(Column::merkle_check_read_output_hash, after_last_row_index, 0);
703 trace.set(Column::merkle_check_write_output_hash, after_last_row_index, 0);
704
705 check_relation<merkle_check>(trace);
706}
707
708TEST_F(MerkleCheckPoseidon2Test, MultipleWithInteractions)
709{
710 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
711 MerkleCheck merkle_check_sim(poseidon2, merkle_event_emitter);
712
713 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
714 MerkleCheckTraceBuilder merkle_check_builder;
715 Poseidon2TraceBuilder poseidon2_builder;
716
717 FF leaf_value = 333;
718 uint64_t leaf_index = 30;
719 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
720 FF root = unconstrained_root_from_path(leaf_value, leaf_index, sibling_path);
721
722 merkle_check_sim.assert_membership(leaf_value, leaf_index, sibling_path, root);
723
724 FF leaf_value2 = 444;
725 FF new_leaf_value2 = 555;
726 uint64_t leaf_index2 = 40;
727 std::vector<FF> sibling_path2 = { 11, 22, 33, 44, 55, 66 };
728 FF root2 = unconstrained_root_from_path(leaf_value2, leaf_index2, sibling_path2);
729 FF expected_new_root2 = unconstrained_root_from_path(new_leaf_value2, leaf_index2, sibling_path2);
730
731 FF new_root2 = merkle_check_sim.write(leaf_value2, new_leaf_value2, leaf_index2, sibling_path2, root2);
732 EXPECT_EQ(new_root2, expected_new_root2);
733
734 poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
735 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
736
737 check_interaction<MerkleCheckTraceBuilder,
740
741 check_relation<merkle_check>(trace);
742}
743
744} // namespace
745} // namespace bb::avm2::constraining
static constexpr size_t SR_END_WHEN_PATH_EMPTY
static constexpr size_t SR_OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE
static constexpr size_t SR_PROPAGATE_READ_ROOT
static constexpr size_t SR_ASSIGN_NODE_LEFT_OR_RIGHT_READ
static constexpr size_t SR_PROPAGATE_WRITE
static constexpr size_t SR_TRACE_CONTINUITY
static constexpr size_t SR_NEXT_INDEX_IS_HALVED
static constexpr size_t SR_PROPAGATE_WRITE_ROOT
static constexpr size_t SR_SELECTOR_ON_END
static constexpr size_t SR_PATH_LEN_DECREMENTS
static constexpr size_t SR_ASSIGN_NODE_LEFT_OR_RIGHT_WRITE
static constexpr size_t SR_OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE
static constexpr size_t SR_START_AFTER_LATCH
static constexpr size_t SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_READ
static constexpr size_t SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_WRITE
static TestTraceContainer from_rows(const std::vector< AvmFullRow > &rows)
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:123
ExecutionIdManager execution_id_manager
TestTraceContainer trace
NoopEventEmitter< Poseidon2PermutationEvent > perm_event_emitter
NoopEventEmitter< Poseidon2PermutationMemoryEvent > perm_mem_event_emitter
NiceMock< MockGreaterThan > mock_gt
EventEmitter< Poseidon2HashEvent > hash_event_emitter
#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)
AvmFlavorSettings::FF FF
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:508
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
typename Flavor::FF FF
simulation::PublicDataTreeReadWriteEvent event