Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
fr.test.cpp
Go to the documentation of this file.
1#include "fr.hpp"
3#include <gtest/gtest.h>
4
5using namespace bb;
6
7TEST(fr, Msgpack)
8{
9 auto [actual, expected] = msgpack_roundtrip(bb::fr{ 1ULL, 2ULL, 3ULL, 4ULL });
10 EXPECT_EQ(actual, expected);
11}
12
13TEST(fr, Eq)
14{
15 fr a{ 0x01, 0x02, 0x03, 0x04 };
16 fr b{ 0x01, 0x02, 0x03, 0x04 };
17 fr c{ 0x01, 0x02, 0x03, 0x05 };
18 fr d{ 0x01, 0x02, 0x04, 0x04 };
19 fr e{ 0x01, 0x03, 0x03, 0x04 };
20 fr f{ 0x02, 0x02, 0x03, 0x04 };
21 EXPECT_EQ((a == b), true);
22 EXPECT_EQ((a == c), false);
23 EXPECT_EQ((a == d), false);
24 EXPECT_EQ((a == e), false);
25 EXPECT_EQ((a == f), false);
26}
27
28TEST(fr, IsZero)
29{
30 fr a = fr::zero();
31 fr b = fr::zero();
32 fr c = fr::zero();
33 fr d = fr::zero();
34 fr e = fr::zero();
35
36 b.data[0] = 1;
37 c.data[1] = 1;
38 d.data[2] = 1;
39 e.data[3] = 1;
40 EXPECT_EQ(a.is_zero(), true);
41 EXPECT_EQ(b.is_zero(), false);
42 EXPECT_EQ(c.is_zero(), false);
43 EXPECT_EQ(d.is_zero(), false);
44 EXPECT_EQ(e.is_zero(), false);
45}
46
47TEST(fr, RandomElement)
48{
51
52 EXPECT_EQ((a == b), false);
53 EXPECT_EQ(a.is_zero(), false);
54 EXPECT_EQ(b.is_zero(), false);
55}
56
57TEST(fr, Mul)
58{
59 auto a_uint = uint256_t{ 0x192f9ddc938ea63, 0x1db93d61007ec4fe, 0xc89284ec31fa49c0, 0x2478d0ff12b04f0f };
60 auto b_uint = uint256_t{ 0x7aade4892631231c, 0x8e7515681fe70144, 0x98edb76e689b6fd8, 0x5d0886b15fc835fa };
61
62 fr a = a_uint;
63 fr b = b_uint;
64 fr expected = (uint512_t(a_uint) * uint512_t(b_uint) % uint512_t(fr::modulus)).lo;
65 fr result;
66 result = a * b;
67 EXPECT_EQ((result == expected), true);
68}
69
70TEST(fr, Sqr)
71{
72 auto a_uint = uint256_t{ 0x192f9ddc938ea63, 0x1db93d61007ec4fe, 0xc89284ec31fa49c0, 0x2478d0ff12b04f0f };
73 fr a = a_uint;
74 fr expected = (uint512_t(a_uint) * uint512_t(a_uint) % uint512_t(fr::modulus)).lo;
75 fr result;
76 result = a.sqr();
77 EXPECT_EQ((result == expected), true);
78}
79
80TEST(fr, Add)
81{
82 fr a{ 0x20565a572c565a66, 0x7bccd0f01f5f7bff, 0x63ec2beaad64711f, 0x624953caaf44a814 };
83 fr b{ 0xa17307a2108adeea, 0x74629976c14c5e2b, 0x9ce6f072ab1740ee, 0x398c753702b2bef0 };
84 fr expected{ 0x7de76c654ce1394f, 0xc7fb821e66f26999, 0x4882d6a6d6fa59b0, 0x6b717a8ed0c5c6db };
85 fr result;
86 result = a + b;
87 EXPECT_EQ(result, expected.reduce_once());
88}
89
90TEST(fr, Sub)
91{
92 fr a{ 0xcfbcfcf457cf2d38, 0x7b27af26ce62aa61, 0xf0378e90d48f2b92, 0x4734b22cb21ded };
93 fr b{ 0x569fdb1db5198770, 0x446ddccef8347d52, 0xef215227182d22a, 0x8281b4fb109306 };
94 fr expected{ 0xbcff176a92b5a5c9, 0x5eedbaa04fe79da0, 0x9995bf24e48db1c5, 0x3029017012d32b11 };
95 fr result;
96 result = a - b;
97 EXPECT_EQ((result == expected), true);
98}
99
100TEST(fr, PlusEquals)
101{
102 fr a{ 0x5def, 0x00, 0x00, 0x00 };
103 fr a_copy = a;
104 a += 2;
105 fr expected = a_copy + 2;
106 EXPECT_EQ((a == expected), true);
107
108 a += 3;
109 expected = a_copy + 5;
110 EXPECT_EQ((a == expected), true);
111}
112
113TEST(fr, PrefixIncrement)
114{
115 fr a{ 0x5def, 0x00, 0x00, 0x00 };
116 fr b = ++a;
117 EXPECT_EQ(b, a);
118}
119
120TEST(fr, PostfixIncrement)
121{
122 fr a{ 0x5def, 0x00, 0x00, 0x00 };
123 fr a_old = a;
124 fr b = a++;
125 EXPECT_EQ(b, a_old);
126 EXPECT_EQ(a, a_old + 1);
127}
128
129TEST(fr, ToMontgomeryForm)
130{
131 fr result{ 0x01, 0x00, 0x00, 0x00 };
132 fr expected = fr::one();
133 result.self_to_montgomery_form();
134 EXPECT_EQ((result == expected), true);
135}
136
137TEST(fr, FromMontgomeryForm)
138{
139 fr result = fr::one();
140 fr expected{ 0x01, 0x00, 0x00, 0x00 };
142 EXPECT_EQ((result == expected), true);
143}
144
145TEST(fr, MontgomeryConsistencyCheck)
146{
149 fr aR;
150 fr bR;
151 fr aRR;
152 fr bRR;
153 fr bRRR;
154 fr result_a;
155 fr result_b;
156 fr result_c;
157 fr result_d;
158 aR = a.to_montgomery_form();
159 aRR = aR.to_montgomery_form();
160 bR = b.to_montgomery_form();
161 bRR = bR.to_montgomery_form();
162 bRRR = bRR.to_montgomery_form();
163 result_a = aRR * bRR; // abRRR
164 result_b = aR * bRRR; // abRRR
165 result_c = aR * bR; // abR
166 result_d = a * b; // abR^-1
167 EXPECT_EQ((result_a == result_b), true);
168 result_a.self_from_montgomery_form(); // abRR
169 result_a.self_from_montgomery_form(); // abR
170 result_a.self_from_montgomery_form(); // ab
171 result_c.self_from_montgomery_form(); // ab
172 result_d.self_to_montgomery_form(); // ab
173 EXPECT_EQ((result_a == result_c), true);
174 EXPECT_EQ((result_a == result_d), true);
175}
176
177TEST(fr, AddMulConsistency)
178{
179 fr multiplicand = { 0x09, 0, 0, 0 };
180 multiplicand.self_to_montgomery_form();
181
183 fr result;
184 result = a + a; // 2
185 result += result; // 4
186 result += result; // 8
187 result += a; // 9
188
189 fr expected;
190 expected = a * multiplicand;
191
192 EXPECT_EQ((result == expected), true);
193}
194
195TEST(fr, SubMulConsistency)
196{
197 fr multiplicand = { 0x05, 0, 0, 0 };
198 multiplicand.self_to_montgomery_form();
199
201 fr result;
202 result = a + a; // 2
203 result += result; // 4
204 result += result; // 8
205 result -= a; // 7
206 result -= a; // 6
207 result -= a; // 5
208
209 fr expected;
210 expected = a * multiplicand;
211
212 EXPECT_EQ((result == expected), true);
213}
214
215TEST(fr, Lambda)
216{
218
219 fr lambda_x = { x.data[0], x.data[1], x.data[2], x.data[3] };
220 fr lambda = fr::cube_root_of_unity();
221 lambda_x = lambda_x * lambda;
222
223 // compute x^3
224 fr x_cubed;
225 x_cubed = x * x;
226 x_cubed *= x;
227
228 // compute lambda_x^3
229 fr lambda_x_cubed;
230 lambda_x_cubed = lambda_x * lambda_x;
231 lambda_x_cubed *= lambda_x;
232
233 EXPECT_EQ((x_cubed == lambda_x_cubed), true);
234}
235
236TEST(fr, Invert)
237{
238 fr input = fr::random_element();
239 fr inverse = input.invert();
240 fr result = input * inverse;
241
242 EXPECT_EQ((result == fr::one()), true);
243}
244
245TEST(fr, InvertOneIsOne)
246{
247 fr result = fr::one();
248 result = result.invert();
249 EXPECT_EQ((result == fr::one()), true);
250}
251
252TEST(fr, Sqrt)
253{
254 fr input = fr::one();
255 auto [is_sqr, root] = input.sqrt();
256 fr result = root.sqr();
257 EXPECT_EQ(result, input);
258}
259
260TEST(fr, SqrtRandom)
261{
262 size_t n = 1;
263 for (size_t i = 0; i < n; ++i) {
264 fr input = fr::random_element().sqr();
265 auto [is_sqr, root] = input.sqrt();
266 fr root_test = root.sqr();
267 EXPECT_EQ(root_test, input);
268 }
269}
270
271TEST(fr, OneAndZero)
272{
273 fr result;
274 result = fr::one() - fr::one();
275 EXPECT_EQ((result == fr::zero()), true);
276}
277
278TEST(fr, Copy)
279{
280 fr result = fr::random_element();
281 fr expected;
282 fr::__copy(result, expected);
283 EXPECT_EQ((result == expected), true);
284}
285
286TEST(fr, Neg)
287{
289 fr b;
290 b = -a;
291 fr result;
292 result = a + b;
293 EXPECT_EQ((result == fr::zero()), true);
294}
295
296TEST(fr, SplitIntoEndomorphismScalars)
297{
299 fr k1 = { 0, 0, 0, 0 };
300 fr k2 = { 0, 0, 0, 0 };
301
303
304 fr result{ 0, 0, 0, 0 };
305
308
309 fr lambda = fr::cube_root_of_unity();
310 result = k2 * lambda;
311 result = k1 - result;
312
314 EXPECT_EQ(result, k);
315}
316
317TEST(fr, SplitIntoEndomorphismScalarsSimple)
318{
319
320 fr input = { 1, 0, 0, 0 };
321 fr k = { 0, 0, 0, 0 };
322 fr k1 = { 0, 0, 0, 0 };
323 fr k2 = { 0, 0, 0, 0 };
324 fr::__copy(input, k);
325
327
328 fr result{ 0, 0, 0, 0 };
331
332 fr lambda = fr::cube_root_of_unity();
333 result = k2 * lambda;
334 result = k1 - result;
335
337 for (size_t i = 0; i < 4; ++i) {
338 EXPECT_EQ(result.data[i], k.data[i]);
339 }
340}
341
342TEST(fr, BatchInvert)
343{
344 size_t n = 10;
345 std::vector<fr> coeffs(n);
346 std::vector<fr> inverses(n);
347 fr one = fr::one();
348 for (size_t i = 0; i < n; ++i) {
349 coeffs[i] = fr::random_element();
350 fr::__copy(coeffs[i], inverses[i]);
351 }
352 fr::batch_invert(&inverses[0], n);
353
354 for (size_t i = 0; i < n; ++i) {
355 coeffs[i] *= inverses[i];
356 coeffs[i] -= one;
357 }
358
359 for (size_t i = 0; i < n; ++i) {
360 EXPECT_TRUE(coeffs[i].is_zero());
361 }
362}
363
364TEST(fr, MultiplicativeGenerator)
365{
366 EXPECT_EQ(fr::multiplicative_generator(), fr(5));
367}
368
369TEST(fr, Uint256Conversions)
370{
371 constexpr uint256_t a{ 0x1111, 0x2222, 0x3333, 0x4444 };
372
373 constexpr fr b(a);
374 constexpr uint256_t c = b;
375
376 static_assert(a == c);
377 EXPECT_EQ(a, c);
378}
379// This test shows that ((lo|hi)% modulus) in uint512_t is equivalent to (lo + 2^256 * hi) in field elements so we
380// don't have to use the slow API (uint512_t's modulo operation)
381TEST(fr, EquivalentRandomness)
382{
384 uint512_t random_uint512 = engine.get_random_uint512();
385 auto random_lo = fr(random_uint512.lo);
386 auto random_hi = fr(random_uint512.hi);
388 constexpr auto pow_2_256 = fr(uint256_t(1) << 128).sqr();
389 EXPECT_EQ(random_lo + pow_2_256 * random_hi, fr((random_uint512 % r).lo));
390}
uint512_t get_random_uint512()
Definition engine.hpp:38
FF a
FF b
numeric::RNG & engine
uintx< uint256_t > uint512_t
Definition uintx.hpp:307
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
Entry point for Barretenberg command-line interface.
TEST(MegaCircuitBuilder, CopyConstructor)
field< Bn254FrParams > fr
Definition fr.hpp:174
static constexpr field cube_root_of_unity()
static constexpr field one()
static constexpr uint256_t modulus
BB_INLINE constexpr field to_montgomery_form() const noexcept
static void split_into_endomorphism_scalars(const field &k, field &k1, field &k2)
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field sqr() const noexcept
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
static BB_INLINE void __copy(const field &a, field &r) noexcept
BB_INLINE constexpr void self_from_montgomery_form() &noexcept
static constexpr field multiplicative_generator() noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static void batch_invert(std::span< field > coeffs) noexcept
BB_INLINE constexpr void self_to_montgomery_form() &noexcept
BB_INLINE constexpr field reduce_once() const noexcept
static constexpr field zero()
std::pair< T, T > msgpack_roundtrip(const T &object)