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