Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
bn128_g1.cpp
Go to the documentation of this file.
1
10
11namespace libff {
12
13#ifdef PROFILE_OP_COUNTS
14long long bn128_G1::add_cnt = 0;
15long long bn128_G1::dbl_cnt = 0;
16#endif
17
18std::vector<size_t> bn128_G1::wnaf_window_table;
20bn128_G1 bn128_G1::G1_zero = {};
21bn128_G1 bn128_G1::G1_one = {};
22bool bn128_G1::initialized = false;
23
24bn::Fp bn128_G1::sqrt(const bn::Fp &el)
25{
26 size_t v = bn128_Fq_s;
29 bn::Fp x = el * w;
30 bn::Fp b = x * w;
31
32#if DEBUG
33 // check if square with Euler's criterion
34 bn::Fp check = b;
35 for (size_t i = 0; i < v-1; ++i)
36 {
37 bn::Fp::square(check, check);
38 }
39
40 assert(check == bn::Fp(1));
41#endif
42
43 // compute square root with Tonelli--Shanks
44 // (does not terminate if not a square!)
45
46 while (b != bn::Fp(1))
47 {
48 size_t m = 0;
49 bn::Fp b2m = b;
50 while (b2m != bn::Fp(1))
51 {
52 // invariant: b2m = b^(2^m) after entering this loop
53 bn::Fp::square(b2m, b2m);
54 m += 1;
55 }
56
57 int j = v-m-1;
58 w = z;
59 while (j > 0)
60 {
61 bn::Fp::square(w, w);
62 --j;
63 } // w = z^2^(v-m-1)
64
65 z = w * w;
66 b = b * z;
67 x = x * w;
68 v = m;
69 }
70
71 return x;
72}
73
75{
77 {
78 this->X = G1_zero.X;
79 this->Y = G1_zero.Y;
80 this->Z = G1_zero.Z;
81 }
82}
83
84void bn128_G1::print() const
85{
86 if (this->is_zero())
87 {
88 printf("O\n");
89 }
90 else
91 {
92 bn128_G1 copy(*this);
93 copy.to_affine_coordinates();
94 std::cout << "(" << copy.X.toString(10) << " : " << copy.Y.toString(10) << " : " << copy.Z.toString(10) << ")\n";
95 }
96}
97
99{
100 if (this->is_zero())
101 {
102 printf("O\n");
103 }
104 else
105 {
106 std::cout << "(" << X.toString(10) << " : " << Y.toString(10) << " : " << Z.toString(10) << ")\n";
107 }
108}
109
111{
112 if (this->is_zero())
113 {
114 X = 0;
115 Y = 1;
116 Z = 0;
117 }
118 else
119 {
120 bn::Fp r;
121 r = Z;
122 r.inverse();
124 X *= Z;
125 r *= Z;
126 Y *= r;
127 Z = 1;
128 }
129}
130
132{
133 this->to_affine_coordinates();
134}
135
137{
138 return (this->is_zero() || this->Z == 1);
139}
140
142{
143 return Z.isZero();
144}
145
146bool bn128_G1::operator==(const bn128_G1 &other) const
147{
148 if (this->is_zero())
149 {
150 return other.is_zero();
151 }
152
153 if (other.is_zero())
154 {
155 return false;
156 }
157
158 /* now neither is O */
159
160 bn::Fp Z1sq, Z2sq, lhs, rhs;
161 bn::Fp::square(Z1sq, this->Z);
162 bn::Fp::square(Z2sq, other.Z);
163 bn::Fp::mul(lhs, Z2sq, this->X);
164 bn::Fp::mul(rhs, Z1sq, other.X);
165
166 if (lhs != rhs)
167 {
168 return false;
169 }
170
171 bn::Fp Z1cubed, Z2cubed;
172 bn::Fp::mul(Z1cubed, Z1sq, this->Z);
173 bn::Fp::mul(Z2cubed, Z2sq, other.Z);
174 bn::Fp::mul(lhs, Z2cubed, this->Y);
175 bn::Fp::mul(rhs, Z1cubed, other.Y);
176
177 return (lhs == rhs);
178}
179
180bool bn128_G1::operator!=(const bn128_G1& other) const
181{
182 return !(operator==(other));
183}
184
186{
187 // handle special cases having to do with O
188 if (this->is_zero())
189 {
190 return other;
191 }
192
193 if (other.is_zero())
194 {
195 return *this;
196 }
197
198 // no need to handle points of order 2,4
199 // (they cannot exist in a prime-order subgroup)
200
201 // handle double case, and then all the rest
202 if (this->operator==(other))
203 {
204 return this->dbl();
205 }
206 else
207 {
208 return this->add(other);
209 }
210}
211
213{
214 bn128_G1 result(*this);
215 bn::Fp::neg(result.Y, result.Y);
216 return result;
217}
218
220{
221 return (*this) + (-other);
222}
223
224bn128_G1 bn128_G1::add(const bn128_G1 &other) const
225{
226#ifdef PROFILE_OP_COUNTS
227 this->add_cnt++;
228#endif
229
230 bn::Fp this_coord[3], other_coord[3], result_coord[3];
231 this->fill_coord(this_coord);
232 other.fill_coord(other_coord);
233 bn::ecop::ECAdd(result_coord, this_coord, other_coord);
234
235 bn128_G1 result(result_coord);
236 return result;
237}
238
240{
241 if (this->is_zero())
242 {
243 return other;
244 }
245
246 if (other.is_zero())
247 {
248 return *this;
249 }
250
251 // no need to handle points of order 2,4
252 // (they cannot exist in a prime-order subgroup)
253
254#ifdef DEBUG
255 assert(other.is_special());
256#endif
257
258 // check for doubling case
259
260 // using Jacobian coordinates so:
261 // (X1:Y1:Z1) = (X2:Y2:Z2)
262 // iff
263 // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
264 // iff
265 // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
266
267 // we know that Z2 = 1
268
269 bn::Fp Z1Z1;
270 bn::Fp::square(Z1Z1, this->Z);
271 const bn::Fp &U1 = this->X;
272 bn::Fp U2;
273 bn::Fp::mul(U2, other.X, Z1Z1);
274 bn::Fp Z1_cubed;
275 bn::Fp::mul(Z1_cubed, this->Z, Z1Z1);
276
277 const bn::Fp &S1 = this->Y;
278 bn::Fp S2;
279 bn::Fp::mul(S2, other.Y, Z1_cubed); // S2 = Y2*Z1*Z1Z1
280
281 if (U1 == U2 && S1 == S2)
282 {
283 // dbl case; nothing of above can be reused
284 return this->dbl();
285 }
286
287#ifdef PROFILE_OP_COUNTS
288 this->add_cnt++;
289#endif
290
291 bn128_G1 result;
292 bn::Fp H, HH, I, J, r, V, tmp;
293 // H = U2-X1
294 bn::Fp::sub(H, U2, this->X);
295 // HH = H^2
296 bn::Fp::square(HH, H);
297 // I = 4*HH
298 bn::Fp::add(tmp, HH, HH);
299 bn::Fp::add(I, tmp, tmp);
300 // J = H*I
301 bn::Fp::mul(J, H, I);
302 // r = 2*(S2-Y1)
303 bn::Fp::sub(tmp, S2, this->Y);
304 bn::Fp::add(r, tmp, tmp);
305 // V = X1*I
306 bn::Fp::mul(V, this->X, I);
307 // X3 = r^2-J-2*V
308 bn::Fp::square(result.X, r);
309 bn::Fp::sub(result.X, result.X, J);
310 bn::Fp::sub(result.X, result.X, V);
311 bn::Fp::sub(result.X, result.X, V);
312 // Y3 = r*(V-X3)-2*Y1*J
313 bn::Fp::sub(tmp, V, result.X);
314 bn::Fp::mul(result.Y, r, tmp);
315 bn::Fp::mul(tmp, this->Y, J);
316 bn::Fp::sub(result.Y, result.Y, tmp);
317 bn::Fp::sub(result.Y, result.Y, tmp);
318 // Z3 = (Z1+H)^2-Z1Z1-HH
319 bn::Fp::add(tmp, this->Z, H);
320 bn::Fp::square(result.Z, tmp);
321 bn::Fp::sub(result.Z, result.Z, Z1Z1);
322 bn::Fp::sub(result.Z, result.Z, HH);
323 return result;
324}
325
327{
328#ifdef PROFILE_OP_COUNTS
329 this->dbl_cnt++;
330#endif
331
332 bn::Fp this_coord[3], result_coord[3];
333 this->fill_coord(this_coord);
334 bn::ecop::ECDouble(result_coord, this_coord);
335
336 bn128_G1 result(result_coord);
337 return result;
338}
339
341{
342 return G1_zero;
343}
344
346{
347 return G1_one;
348}
349
351{
352 return bn128_Fr::random_element().as_bigint() * G1_one;
353}
354
355std::ostream& operator<<(std::ostream &out, const bn128_G1 &g)
356{
357 bn128_G1 gcopy(g);
358 gcopy.to_affine_coordinates();
359
360 out << (gcopy.is_zero() ? '1' : '0') << OUTPUT_SEPARATOR;
361
362#ifdef NO_PT_COMPRESSION
363 /* no point compression case */
364#ifndef BINARY_OUTPUT
365 out << gcopy.X << OUTPUT_SEPARATOR << gcopy.Y;
366#else
367 out.write((char*) &gcopy.X, sizeof(gcopy.X));
368 out.write((char*) &gcopy.Y, sizeof(gcopy.Y));
369#endif
370
371#else
372 /* point compression case */
373#ifndef BINARY_OUTPUT
374 out << gcopy.X;
375#else
376 out.write((char*) &gcopy.X, sizeof(gcopy.X));
377#endif
378 out << OUTPUT_SEPARATOR << (((unsigned char*)&gcopy.Y)[0] & 1 ? '1' : '0');
379#endif
380
381 return out;
382}
383
385{
386 if (this->is_zero())
387 {
388 return true;
389 }
390 else
391 {
392 /*
393 y^2 = x^3 + b
394
395 We are using Jacobian coordinates, so equation we need to check is actually
396
397 (y/z^3)^2 = (x/z^2)^3 + b
398 y^2 / z^6 = x^3 / z^6 + b
399 y^2 = x^3 + b z^6
400 */
401 bn::Fp X2, Y2, Z2;
402 bn::Fp::square(X2, this->X);
403 bn::Fp::square(Y2, this->Y);
404 bn::Fp::square(Z2, this->Z);
405
406 bn::Fp X3, Z3, Z6;
407 bn::Fp::mul(X3, X2, this->X);
408 bn::Fp::mul(Z3, Z2, this->Z);
409 bn::Fp::square(Z6, Z3);
410
411 return (Y2 == X3 + bn128_coeff_b * Z6);
412 }
413}
414
415std::istream& operator>>(std::istream &in, bn128_G1 &g)
416{
417 char is_zero;
418 in.read((char*)&is_zero, 1); // this reads is_zero;
419 is_zero -= '0';
421
422#ifdef NO_PT_COMPRESSION
423 /* no point compression case */
424#ifndef BINARY_OUTPUT
425 in >> g.X;
427 in >> g.Y;
428#else
429 in.read((char*) &g.X, sizeof(g.X));
430 in.read((char*) &g.Y, sizeof(g.Y));
431#endif
432
433#else
434 /* point compression case */
435 bn::Fp tX;
436#ifndef BINARY_OUTPUT
437 in >> tX;
438#else
439 in.read((char*)&tX, sizeof(tX));
440#endif
442 unsigned char Y_lsb;
443 in.read((char*)&Y_lsb, 1);
444 Y_lsb -= '0';
445
446 // y = +/- sqrt(x^3 + b)
447 if (!is_zero)
448 {
449 g.X = tX;
450 bn::Fp tX2, tY2;
451 bn::Fp::square(tX2, tX);
452 bn::Fp::mul(tY2, tX2, tX);
453 bn::Fp::add(tY2, tY2, bn128_coeff_b);
454
455 g.Y = bn128_G1::sqrt(tY2);
456 if ((((unsigned char*)&g.Y)[0] & 1) != Y_lsb)
457 {
458 bn::Fp::neg(g.Y, g.Y);
459 }
460 }
461#endif
462
463 /* finalize */
464 if (!is_zero)
465 {
466 g.Z = bn::Fp(1);
467 }
468 else
469 {
470 g = bn128_G1::zero();
471 }
472
473 return in;
474}
475
476std::ostream& operator<<(std::ostream& out, const std::vector<bn128_G1> &v)
477{
478 out << v.size() << "\n";
479 for (const bn128_G1& t : v)
480 {
481 out << t << OUTPUT_NEWLINE;
482 }
483 return out;
484}
485
486std::istream& operator>>(std::istream& in, std::vector<bn128_G1> &v)
487{
488 v.clear();
489
490 size_t s;
491 in >> s;
492 consume_newline(in);
493 v.reserve(s);
494
495 for (size_t i = 0; i < s; ++i)
496 {
497 bn128_G1 g;
498 in >> g;
500 v.emplace_back(g);
501 }
502 return in;
503}
504
505void bn128_G1::batch_to_special_all_non_zeros(std::vector<bn128_G1> &vec)
506{
507 std::vector<bn::Fp> Z_vec;
508 Z_vec.reserve(vec.size());
509
510 for (auto &el: vec)
511 {
512 Z_vec.emplace_back(el.Z);
513 }
515
516 const bn::Fp one = 1;
517
518 for (size_t i = 0; i < vec.size(); ++i)
519 {
520 bn::Fp Z2, Z3;
521 bn::Fp::square(Z2, Z_vec[i]);
522 bn::Fp::mul(Z3, Z2, Z_vec[i]);
523
524 bn::Fp::mul(vec[i].X, vec[i].X, Z2);
525 bn::Fp::mul(vec[i].Y, vec[i].Y, Z3);
526 vec[i].Z = one;
527 }
528}
529
530} // libff
const mie::Vuint & r
Definition bn.cpp:28
static Fp_model< n, modulus > random_element()
bool is_well_formed() const
Definition bn128_g1.cpp:384
void print() const
Definition bn128_g1.cpp:84
bool is_zero() const
Definition bn128_g1.cpp:141
void print_coordinates() const
Definition bn128_g1.cpp:98
static bn128_G1 G1_zero
Definition bn128_g1.hpp:33
static bn128_G1 zero()
Definition bn128_g1.cpp:340
bn128_G1 dbl() const
Definition bn128_g1.cpp:326
static std::vector< size_t > wnaf_window_table
Definition bn128_g1.hpp:31
bool is_special() const
Definition bn128_g1.cpp:136
bool operator==(const bn128_G1 &other) const
Definition bn128_g1.cpp:146
bn128_G1 add(const bn128_G1 &other) const
Definition bn128_g1.cpp:224
bn128_G1 operator-() const
Definition bn128_g1.cpp:212
bn128_G1 operator+(const bn128_G1 &other) const
Definition bn128_g1.cpp:185
static bn128_G1 one()
Definition bn128_g1.cpp:345
bn128_G1 mixed_add(const bn128_G1 &other) const
Definition bn128_g1.cpp:239
void to_affine_coordinates()
Definition bn128_g1.cpp:110
static void batch_to_special_all_non_zeros(std::vector< bn128_G1 > &vec)
Definition bn128_g1.cpp:505
static std::vector< size_t > fixed_base_exp_window_table
Definition bn128_g1.hpp:32
static bool initialized
Definition bn128_g1.hpp:35
static bn128_G1 G1_one
Definition bn128_g1.hpp:34
bool operator!=(const bn128_G1 &other) const
Definition bn128_g1.cpp:180
static bn128_G1 random_element()
Definition bn128_g1.cpp:350
void fill_coord(bn::Fp coord[3]) const
Definition bn128_g1.hpp:41
Definition zm2.h:18
static void(* add)(Fp &out, const Fp &x, const Fp &y)
Definition zm2.h:83
static void(* mul)(Fp &out, const Fp &x, const Fp &y)
Definition zm2.h:93
MIE_FORCE_INLINE bool isZero() const
Definition zm2.h:127
static void(* neg)(Fp &out, const Fp &x)
Definition zm2.h:92
static void(* sub)(Fp &out, const Fp &x, const Fp &y)
Definition zm2.h:91
std::string toString(int base=10) const
Definition zm2.h:250
static void square(Fp &out, const Fp &x)
Definition zm2.h:282
#define OUTPUT_NEWLINE
#define OUTPUT_SEPARATOR
void ECDouble(FF *out, const FF *in)
Definition bn.h:2497
void ECAdd(FF *out, const FF *a, const FF *b)
Definition bn.h:2526
mie::Fp Fp
Definition bn.h:2952
mie::Vuint bn128_Fq_t_minus_1_over_2
void consume_OUTPUT_NEWLINE(std::istream &in)
void bn_batch_invert(std::vector< FieldT > &vec)
std::istream & operator>>(std::istream &in, alt_bn128_G1 &g)
void consume_OUTPUT_SEPARATOR(std::istream &in)
bn::Fp bn128_coeff_b
std::ostream & operator<<(std::ostream &out, const alt_bn128_G1 &g)
bn::Fp bn128_Fq_nqr_to_t
size_t bn128_Fq_s
void consume_newline(std::istream &in)
T power(const T &x, const S &y)
Definition zm.h:1389
Definition test_zm.cpp:19
Definition lib.h:43
char * s
uint16_t j