Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
element.test.cpp
Go to the documentation of this file.
6#include <gtest/gtest.h>
7
8using namespace bb;
9
10namespace {
11template <typename G_> class TestElement : public testing::Test {
12 public:
13 using G = G_;
14 using element = typename G::element;
15 using affine_element = typename G::affine_element;
16 using Fr = typename G::Fr;
17 using Fq = typename G::Fq;
18
19 static void test_random_element()
20 {
21 element result = element::random_element();
22 EXPECT_EQ(result.on_curve(), true);
23 }
24
25 static void test_random_affine_element()
26 {
27 affine_element result = element::random_element();
28 EXPECT_EQ(result.on_curve(), true);
29 }
30
31 static void test_on_curve()
32 {
33 for (size_t i = 0; i < 100; ++i) {
34 element test = element::random_element();
35 EXPECT_EQ(test.on_curve(), true);
36 affine_element affine_test = element::random_element();
37 EXPECT_EQ(affine_test.on_curve(), true);
38 }
39 }
40
41 static void test_eq()
42 {
43 element a = element::random_element();
44 element b = a.normalize();
45
46 EXPECT_EQ(a == b, true);
47 EXPECT_EQ(a == a, true);
48
49 b.self_set_infinity();
50
51 EXPECT_EQ(a == b, false);
52 element c = element::random_element();
53
54 EXPECT_EQ(a == c, false);
55
56 a.self_set_infinity();
57
58 EXPECT_EQ(a == b, true);
59 }
60
61 static void test_check_group_modulus()
62 {
63 Fr exponent = -Fr(1);
64 element result = G::one * exponent;
65 result += G::one;
66 result += G::one;
67 EXPECT_EQ(result.on_curve(), true);
68 EXPECT_EQ(result == G::one, true);
69 }
70
71 static void test_add_exception_test_infinity()
72 {
73 element lhs = element::random_element();
75 element result;
76
77 rhs = -lhs;
78
79 result = lhs + rhs;
80
81 EXPECT_EQ(result.is_point_at_infinity(), true);
82
83 element rhs_b;
84 rhs_b = rhs;
85 rhs_b.self_set_infinity();
86
87 result = lhs + rhs_b;
88
89 EXPECT_EQ(lhs == result, true);
90
91 lhs.self_set_infinity();
92 result = lhs + rhs;
93
94 EXPECT_EQ(rhs == result, true);
95 }
96
97 static void test_add_exception_test_dbl()
98 {
99 element lhs = element::random_element();
100 element rhs;
101 rhs = lhs;
102
103 element result;
104 element expected;
105
106 result = lhs + rhs;
107 expected = lhs.dbl();
108
109 EXPECT_EQ(result == expected, true);
110 }
111
112 static void test_add_dbl_consistency()
113 {
114 element a = element::random_element();
115 element b = element::random_element();
116
117 element c;
118 element d;
119 element add_result;
120 element dbl_result;
121
122 c = a + b;
123 b = -b;
124 d = a + b;
125
126 add_result = c + d;
127 dbl_result = a.dbl();
128
129 EXPECT_EQ(add_result == dbl_result, true);
130 }
131
132 static void test_add_dbl_consistency_repeated()
133 {
134 element a = element::random_element();
135 element b;
136 element c;
137 element d;
138 element e;
139
140 element result;
141 element expected;
142
143 b = a.dbl(); // b = 2a
144 c = b.dbl(); // c = 4a
145
146 d = a + b; // d = 3a
147 e = a + c; // e = 5a
148 result = d + e; // result = 8a
149
150 expected = c.dbl(); // expected = 8a
151
152 EXPECT_EQ(result == expected, true);
153 }
154
155 static void test_mixed_add_exception_test_infinity()
156 {
157 element lhs = G::one;
158 affine_element rhs = element::random_element();
159 lhs.x = rhs.x;
160 lhs.y = -rhs.y;
161
162 element result;
163 result = lhs + rhs;
164
165 EXPECT_EQ(result.is_point_at_infinity(), true);
166
167 lhs.self_set_infinity();
168 result = lhs + rhs;
169 element rhs_c;
170 rhs_c = element(rhs);
171
172 EXPECT_EQ(rhs_c == result, true);
173 }
174
175 static void test_mixed_add_exception_test_dbl()
176 {
177 affine_element rhs = element::random_element();
178 element lhs;
179 lhs = element(rhs);
180
181 element result;
182 element expected;
183 result = lhs + rhs;
184
185 expected = lhs.dbl();
186
187 EXPECT_EQ(result == expected, true);
188 }
189
190 static void test_add_mixed_add_consistency_check()
191 {
192 affine_element rhs = element::random_element();
193 element lhs = element::random_element();
194 element rhs_b;
195 rhs_b = element(rhs);
196
197 element add_result;
198 element mixed_add_result;
199 add_result = lhs + rhs_b;
200 mixed_add_result = lhs + rhs;
201
202 EXPECT_EQ(add_result == mixed_add_result, true);
203 }
204
205 static void test_batch_normalize()
206 {
207 size_t num_points = 2;
208 std::vector<element> points(num_points);
209 std::vector<element> normalized(num_points);
210 for (size_t i = 0; i < num_points; ++i) {
211 element a = element::random_element();
212 element b = element::random_element();
213 points[i] = a + b;
214 normalized[i] = points[i];
215 }
216 element::batch_normalize(&normalized[0], num_points);
217
218 for (size_t i = 0; i < num_points; ++i) {
219 Fq zz;
220 Fq zzz;
221 Fq result_x;
222 Fq result_y;
223 zz = points[i].z.sqr();
224 zzz = points[i].z * zz;
225 result_x = normalized[i].x * zz;
226 result_y = normalized[i].y * zzz;
227
228 EXPECT_EQ((result_x == points[i].x), true);
229 EXPECT_EQ((result_y == points[i].y), true);
230 }
231 }
232
233 // batch_normalize must preserve infinity points and correctly normalize non-infinity ones.
234 static void test_batch_normalize_with_infinity()
235 {
236 constexpr size_t num_points = 6;
237 std::vector<element> points(num_points);
238 for (size_t i = 0; i < num_points; ++i) {
239 if (i % 3 == 0) {
240 points[i] = element::infinity();
241 } else {
242 element a = element::random_element();
243 element b = element::random_element();
244 points[i] = a + b;
245 }
246 }
247 std::vector<element> normalized = points;
248 element::batch_normalize(&normalized[0], num_points);
249
250 for (size_t i = 0; i < num_points; ++i) {
251 if (i % 3 == 0) {
252 EXPECT_TRUE(normalized[i].is_point_at_infinity());
253 } else {
254 Fq zz = points[i].z.sqr();
255 Fq zzz = points[i].z * zz;
256 EXPECT_EQ(normalized[i].x * zz, points[i].x);
257 EXPECT_EQ(normalized[i].y * zzz, points[i].y);
258 }
259 }
260 }
261
262 static void test_group_exponentiation_zero_and_one()
263 {
264 affine_element result = G::one * Fr::zero();
265
266 EXPECT_EQ(result.is_point_at_infinity(), true);
267
268 result = G::one * Fr::one();
269
270 EXPECT_EQ(result == G::affine_one, true);
271 }
272
273 static void test_group_exponentiation_consistency_check()
274 {
277
278 Fr c;
279 c = a * b;
280
281 affine_element input = G::affine_one;
282 affine_element result = input * a;
283 result = result * b;
284
285 affine_element expected = input * c;
286
287 EXPECT_EQ(result == expected, true);
288 }
289
290 static void test_infinity()
291 {
292 affine_element inf_affine = affine_element::infinity();
293 EXPECT_EQ(inf_affine.is_point_at_infinity(), true);
294
295 element inf_element = element::infinity();
296 EXPECT_EQ(inf_element.is_point_at_infinity(), true);
297 }
298
299 static void test_infinity_canonical_form()
300 {
301 // affine_element: infinity() (value-init then self_set_infinity) and set_infinity() applied
302 // to a random point (copy of a non-trivial state then self_set_infinity) must match.
303 const affine_element inf_from_factory = affine_element::infinity();
304 const affine_element inf_from_random = affine_element(element::random_element()).set_infinity();
305
306 EXPECT_TRUE(inf_from_factory.is_point_at_infinity());
307 EXPECT_TRUE(inf_from_random.is_point_at_infinity());
308
309 EXPECT_EQ(inf_from_factory.y, Fq::zero());
310 EXPECT_EQ(inf_from_random.y, Fq::zero());
311 EXPECT_EQ(inf_from_factory.x, inf_from_random.x);
312 EXPECT_EQ(inf_from_factory.y, inf_from_random.y);
313
314 // element: infinity() (value-init), zero() (default-init, indeterminate y/z storage), and
315 // set_infinity() applied to a random point must all match.
316 const element inf_elem_factory = element::infinity();
317 const element inf_elem_zero = element::zero();
318 const element inf_elem_set = element::random_element().set_infinity();
319
320 EXPECT_TRUE(inf_elem_factory.is_point_at_infinity());
321 EXPECT_TRUE(inf_elem_zero.is_point_at_infinity());
322 EXPECT_TRUE(inf_elem_set.is_point_at_infinity());
323
324 for (const element& e : { inf_elem_factory, inf_elem_zero, inf_elem_set }) {
325 EXPECT_EQ(e.y, Fq::zero());
326 EXPECT_EQ(e.z, Fq::zero());
327 EXPECT_EQ(e.x, inf_elem_factory.x);
328 }
329 }
330
331 static void test_straus_msm_matches_naive_sum()
332 {
333 for (size_t n = 1; n <= 16; ++n) {
335 std::vector<Fr> scalars(n);
336 for (size_t i = 0; i < n; ++i) {
337 points[i] = affine_element(element::random_element());
338 scalars[i] = Fr::random_element();
339 }
340 element naive = element::infinity();
341 for (size_t i = 0; i < n; ++i) {
342 naive += points[i] * scalars[i];
343 }
344 element strauss = element::straus_msm(points, scalars);
345 EXPECT_EQ(strauss == naive, true) << "straus_msm mismatch at n=" << n;
346 }
347 }
348
349 static void test_straus_msm_truncates_to_shorter_input()
350 {
351 std::vector<affine_element> points = { affine_element(element::random_element()),
352 affine_element(element::random_element()),
353 affine_element(element::random_element()) };
354 std::vector<Fr> scalars = { Fr::random_element(), Fr::random_element() };
355
356 element expected = (points[0] * scalars[0]) + (points[1] * scalars[1]);
357 EXPECT_EQ(element::straus_msm(points, scalars) == expected, true);
358
359 std::vector<Fr> extra_scalars = { scalars[0], scalars[1], Fr::random_element() };
360 std::vector<affine_element> fewer_points = { points[0], points[1] };
361 EXPECT_EQ(element::straus_msm(fewer_points, extra_scalars) == expected, true);
362 }
363
364 static void test_straus_msm_edge_cases()
365 {
366 // Empty input → infinity
367 EXPECT_EQ(element::straus_msm({}, {}).is_point_at_infinity(), true);
368
369 // All-zero scalars → infinity
370 std::vector<affine_element> points = { affine_element(element::random_element()),
371 affine_element(element::random_element()) };
372 std::vector<Fr> zeros = { Fr::zero(), Fr::zero() };
373 EXPECT_EQ(element::straus_msm(points, zeros).is_point_at_infinity(), true);
374
375 // Mixed: some zero scalars, some infinity points → matches non-zero/non-infinity sum
376 const Fr s0 = Fr::random_element();
377 const Fr s2 = Fr::random_element();
378 std::vector<affine_element> mixed_points = {
379 affine_element(element::random_element()),
380 affine_element::infinity(),
381 affine_element(element::random_element()),
382 };
383 std::vector<Fr> mixed_scalars = { s0, Fr::random_element(), s2 };
384 element expected = mixed_points[0] * s0 + mixed_points[2] * s2;
385 EXPECT_EQ(element::straus_msm(mixed_points, mixed_scalars) == expected, true);
386 }
387
388 static void test_derive_generators()
389 {
390 constexpr size_t num_generators = 128;
391 auto result = G::derive_generators("test generators", num_generators);
392
393 const auto is_unique = [&result](const affine_element& y, const size_t j) {
394 for (size_t i = 0; i < result.size(); ++i) {
395 if ((i != j) && result[i] == y) {
396 return false;
397 }
398 }
399 return true;
400 };
401
402 for (size_t k = 0; k < num_generators; ++k) {
403 EXPECT_EQ(is_unique(result[k], k), true);
404 EXPECT_EQ(result[k].on_curve(), true);
405 }
406 }
407};
408
409using TestTypes = testing::Types<bb::g1, bb::g2, grumpkin::g1, secp256k1::g1, secp256r1::g1>;
410} // namespace
411
413
414TYPED_TEST(TestElement, RandomElement)
415{
416 TestFixture::test_random_element();
417}
418
419TYPED_TEST(TestElement, RandomAffineElement)
420{
421 TestFixture::test_random_affine_element();
422}
423
424TYPED_TEST(TestElement, OnCurve)
425{
426 TestFixture::test_on_curve();
427}
428
429TYPED_TEST(TestElement, Eq)
430{
431 TestFixture::test_eq();
432}
433
434TYPED_TEST(TestElement, CheckGroupModulus)
435{
436 TestFixture::test_check_group_modulus();
437}
438
439TYPED_TEST(TestElement, AddExceptionTestInfinity)
440{
441 TestFixture::test_add_exception_test_infinity();
442}
443
444TYPED_TEST(TestElement, AddExceptionTestDbl)
445{
446 TestFixture::test_add_exception_test_dbl();
447}
448
449TYPED_TEST(TestElement, AddDblConsistency)
450{
451 TestFixture::test_add_dbl_consistency();
452}
453
454TYPED_TEST(TestElement, AddDblConsistencyRepeated)
455{
456 TestFixture::test_add_dbl_consistency_repeated();
457}
458
459TYPED_TEST(TestElement, MixedAddExceptionTestInfinity)
460{
461 TestFixture::test_mixed_add_exception_test_infinity();
462}
463
464TYPED_TEST(TestElement, MixedAddExceptionTestDbl)
465{
466 TestFixture::test_mixed_add_exception_test_dbl();
467}
468
469TYPED_TEST(TestElement, AddMixedAddConsistencyCheck)
470{
471 TestFixture::test_add_mixed_add_consistency_check();
472}
473
474TYPED_TEST(TestElement, BatchNormalize)
475{
476 TestFixture::test_batch_normalize();
477}
478
479TYPED_TEST(TestElement, BatchNormalizeWithInfinity)
480{
481 TestFixture::test_batch_normalize_with_infinity();
482}
483
484TYPED_TEST(TestElement, GroupExponentiationZeroAndOne)
485{
486 TestFixture::test_group_exponentiation_zero_and_one();
487}
488
489TYPED_TEST(TestElement, GroupExponentiationConsistencyCheck)
490{
491 TestFixture::test_group_exponentiation_consistency_check();
492}
493
494TYPED_TEST(TestElement, Infinity)
495{
496 TestFixture::test_infinity();
497}
498
499TYPED_TEST(TestElement, InfinityCanonicalForm)
500{
501 TestFixture::test_infinity_canonical_form();
502}
503
504TYPED_TEST(TestElement, DeriveGenerators)
505{
507 TestFixture::test_derive_generators();
508 }
509}
510
511TYPED_TEST(TestElement, StrausMsmMatchesNaiveSum)
512{
514 TestFixture::test_straus_msm_matches_naive_sum();
515 }
516}
517
518TYPED_TEST(TestElement, StrausMsmTruncatesToShorterInput)
519{
521 TestFixture::test_straus_msm_truncates_to_shorter_input();
522 }
523}
524
525TYPED_TEST(TestElement, StrausMsmEdgeCases)
526{
528 TestFixture::test_straus_msm_edge_cases();
529 }
530}
FF a
FF b
#define G(r, i, a, b, c, d)
Definition blake2s.cpp:116
const size_t num_points
AffineElement * rhs
std::conditional_t< IsGoblinBigGroup< C, Fq, Fr, G >, element_goblin::goblin_element< C, goblin_field< C >, Fr, G >, element_default::element< C, Fq, Fr, G > > element
element wraps either element_default::element or element_goblin::goblin_element depending on parametr...
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
testing::Types< VKTestParams< UltraFlavor, stdlib::recursion::honk::DefaultIO< UltraCircuitBuilder > >, VKTestParams< UltraFlavor, stdlib::recursion::honk::RollupIO >, VKTestParams< UltraKeccakFlavor, stdlib::recursion::honk::DefaultIO< UltraCircuitBuilder > >, VKTestParams< MegaFlavor, stdlib::recursion::honk::DefaultIO< MegaCircuitBuilder > > > TestTypes
static constexpr field one()
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field sqr() const noexcept
static constexpr field zero()