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