Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5
28
29namespace bb::avm2::constraining {
30namespace {
31
32using ::testing::Return;
33using ::testing::StrictMock;
34
35using tracegen::EccTraceBuilder;
36using tracegen::TestTraceContainer;
37using tracegen::ToRadixTraceBuilder;
38
40using C = Column;
41using ecc = bb::avm2::ecc<FF>;
42using scalar_mul = bb::avm2::scalar_mul<FF>;
43using mem_aware_ecc = bb::avm2::ecc_mem<FF>;
44using EccSimulator = simulation::Ecc;
45using ToRadixSimulator = simulation::ToRadix;
46
47using simulation::EccAddEvent;
48using simulation::EccAddMemoryEvent;
49using simulation::EventEmitter;
50using simulation::FakeGreaterThan;
51using simulation::FakeToRadix;
52using simulation::MemoryStore;
53using simulation::MockExecutionIdManager;
54using simulation::MockGreaterThan;
55using simulation::MockMemory;
56using simulation::NoopEventEmitter;
57using simulation::ScalarMulEvent;
58using simulation::ToRadixEvent;
59using simulation::ToRadixMemoryEvent;
60
61// Known good points for P and Q
62FF p_x("0x04c95d1b26d63d46918a156cae92db1bcbc4072a27ec81dc82ea959abdbcf16a");
63FF p_y("0x035b6dd9e63c1370462c74775765d07fc21fd1093cc988149d3aa763bb3dbb60");
64EmbeddedCurvePoint p(p_x, p_y, false);
65
66FF q_x("0x009242167ec31949c00cbe441cd36757607406e87844fa2c8c4364a4403e66d7");
67FF q_y("0x0fe3016d64cfa8045609f375284b6b739b5fa282e4cbb75cc7f1687ecc7420e3");
68EmbeddedCurvePoint q(q_x, q_y, false);
69
70TEST(EccAddConstrainingTest, EccEmptyRow)
71{
72 check_relation<ecc>(testing::empty_trace());
73}
74
75TEST(EccAddConstrainingTest, EccAdd)
76{
77 // R = P + Q;
78 FF r_x("0x2b01df0ef6d941a826bea23bece8243cbcdc159d5e97fbaa2171f028e05ba9b6");
79 FF r_y("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
80 EmbeddedCurvePoint r(r_x, r_y, false);
81
83 .ecc_add_op = 1,
84 .ecc_double_op = 0,
85
86 .ecc_inv_2_p_y = FF::zero(),
87 .ecc_inv_x_diff = (q.x() - p.x()).invert(),
88 .ecc_inv_y_diff = (q.y() - p.y()).invert(),
89
90 .ecc_lambda = (q.y() - p.y()) / (q.x() - p.x()),
91
92 // Point P
93 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
94 .ecc_p_x = p.x(),
95 .ecc_p_y = p.y(),
96
97 // Point Q
98 .ecc_q_is_inf = static_cast<int>(q.is_infinity()),
99 .ecc_q_x = q.x(),
100 .ecc_q_y = q.y(),
101
102 // Resulting Point
103 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
104 .ecc_r_x = r.x(),
105 .ecc_r_y = r.y(),
106
107 .ecc_result_infinity = 0,
108
109 .ecc_sel = 1,
110 .ecc_use_computed_result = 1,
111 .ecc_x_match = 0,
112 .ecc_y_match = 0,
113
114 } });
115
116 check_relation<ecc>(trace);
117}
118
119TEST(EccAddConstrainingTest, EccDouble)
120{
121 // R = P + P;
122 FF r_x("0x088b996194bb5e6e8e5e49733bb671c3e660cf77254f743f366cc8e33534ee3b");
123 FF r_y("0x2807ffa01c0f522d0be1e1acfb6914ac8eabf1acf420c0629d37beee992e9a0e");
124 EmbeddedCurvePoint r(r_x, r_y, false);
125
127 .ecc_add_op = 0,
128 .ecc_double_op = 1,
129
130 .ecc_inv_2_p_y = (p.y() * 2).invert(),
131 .ecc_inv_x_diff = FF::zero(),
132 .ecc_inv_y_diff = FF::zero(),
133
134 .ecc_lambda = (p.x() * p.x() * 3) / (p.y() * 2),
135
136 // Point P
137 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
138 .ecc_p_x = p.x(),
139 .ecc_p_y = p.y(),
140
141 // Point Q set to point p since this is doubling
142 .ecc_q_is_inf = static_cast<int>(p.is_infinity()),
143 .ecc_q_x = p.x(),
144 .ecc_q_y = p.y(),
145
146 // Resulting Point
147 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
148 .ecc_r_x = r.x(),
149 .ecc_r_y = r.y(),
150
151 .ecc_result_infinity = 0,
152
153 .ecc_sel = 1,
154 .ecc_use_computed_result = 1,
155 .ecc_x_match = 1,
156 .ecc_y_match = 1,
157
158 } });
159
160 check_relation<ecc>(trace);
161}
162
163TEST(EccAddConstrainingTest, EccAddResultingInInfinity)
164{
165 // R = P + (-P) = O; , where O is the point at infinity
166 EmbeddedCurvePoint q(p.x(), -p.y(), false);
167 EmbeddedCurvePoint r(0, 0, true);
168
170 .ecc_add_op = 0,
171 .ecc_double_op = 0,
172
173 .ecc_inv_2_p_y = FF::zero(),
174 .ecc_inv_x_diff = FF::zero(),
175 .ecc_inv_y_diff = (q.y() - p.y()).invert(),
176
177 .ecc_lambda = 0,
178
179 // Point P
180 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
181 .ecc_p_x = p.x(),
182 .ecc_p_y = p.y(),
183
184 // Point Q
185 .ecc_q_is_inf = static_cast<int>(q.is_infinity()),
186 .ecc_q_x = q.x(),
187 .ecc_q_y = q.y(),
188
189 // Resulting Point
190 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
191 .ecc_r_x = r.x(),
192 .ecc_r_y = r.y(),
193
194 .ecc_result_infinity = 1,
195
196 .ecc_sel = 1,
197 .ecc_x_match = 1,
198 .ecc_y_match = 0,
199 } });
200
201 check_relation<ecc>(trace);
202}
203
204TEST(EccAddConstrainingTest, EccAddingToInfinity)
205{
206 EmbeddedCurvePoint p(0, 0, true);
207
208 // R = O + Q = Q; , where O is the point at infinity
209
210 EmbeddedCurvePoint r(q.x(), q.y(), false);
211
213 .ecc_add_op = 1,
214 .ecc_double_op = 0,
215
216 .ecc_inv_2_p_y = FF::zero(),
217 .ecc_inv_x_diff = (q.x() - p.x()).invert(),
218 .ecc_inv_y_diff = (q.y() - p.y()).invert(),
219
220 .ecc_lambda = (q.y() - p.y()) / (q.x() - p.x()),
221
222 // Point P
223 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
224 .ecc_p_x = p.x(),
225 .ecc_p_y = p.y(),
226
227 // Point Q
228 .ecc_q_is_inf = static_cast<int>(q.is_infinity()),
229 .ecc_q_x = q.x(),
230 .ecc_q_y = q.y(),
231
232 // Resulting Point
233 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
234 .ecc_r_x = r.x(),
235 .ecc_r_y = r.y(),
236
237 .ecc_result_infinity = 0,
238
239 .ecc_sel = 1,
240 .ecc_x_match = 0,
241 .ecc_y_match = 0,
242 } });
243
244 check_relation<ecc>(trace);
245}
246
247TEST(EccAddConstrainingTest, EccAddingInfinity)
248{
249 EmbeddedCurvePoint q(0, 0, true);
250
251 // R = P + O = P; , where O is the point at infinity
252 EmbeddedCurvePoint r(p.x(), p.y(), false);
253
255 .ecc_add_op = 1,
256 .ecc_double_op = 0,
257
258 .ecc_inv_2_p_y = (p.y() * 2).invert(),
259 .ecc_inv_x_diff = (q.x() - p.x()).invert(),
260 .ecc_inv_y_diff = (q.y() - p.y()).invert(),
261
262 .ecc_lambda = (q.y() - p.y()) / (q.x() - p.x()),
263
264 // Point P
265 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
266 .ecc_p_x = p.x(),
267 .ecc_p_y = p.y(),
268
269 // Point Q
270 .ecc_q_is_inf = static_cast<int>(q.is_infinity()),
271 .ecc_q_x = q.x(),
272 .ecc_q_y = q.y(),
273
274 // Resulting Point
275 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
276 .ecc_r_x = r.x(),
277 .ecc_r_y = r.y(),
278
279 .ecc_result_infinity = 0,
280
281 .ecc_sel = 1,
282 .ecc_x_match = 0,
283 .ecc_y_match = 0,
284
285 } });
286
287 check_relation<ecc>(trace);
288}
289
290TEST(EccAddConstrainingTest, EccDoublingInf)
291{
292 EmbeddedCurvePoint p(0, 0, true);
293
294 // r = O + O = O; , where O is the point at infinity
295 EmbeddedCurvePoint r(0, 0, true);
296
298 .ecc_add_op = 0,
299 .ecc_double_op = 1,
300
301 .ecc_inv_2_p_y = FF::zero(),
302 .ecc_inv_x_diff = FF::zero(),
303 .ecc_inv_y_diff = FF::zero(),
304
305 .ecc_lambda = FF::zero(),
306
307 // Point P
308 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
309 .ecc_p_x = p.x(),
310 .ecc_p_y = p.y(),
311
312 // Point Q
313 .ecc_q_is_inf = static_cast<int>(p.is_infinity()),
314 .ecc_q_x = p.x(),
315 .ecc_q_y = p.y(),
316
317 // Resulting Point
318 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
319 .ecc_r_x = r.x(),
320 .ecc_r_y = r.y(),
321
322 .ecc_result_infinity = 1,
323
324 .ecc_sel = 1,
325 .ecc_x_match = 1,
326 .ecc_y_match = 1,
327
328 } });
329
330 check_relation<ecc>(trace);
331}
332
333TEST(EccAddConstrainingTest, EccTwoOps)
334{
335 EmbeddedCurvePoint r1 = p + q;
336 EmbeddedCurvePoint r2 = r1 + r1;
337
339 .ecc_add_op = 1,
340 .ecc_double_op = 0,
341
342 .ecc_inv_2_p_y = FF::zero(),
343 .ecc_inv_x_diff = (q.x() - p.x()).invert(),
344 .ecc_inv_y_diff = (q.y() - p.y()).invert(),
345
346 .ecc_lambda = (q.y() - p.y()) / (q.x() - p.x()),
347
348 // Point P
349 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
350 .ecc_p_x = p.x(),
351 .ecc_p_y = p.y(),
352
353 // Point Q
354 .ecc_q_is_inf = static_cast<int>(q.is_infinity()),
355 .ecc_q_x = q.x(),
356 .ecc_q_y = q.y(),
357
358 // Resulting Point
359 .ecc_r_is_inf = static_cast<int>(r1.is_infinity()),
360 .ecc_r_x = r1.x(),
361 .ecc_r_y = r1.y(),
362
363 .ecc_result_infinity = 0,
364
365 .ecc_sel = 1,
366 .ecc_use_computed_result = 1,
367 .ecc_x_match = 0,
368 .ecc_y_match = 0,
369
370 },
371 {
372 .ecc_add_op = 0,
373 .ecc_double_op = 1,
374
375 .ecc_inv_2_p_y = (r1.y() * 2).invert(),
376 .ecc_inv_x_diff = FF::zero(),
377 .ecc_inv_y_diff = FF::zero(),
378
379 .ecc_lambda = (r1.x() * r1.x() * 3) / (r1.y() * 2),
380
381 // Point P
382 .ecc_p_is_inf = static_cast<int>(r1.is_infinity()),
383 .ecc_p_x = r1.x(),
384 .ecc_p_y = r1.y(),
385
386 // Point Q set to point p since this is doubling
387 .ecc_q_is_inf = static_cast<int>(r1.is_infinity()),
388 .ecc_q_x = r1.x(),
389 .ecc_q_y = r1.y(),
390
391 // Resulting Point
392 .ecc_r_is_inf = static_cast<int>(r2.is_infinity()),
393 .ecc_r_x = r2.x(),
394 .ecc_r_y = r2.y(),
395
396 .ecc_result_infinity = 0,
397
398 .ecc_sel = 1,
399 .ecc_use_computed_result = 1,
400 .ecc_x_match = 1,
401 .ecc_y_match = 1,
402
403 } });
404
405 check_relation<ecc>(trace);
406}
407
408TEST(EccAddConstrainingTest, EccNegativeBadAdd)
409{
410 // R != P + Q;
411
412 FF r_x("0x20f096ae3de9aea007e0b94a0274b2443d6682d1901f6909f284ec967bc169be");
413 FF r_y("0x27948713833bb314e828f2b6f45f408da6564a3ac03b9e430a9c6634bb849ef2");
414 EmbeddedCurvePoint r(r_x, r_y, false);
415
417 .ecc_add_op = 1,
418 .ecc_double_op = 0,
419
420 .ecc_inv_2_p_y = FF::zero(),
421 .ecc_inv_x_diff = (q.x() - p.x()).invert(),
422 .ecc_inv_y_diff = (q.y() - p.y()).invert(),
423
424 .ecc_lambda = (q.y() - p.y()) / (q.x() - p.x()),
425
426 // Point P
427 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
428 .ecc_p_x = p.x(),
429 .ecc_p_y = p.y(),
430
431 // Point Q
432 .ecc_q_is_inf = static_cast<int>(q.is_infinity()),
433 .ecc_q_x = q.x(),
434 .ecc_q_y = q.y(),
435
436 // Resulting Point
437 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
438 .ecc_r_x = r.x(),
439 .ecc_r_y = r.y(),
440
441 .ecc_result_infinity = 0,
442
443 .ecc_sel = 1,
444 .ecc_x_match = 0,
445 .ecc_y_match = 0,
446
447 } });
448
449 EXPECT_THROW_WITH_MESSAGE(check_relation<ecc>(trace, ecc::SR_OUTPUT_X_COORD), "OUTPUT_X_COORD");
450}
451
452TEST(EccAddConstrainingTest, EccNegativeBadDouble)
453{
454 // R != P + P;
455
456 FF r_x("0x2b01df0ef6d941a826bea23bece8243cbcdc159d5e97fbaa2171f028e05ba9b6");
457 FF r_y("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
458 EmbeddedCurvePoint r(r_x, r_y, false);
459
461 .ecc_add_op = 0,
462 .ecc_double_op = 1,
463
464 .ecc_inv_2_p_y = (p.y() * 2).invert(),
465 .ecc_inv_x_diff = FF::zero(),
466 .ecc_inv_y_diff = FF::zero(),
467
468 .ecc_lambda = (p.x() * p.x() * 3) / (p.y() * 2),
469
470 // Point P
471 .ecc_p_is_inf = static_cast<int>(p.is_infinity()),
472 .ecc_p_x = p.x(),
473 .ecc_p_y = p.y(),
474
475 // Point Q set to point p since this is doubling
476 .ecc_q_is_inf = static_cast<int>(p.is_infinity()),
477 .ecc_q_x = p.x(),
478 .ecc_q_y = p.y(),
479
480 // Resulting Point
481 .ecc_r_is_inf = static_cast<int>(r.is_infinity()),
482 .ecc_r_x = r.x(),
483 .ecc_r_y = r.y(),
484
485 .ecc_result_infinity = 0,
486
487 .ecc_sel = 1,
488 .ecc_x_match = 1,
489 .ecc_y_match = 1,
490
491 } });
492
493 EXPECT_THROW_WITH_MESSAGE(check_relation<ecc>(trace, ecc::SR_OUTPUT_X_COORD), "OUTPUT_X_COORD");
494}
495
496TEST(ScalarMulConstrainingTest, ScalarMulEmptyRow)
497{
498 check_relation<scalar_mul>(testing::empty_trace());
499}
500
501TEST(ScalarMulConstrainingTest, MulByOne)
502{
503 EccTraceBuilder builder;
504
505 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
506 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
507 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
508
509 StrictMock<MockExecutionIdManager> execution_id_manager;
510 StrictMock<MockGreaterThan> gt;
511 FakeToRadix to_radix_simulator = FakeToRadix();
512 EccSimulator ecc_simulator(execution_id_manager,
513 gt,
514 to_radix_simulator,
515 ecc_add_event_emitter,
516 scalar_mul_event_emitter,
517 ecc_add_memory_event_emitter);
518
519 FF scalar = FF(1);
520 ecc_simulator.scalar_mul(p, scalar);
521
522 TestTraceContainer trace = TestTraceContainer::from_rows({
523 { .precomputed_first_row = 1 },
524 });
525
526 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
527 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 254);
528 check_relation<scalar_mul>(trace);
529}
530
531TEST(ScalarMulConstrainingTest, BasicMul)
532{
533 EccTraceBuilder builder;
534
535 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
536 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
537 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
538
539 StrictMock<MockExecutionIdManager> execution_id_manager;
540 StrictMock<MockGreaterThan> gt;
541 FakeToRadix to_radix_simulator = FakeToRadix();
542 EccSimulator ecc_simulator(execution_id_manager,
543 gt,
544 to_radix_simulator,
545 ecc_add_event_emitter,
546 scalar_mul_event_emitter,
547 ecc_add_memory_event_emitter);
548
549 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
550 ecc_simulator.scalar_mul(p, scalar);
551
552 TestTraceContainer trace = TestTraceContainer::from_rows({
553 { .precomputed_first_row = 1 },
554 });
555
556 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
557 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 254);
558 check_relation<scalar_mul>(trace);
559}
560
561TEST(ScalarMulConstrainingTest, MultipleInvocations)
562{
563 EccTraceBuilder builder;
564
565 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
566 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
567 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
568
569 StrictMock<MockExecutionIdManager> execution_id_manager;
570 StrictMock<MockGreaterThan> gt;
571 FakeToRadix to_radix_simulator = FakeToRadix();
572 EccSimulator ecc_simulator(execution_id_manager,
573 gt,
574 to_radix_simulator,
575 ecc_add_event_emitter,
576 scalar_mul_event_emitter,
577 ecc_add_memory_event_emitter);
578
579 ecc_simulator.scalar_mul(p, FF("0x2b01df0ef6d941a826bea23bece8243cbcdc159d5e97fbaa2171f028e05ba9b6"));
580 ecc_simulator.scalar_mul(q, FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09"));
581
582 TestTraceContainer trace = TestTraceContainer::from_rows({
583 { .precomputed_first_row = 1 },
584 });
585
586 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
587 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + (254) * 2);
588 check_relation<scalar_mul>(trace);
589}
590
591TEST(ScalarMulConstrainingTest, MulInteractions)
592{
593 EccTraceBuilder builder;
594
595 EventEmitter<EccAddEvent> ecc_add_event_emitter;
596 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
597 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
598 EventEmitter<ToRadixEvent> to_radix_event_emitter;
599 NoopEventEmitter<ToRadixMemoryEvent> to_radix_mem_event_emitter;
600
601 StrictMock<MockExecutionIdManager> execution_id_manager;
602 StrictMock<MockGreaterThan> gt;
603 ToRadixSimulator to_radix_simulator(execution_id_manager, gt, to_radix_event_emitter, to_radix_mem_event_emitter);
604 EccSimulator ecc_simulator(execution_id_manager,
605 gt,
606 to_radix_simulator,
607 ecc_add_event_emitter,
608 scalar_mul_event_emitter,
609 ecc_add_memory_event_emitter);
610
611 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
612 ecc_simulator.scalar_mul(p, scalar);
613
614 TestTraceContainer trace = TestTraceContainer::from_rows({
615 { .precomputed_first_row = 1 },
616 });
617
618 ToRadixTraceBuilder to_radix_builder;
619 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
620 builder.process_add(ecc_add_event_emitter.dump_events(), trace);
621 to_radix_builder.process(to_radix_event_emitter.dump_events(), trace);
622
623 check_interaction<EccTraceBuilder,
627}
628
629TEST(ScalarMulConstrainingTest, MulAddInteractionsInfinity)
630{
631 EccTraceBuilder builder;
632
633 EventEmitter<EccAddEvent> ecc_add_event_emitter;
634 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
635 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
636
637 StrictMock<MockExecutionIdManager> execution_id_manager;
638 StrictMock<MockGreaterThan> gt;
639 FakeToRadix to_radix_simulator = FakeToRadix();
640 EccSimulator ecc_simulator(execution_id_manager,
641 gt,
642 to_radix_simulator,
643 ecc_add_event_emitter,
644 scalar_mul_event_emitter,
645 ecc_add_memory_event_emitter);
646
647 EmbeddedCurvePoint result = ecc_simulator.scalar_mul(EmbeddedCurvePoint::infinity(), FF(10));
648 ASSERT_TRUE(result.is_infinity());
649
650 TestTraceContainer trace = TestTraceContainer::from_rows({
651 { .precomputed_first_row = 1 },
652 });
653
654 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
655 builder.process_add(ecc_add_event_emitter.dump_events(), trace);
656
657 check_interaction<EccTraceBuilder, lookup_scalar_mul_double_settings, lookup_scalar_mul_add_settings>(trace);
658
659 check_relation<scalar_mul>(trace);
660 check_relation<ecc>(trace);
661}
662
663TEST(ScalarMulConstrainingTest, NegativeMulAddInteractions)
664{
665 EccTraceBuilder builder;
666
667 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
668 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
669 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
670
671 StrictMock<MockExecutionIdManager> execution_id_manager;
672 StrictMock<MockGreaterThan> gt;
673 FakeToRadix to_radix_simulator = FakeToRadix();
674 EccSimulator ecc_simulator(execution_id_manager,
675 gt,
676 to_radix_simulator,
677 ecc_add_event_emitter,
678 scalar_mul_event_emitter,
679 ecc_add_memory_event_emitter);
680
681 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
682 ecc_simulator.scalar_mul(p, scalar);
683
684 TestTraceContainer trace = TestTraceContainer::from_rows({
685 { .precomputed_first_row = 1 },
686 });
687
688 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
689
690 EXPECT_THROW_WITH_MESSAGE((check_interaction<EccTraceBuilder, lookup_scalar_mul_double_settings>(trace)),
691 "Failed.*SCALAR_MUL_DOUBLE. Could not find tuple in destination.");
692 EXPECT_THROW_WITH_MESSAGE((check_interaction<EccTraceBuilder, lookup_scalar_mul_add_settings>(trace)),
693 "Failed.*SCALAR_MUL_ADD. Could not find tuple in destination.");
694}
695
696TEST(ScalarMulConstrainingTest, NegativeMulRadixInteractions)
697{
698 EccTraceBuilder builder;
699
700 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
701 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
702 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
703
704 StrictMock<MockExecutionIdManager> execution_id_manager;
705 StrictMock<MockGreaterThan> gt;
706 FakeToRadix to_radix_simulator = FakeToRadix();
707 EccSimulator ecc_simulator(execution_id_manager,
708 gt,
709 to_radix_simulator,
710 ecc_add_event_emitter,
711 scalar_mul_event_emitter,
712 ecc_add_memory_event_emitter);
713
714 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
715 ecc_simulator.scalar_mul(p, scalar);
716
717 TestTraceContainer trace = TestTraceContainer::from_rows({
718 { .precomputed_first_row = 1 },
719 });
720
721 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
722
723 EXPECT_THROW_WITH_MESSAGE((check_interaction<EccTraceBuilder, lookup_scalar_mul_to_radix_settings>(trace)),
724 "Failed.*SCALAR_MUL_TO_RADIX. Could not find tuple in destination.");
725
726 check_relation<scalar_mul>(trace);
727}
728
729TEST(ScalarMulConstrainingTest, NegativeDisableSel)
730{
731 EccTraceBuilder builder;
732
733 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
734 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
735 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
736
737 StrictMock<MockExecutionIdManager> execution_id_manager;
738 StrictMock<MockGreaterThan> gt;
739 FakeToRadix to_radix_simulator = FakeToRadix();
740 EccSimulator ecc_simulator(execution_id_manager,
741 gt,
742 to_radix_simulator,
743 ecc_add_event_emitter,
744 scalar_mul_event_emitter,
745 ecc_add_memory_event_emitter);
746
747 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
748 ecc_simulator.scalar_mul(p, scalar);
749
750 TestTraceContainer trace = TestTraceContainer::from_rows({
751 { .precomputed_first_row = 1 },
752 });
753
754 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
755 // Disable the selector in one of the rows between start and end
756 trace.set(Column::scalar_mul_sel, 5, 0);
758 "SELECTOR_CONSISTENCY");
759}
760
761TEST(ScalarMulConstrainingTest, NegativeEnableStartFirstRow)
762{
763 EccTraceBuilder builder;
764
765 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
766 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
767 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
768
769 StrictMock<MockExecutionIdManager> execution_id_manager;
770 StrictMock<MockGreaterThan> gt;
771 FakeToRadix to_radix_simulator = FakeToRadix();
772 EccSimulator ecc_simulator(execution_id_manager,
773 gt,
774 to_radix_simulator,
775 ecc_add_event_emitter,
776 scalar_mul_event_emitter,
777 ecc_add_memory_event_emitter);
778
779 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
780 ecc_simulator.scalar_mul(p, scalar);
781
782 TestTraceContainer trace = TestTraceContainer::from_rows({
783 { .precomputed_first_row = 1 },
784 });
785
786 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
787 // Enable the start in the first row
788 trace.set(Column::scalar_mul_start, 0, 1);
789 EXPECT_THROW_WITH_MESSAGE(check_relation<scalar_mul>(trace, scalar_mul::SR_SELECTOR_ON_START), "SELECTOR_ON_START");
790}
791
792TEST(ScalarMulConstrainingTest, NegativeMutateScalarOnEnd)
793{
794 EccTraceBuilder builder;
795
796 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
797 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
798 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
799
800 StrictMock<MockExecutionIdManager> execution_id_manager;
801 StrictMock<MockGreaterThan> gt;
802 FakeToRadix to_radix_simulator = FakeToRadix();
803 EccSimulator ecc_simulator(execution_id_manager,
804 gt,
805 to_radix_simulator,
806 ecc_add_event_emitter,
807 scalar_mul_event_emitter,
808 ecc_add_memory_event_emitter);
809
810 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
811 ecc_simulator.scalar_mul(p, scalar);
812
813 TestTraceContainer trace = TestTraceContainer::from_rows({
814 { .precomputed_first_row = 1 },
815 });
816
817 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
818 // Mutate the scalar on the end row
819 trace.set(Column::scalar_mul_scalar, 254, 27);
821 "INPUT_CONSISTENCY_SCALAR");
822}
823
824TEST(ScalarMulConstrainingTest, NegativeMutatePointXOnEnd)
825{
826 EccTraceBuilder builder;
827
828 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
829 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
830 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
831
832 StrictMock<MockExecutionIdManager> execution_id_manager;
833 StrictMock<MockGreaterThan> gt;
834 FakeToRadix to_radix_simulator = FakeToRadix();
835 EccSimulator ecc_simulator(execution_id_manager,
836 gt,
837 to_radix_simulator,
838 ecc_add_event_emitter,
839 scalar_mul_event_emitter,
840 ecc_add_memory_event_emitter);
841
842 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
843 ecc_simulator.scalar_mul(p, scalar);
844
845 TestTraceContainer trace = TestTraceContainer::from_rows({
846 { .precomputed_first_row = 1 },
847 });
848
849 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
850 // Mutate the point on the end row
851 trace.set(Column::scalar_mul_point_x, 254, q.x());
852
854 "INPUT_CONSISTENCY_X");
855}
856
857TEST(ScalarMulConstrainingTest, NegativeMutatePointYOnEnd)
858{
859 EccTraceBuilder builder;
860
861 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
862 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
863 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
864
865 StrictMock<MockExecutionIdManager> execution_id_manager;
866 StrictMock<MockGreaterThan> gt;
867 FakeToRadix to_radix_simulator = FakeToRadix();
868 EccSimulator ecc_simulator(execution_id_manager,
869 gt,
870 to_radix_simulator,
871 ecc_add_event_emitter,
872 scalar_mul_event_emitter,
873 ecc_add_memory_event_emitter);
874
875 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
876 ecc_simulator.scalar_mul(p, scalar);
877
878 TestTraceContainer trace = TestTraceContainer::from_rows({
879 { .precomputed_first_row = 1 },
880 });
881
882 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
883 // Mutate the point on the end row
884 trace.set(Column::scalar_mul_point_y, 254, q.y());
885
887 "INPUT_CONSISTENCY_Y");
888}
889
890TEST(ScalarMulConstrainingTest, NegativeMutatePointInfOnEnd)
891{
892 EccTraceBuilder builder;
893
894 NoopEventEmitter<EccAddEvent> ecc_add_event_emitter;
895 EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
896 NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
897
898 StrictMock<MockExecutionIdManager> execution_id_manager;
899 StrictMock<MockGreaterThan> gt;
900 FakeToRadix to_radix_simulator = FakeToRadix();
901 EccSimulator ecc_simulator(execution_id_manager,
902 gt,
903 to_radix_simulator,
904 ecc_add_event_emitter,
905 scalar_mul_event_emitter,
906 ecc_add_memory_event_emitter);
907
908 FF scalar = FF("0x0cc4c71e882bc62b7b3d1964a8540cb5211339dfcddd2e095fd444bf1aed4f09");
909 ecc_simulator.scalar_mul(p, scalar);
910
911 TestTraceContainer trace = TestTraceContainer::from_rows({
912 { .precomputed_first_row = 1 },
913 });
914
915 builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);
916 // Mutate the point on the end row
917 trace.set(Column::scalar_mul_point_inf, 254, 1);
918
920 "INPUT_CONSISTENCY_INF");
921}
922
924// Memory Aware Ecc Add
926
927TEST(EccAddMemoryConstrainingTest, EccAddMemoryEmptyRow)
928{
929 check_relation<mem_aware_ecc>(testing::empty_trace());
930}
931
932TEST(EccAddMemoryConstrainingTest, EccAddMemory)
933{
934 TestTraceContainer trace;
935 EccTraceBuilder builder;
937
938 EventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
939 EventEmitter<EccAddEvent> ecc_add_event_emitter;
940 NoopEventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
941 NoopEventEmitter<ToRadixEvent> to_radix_event_emitter;
942
943 StrictMock<MockExecutionIdManager> execution_id_manager;
944 EXPECT_CALL(execution_id_manager, get_execution_id)
945 .WillRepeatedly(Return(0)); // Use a fixed execution IDfor the test
946 FakeGreaterThan gt;
947 FakeToRadix to_radix_simulator = FakeToRadix();
948 EccSimulator ecc_simulator(execution_id_manager,
949 gt,
950 to_radix_simulator,
951 ecc_add_event_emitter,
952 scalar_mul_event_emitter,
953 ecc_add_memory_event_emitter);
954
955 MemoryAddress dst_address = 5;
956 ecc_simulator.add(memory, p, q, dst_address);
957 builder.process_add_with_memory(ecc_add_memory_event_emitter.dump_events(), trace);
958 builder.process_add(ecc_add_event_emitter.dump_events(), trace);
959
960 check_relation<mem_aware_ecc>(trace);
961}
962
963TEST(EccAddMemoryConstrainingTest, EccAddMemoryInteractions)
964{
965
966 EccTraceBuilder builder;
968
969 StrictMock<MockExecutionIdManager> execution_id_manager;
970 EXPECT_CALL(execution_id_manager, get_execution_id)
971 .WillRepeatedly(Return(0)); // Use a fixed execution IDfor the test
972 FakeGreaterThan gt;
973 FakeToRadix to_radix_simulator = FakeToRadix();
974
975 EventEmitter<EccAddEvent> ecc_add_event_emitter;
976 NoopEventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
977 EventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
978 NoopEventEmitter<ToRadixEvent> to_radix_event_emitter;
979 EccSimulator ecc_simulator(execution_id_manager,
980 gt,
981 to_radix_simulator,
982 ecc_add_event_emitter,
983 scalar_mul_event_emitter,
984 ecc_add_memory_event_emitter);
985
986 EmbeddedCurvePoint result = p + q;
987
988 uint32_t dst_address = 0x1000;
989 // Set the execution and gt traces
990 TestTraceContainer trace = TestTraceContainer({
991 // Row 0
992 {
993 // Execution
994 { C::execution_sel, 1 },
995 { C::execution_sel_execute_ecc_add, 1 },
996 { C::execution_rop_6_, dst_address },
997 { C::execution_register_0_, p.x() },
998 { C::execution_register_1_, p.y() },
999 { C::execution_register_2_, p.is_infinity() ? 1 : 0 },
1000 { C::execution_register_3_, q.x() },
1001 { C::execution_register_4_, q.y() },
1002 { C::execution_register_5_, q.is_infinity() ? 1 : 0 },
1003 // GT - dst out of range check
1004 { C::gt_sel, 1 },
1005 { C::gt_input_a, dst_address + 2 }, // highest write address is dst_address + 2
1006 { C::gt_input_b, AVM_HIGHEST_MEM_ADDRESS },
1007 { C::gt_res, 0 },
1008 // Memory Writes
1009 { C::memory_address, dst_address },
1010 { C::memory_value, result.x() },
1011 { C::memory_sel, 1 },
1012 { C::memory_rw, 1 }, // write
1013 { C::memory_tag, static_cast<uint8_t>(MemoryTag::FF) },
1014 },
1015 {
1016 // Memory Writes
1017 { C::memory_address, dst_address + 1 },
1018 { C::memory_value, result.y() },
1019 { C::memory_sel, 1 },
1020 { C::memory_rw, 1 }, // write
1021 { C::memory_tag, static_cast<uint8_t>(MemoryTag::FF) },
1022 },
1023 {
1024 // Memory Writes
1025 { C::memory_address, dst_address + 2 },
1026 { C::memory_value, result.is_infinity() },
1027 { C::memory_sel, 1 },
1028 { C::memory_rw, 1 }, // write
1029 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U1) },
1030 },
1031 });
1032
1033 ecc_simulator.add(memory, p, q, dst_address);
1034
1035 builder.process_add_with_memory(ecc_add_memory_event_emitter.dump_events(), trace);
1036 builder.process_add(ecc_add_event_emitter.dump_events(), trace);
1037
1038 check_all_interactions<EccTraceBuilder>(trace);
1039 check_relation<mem_aware_ecc>(trace);
1040}
1041
1042TEST(EccAddMemoryConstrainingTest, EccAddMemoryInvalidDstRange)
1043{
1044
1045 EccTraceBuilder builder;
1047
1048 NoopEventEmitter<ToRadixEvent> to_radix_event_emitter;
1049 EventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
1050 EventEmitter<EccAddEvent> ecc_add_event_emitter;
1051 NoopEventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
1052
1053 StrictMock<MockExecutionIdManager> execution_id_manager;
1054 EXPECT_CALL(execution_id_manager, get_execution_id)
1055 .WillRepeatedly(Return(0)); // Use a fixed execution IDfor the test
1056 FakeGreaterThan gt;
1057 FakeToRadix to_radix_simulator = FakeToRadix();
1058
1059 EccSimulator ecc_simulator(execution_id_manager,
1060 gt,
1061 to_radix_simulator,
1062 ecc_add_event_emitter,
1063 scalar_mul_event_emitter,
1064 ecc_add_memory_event_emitter);
1065
1066 uint32_t dst_address = AVM_HIGHEST_MEM_ADDRESS - 1; // Invalid address, will result in out of range error
1067 // Set the execution and gt traces
1068 TestTraceContainer trace = TestTraceContainer({
1069 // Row 0
1070 {
1071 // Execution
1072 { C::execution_sel, 1 },
1073 { C::execution_sel_execute_ecc_add, 1 },
1074 { C::execution_rop_6_, dst_address },
1075 { C::execution_register_0_, p.x() },
1076 { C::execution_register_1_, p.y() },
1077 { C::execution_register_2_, p.is_infinity() ? 1 : 0 },
1078 { C::execution_register_3_, q.x() },
1079 { C::execution_register_4_, q.y() },
1080 { C::execution_register_5_, q.is_infinity() ? 1 : 0 },
1081 { C::execution_sel_opcode_error, 1 },
1082 // GT - dst out of range check
1083 { C::gt_sel, 1 },
1084 { C::gt_input_a, static_cast<uint64_t>(dst_address) + 2 },
1085 { C::gt_input_b, AVM_HIGHEST_MEM_ADDRESS },
1086 { C::gt_res, 1 },
1087 },
1088 });
1089
1090 EXPECT_THROW_WITH_MESSAGE(ecc_simulator.add(memory, p, q, dst_address), "EccException.* dst address out of range");
1091
1092 builder.process_add_with_memory(ecc_add_memory_event_emitter.dump_events(), trace);
1093 EXPECT_EQ(ecc_add_event_emitter.get_events().size(), 0); // Expect 0 add events since error in ecc_mem
1094
1095 check_all_interactions<EccTraceBuilder>(trace);
1096 check_relation<mem_aware_ecc>(trace);
1097}
1098
1099TEST(EccAddMemoryConstrainingTest, EccAddMemoryPointError)
1100{
1101
1102 EccTraceBuilder builder;
1104 EventEmitter<EccAddEvent> ecc_add_event_emitter;
1105 NoopEventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
1106 EventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
1107
1108 StrictMock<MockExecutionIdManager> execution_id_manager;
1109 EXPECT_CALL(execution_id_manager, get_execution_id)
1110 .WillRepeatedly(Return(0)); // Use a fixed execution IDfor the test
1111 FakeGreaterThan gt;
1112 FakeToRadix to_radix_simulator = FakeToRadix();
1113
1114 EccSimulator ecc_simulator(execution_id_manager,
1115 gt,
1116 to_radix_simulator,
1117 ecc_add_event_emitter,
1118 scalar_mul_event_emitter,
1119 ecc_add_memory_event_emitter);
1120
1121 // Point P is not on the curve
1122 FF p_x("0x0000000000063d46918a156cae92db1bcbc4072a27ec81dc82ea959abdbcf16a");
1123 FF p_y("0x00000000000c1370462c74775765d07fc21fd1093cc988149d3aa763bb3dbb60");
1124 EmbeddedCurvePoint p(p_x, p_y, false);
1125
1126 uint32_t dst_address = 0x1000;
1127
1128 EXPECT_CALL(execution_id_manager, get_execution_id()).WillOnce(::testing::Return(0));
1129 // Set the execution and gt traces
1130 TestTraceContainer trace = TestTraceContainer({
1131 // Row 0
1132 {
1133 // Execution
1134 { C::execution_sel, 1 },
1135 { C::execution_sel_execute_ecc_add, 1 },
1136 { C::execution_rop_6_, dst_address },
1137 { C::execution_register_0_, p.x() },
1138 { C::execution_register_1_, p.y() },
1139 { C::execution_register_2_, p.is_infinity() ? 1 : 0 },
1140 { C::execution_register_3_, q.x() },
1141 { C::execution_register_4_, q.y() },
1142 { C::execution_register_5_, q.is_infinity() ? 1 : 0 },
1143 { C::execution_sel_opcode_error, 1 }, // Indicate an error in the operation
1144 // GT - dst out of range check
1145 { C::gt_sel, 1 },
1146 { C::gt_input_a, dst_address + 2 }, // highest write address is dst_address + 2
1147 { C::gt_input_b, AVM_HIGHEST_MEM_ADDRESS },
1148 { C::gt_res, 0 },
1149 },
1150 });
1151
1152 EXPECT_THROW(ecc_simulator.add(memory, p, q, dst_address), simulation::EccException);
1153
1154 builder.process_add_with_memory(ecc_add_memory_event_emitter.dump_events(), trace);
1155 // Expect no events to be emitted since the operation failed
1156 EXPECT_EQ(ecc_add_event_emitter.get_events().size(), 0);
1157
1158 check_all_interactions<EccTraceBuilder>(trace);
1159 check_relation<mem_aware_ecc>(trace);
1160}
1161
1162} // namespace
1163} // namespace bb::avm2::constraining
#define AVM_HIGHEST_MEM_ADDRESS
static constexpr size_t SR_OUTPUT_X_COORD
Definition ecc.hpp:61
static constexpr size_t SR_INPUT_CONSISTENCY_X
static constexpr size_t SR_INPUT_CONSISTENCY_INF
static constexpr size_t SR_SELECTOR_CONSISTENCY
static constexpr size_t SR_SELECTOR_ON_START
static constexpr size_t SR_INPUT_CONSISTENCY_Y
static constexpr size_t SR_INPUT_CONSISTENCY_SCALAR
static TestTraceContainer from_rows(const std::vector< AvmFullRow > &rows)
void set(Column col, uint32_t row, const FF &value)
AluTraceBuilder builder
Definition alu.test.cpp:123
ExecutionIdManager execution_id_manager
GreaterThan gt
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
void check_interaction(tracegen::TestTraceContainer &trace)
AvmFlavorSettings::FF FF
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:508
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
lookup_settings< lookup_scalar_mul_double_settings_ > lookup_scalar_mul_double_settings
StandardAffinePoint< AvmFlavorSettings::EmbeddedCurve::AffineElement > EmbeddedCurvePoint
Definition field.hpp:12
lookup_settings< lookup_scalar_mul_to_radix_settings_ > lookup_scalar_mul_to_radix_settings
lookup_settings< lookup_scalar_mul_add_settings_ > lookup_scalar_mul_add_settings
uint32_t MemoryAddress
typename Flavor::FF FF
MemoryStore memory