Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
alt_bn128_g1.cpp
Go to the documentation of this file.
1
9
10namespace libff {
11
12#ifdef PROFILE_OP_COUNTS
13long long alt_bn128_G1::add_cnt = 0;
14long long alt_bn128_G1::dbl_cnt = 0;
15#endif
16
17std::vector<size_t> alt_bn128_G1::wnaf_window_table;
21bool alt_bn128_G1::initialized = false;
22
24{
25 if (initialized)
26 {
27 this->X = G1_zero.X;
28 this->Y = G1_zero.Y;
29 this->Z = G1_zero.Z;
30 }
31}
32
34{
35 if (this->is_zero())
36 {
37 printf("O\n");
38 }
39 else
40 {
41 alt_bn128_G1 copy(*this);
42 copy.to_affine_coordinates();
43 gmp_printf("(%Nd , %Nd)\n",
44 copy.X.as_bigint().data, alt_bn128_Fq::num_limbs,
45 copy.Y.as_bigint().data, alt_bn128_Fq::num_limbs);
46 }
47}
48
50{
51 if (this->is_zero())
52 {
53 printf("O\n");
54 }
55 else
56 {
57 gmp_printf("(%Nd : %Nd : %Nd)\n",
58 this->X.as_bigint().data, alt_bn128_Fq::num_limbs,
59 this->Y.as_bigint().data, alt_bn128_Fq::num_limbs,
60 this->Z.as_bigint().data, alt_bn128_Fq::num_limbs);
61 }
62}
63
65{
66 if (this->is_zero())
67 {
68 this->X = alt_bn128_Fq::zero();
69 this->Y = alt_bn128_Fq::one();
70 this->Z = alt_bn128_Fq::zero();
71 }
72 else
73 {
74 alt_bn128_Fq Z_inv = Z.inverse();
75 alt_bn128_Fq Z2_inv = Z_inv.squared();
76 alt_bn128_Fq Z3_inv = Z2_inv * Z_inv;
77 this->X = this->X * Z2_inv;
78 this->Y = this->Y * Z3_inv;
79 this->Z = alt_bn128_Fq::one();
80 }
81}
82
87
89{
90 return (this->is_zero() || this->Z == alt_bn128_Fq::one());
91}
92
94{
95 return (this->Z.is_zero());
96}
97
98bool alt_bn128_G1::operator==(const alt_bn128_G1 &other) const
99{
100 if (this->is_zero())
101 {
102 return other.is_zero();
103 }
104
105 if (other.is_zero())
106 {
107 return false;
108 }
109
110 /* now neither is O */
111
112 // using Jacobian coordinates so:
113 // (X1:Y1:Z1) = (X2:Y2:Z2)
114 // iff
115 // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
116 // iff
117 // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
118
119 alt_bn128_Fq Z1_squared = (this->Z).squared();
120 alt_bn128_Fq Z2_squared = (other.Z).squared();
121
122 if ((this->X * Z2_squared) != (other.X * Z1_squared))
123 {
124 return false;
125 }
126
127 alt_bn128_Fq Z1_cubed = (this->Z) * Z1_squared;
128 alt_bn128_Fq Z2_cubed = (other.Z) * Z2_squared;
129
130 if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed))
131 {
132 return false;
133 }
134
135 return true;
136}
137
139{
140 return !(operator==(other));
141}
142
144{
145 // handle special cases having to do with O
146 if (this->is_zero())
147 {
148 return other;
149 }
150
151 if (other.is_zero())
152 {
153 return *this;
154 }
155
156 // no need to handle points of order 2,4
157 // (they cannot exist in a prime-order subgroup)
158
159 // check for doubling case
160
161 // using Jacobian coordinates so:
162 // (X1:Y1:Z1) = (X2:Y2:Z2)
163 // iff
164 // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
165 // iff
166 // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
167
168 alt_bn128_Fq Z1Z1 = (this->Z).squared();
169 alt_bn128_Fq Z2Z2 = (other.Z).squared();
170
171 alt_bn128_Fq U1 = this->X * Z2Z2;
172 alt_bn128_Fq U2 = other.X * Z1Z1;
173
174 alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1;
175 alt_bn128_Fq Z2_cubed = (other.Z) * Z2Z2;
176
177 alt_bn128_Fq S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2
178 alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1
179
180 if (U1 == U2 && S1 == S2)
181 {
182 // dbl case; nothing of above can be reused
183 return this->dbl();
184 }
185
186 // rest of add case
187 alt_bn128_Fq H = U2 - U1; // H = U2-U1
188 alt_bn128_Fq S2_minus_S1 = S2-S1;
189 alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2
190 alt_bn128_Fq J = H * I; // J = H * I
191 alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1)
192 alt_bn128_Fq V = U1 * I; // V = U1 * I
193 alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V
194 alt_bn128_Fq S1_J = S1 * J;
195 alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J
196 alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
197
198 return alt_bn128_G1(X3, Y3, Z3);
199}
200
202{
203 return alt_bn128_G1(this->X, -(this->Y), this->Z);
204}
205
206
208{
209 return (*this) + (-other);
210}
211
213{
214 // handle special cases having to do with O
215 if (this->is_zero())
216 {
217 return other;
218 }
219
220 if (other.is_zero())
221 {
222 return *this;
223 }
224
225 // no need to handle points of order 2,4
226 // (they cannot exist in a prime-order subgroup)
227
228 // handle double case
229 if (this->operator==(other))
230 {
231 return this->dbl();
232 }
233
234#ifdef PROFILE_OP_COUNTS
235 this->add_cnt++;
236#endif
237 // NOTE: does not handle O and pts of order 2,4
238 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
239
240 alt_bn128_Fq Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2
241 alt_bn128_Fq Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2
242 alt_bn128_Fq U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2
243 alt_bn128_Fq U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1
244 alt_bn128_Fq S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2
245 alt_bn128_Fq S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1
246 alt_bn128_Fq H = U2 - U1; // H = U2-U1
247 alt_bn128_Fq S2_minus_S1 = S2-S1;
248 alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2
249 alt_bn128_Fq J = H * I; // J = H * I
250 alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1)
251 alt_bn128_Fq V = U1 * I; // V = U1 * I
252 alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V
253 alt_bn128_Fq S1_J = S1 * J;
254 alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J
255 alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
256
257 return alt_bn128_G1(X3, Y3, Z3);
258}
259
261{
262#ifdef DEBUG
263 assert(other.is_special());
264#endif
265
266 // handle special cases having to do with O
267 if (this->is_zero())
268 {
269 return other;
270 }
271
272 if (other.is_zero())
273 {
274 return *this;
275 }
276
277 // no need to handle points of order 2,4
278 // (they cannot exist in a prime-order subgroup)
279
280 // check for doubling case
281
282 // using Jacobian coordinates so:
283 // (X1:Y1:Z1) = (X2:Y2:Z2)
284 // iff
285 // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
286 // iff
287 // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
288
289 // we know that Z2 = 1
290
291 const alt_bn128_Fq Z1Z1 = (this->Z).squared();
292
293 const alt_bn128_Fq &U1 = this->X;
294 const alt_bn128_Fq U2 = other.X * Z1Z1;
295
296 const alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1;
297
298 const alt_bn128_Fq &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2
299 const alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1
300
301 if (U1 == U2 && S1 == S2)
302 {
303 // dbl case; nothing of above can be reused
304 return this->dbl();
305 }
306
307#ifdef PROFILE_OP_COUNTS
308 this->add_cnt++;
309#endif
310
311 // NOTE: does not handle O and pts of order 2,4
312 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
313 alt_bn128_Fq H = U2-(this->X); // H = U2-X1
314 alt_bn128_Fq HH = H.squared() ; // HH = H&2
315 alt_bn128_Fq I = HH+HH; // I = 4*HH
316 I = I + I;
317 alt_bn128_Fq J = H*I; // J = H*I
318 alt_bn128_Fq r = S2-(this->Y); // r = 2*(S2-Y1)
319 r = r + r;
320 alt_bn128_Fq V = (this->X) * I ; // V = X1*I
321 alt_bn128_Fq X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V
322 alt_bn128_Fq Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J
323 Y3 = r*(V-X3) - Y3 - Y3;
324 alt_bn128_Fq Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH
325
326 return alt_bn128_G1(X3, Y3, Z3);
327}
328
330{
331#ifdef PROFILE_OP_COUNTS
332 this->dbl_cnt++;
333#endif
334 // handle point at infinity
335 if (this->is_zero())
336 {
337 return (*this);
338 }
339
340 // no need to handle points of order 2,4
341 // (they cannot exist in a prime-order subgroup)
342
343 // NOTE: does not handle O and pts of order 2,4
344 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
345
346 alt_bn128_Fq A = (this->X).squared(); // A = X1^2
347 alt_bn128_Fq B = (this->Y).squared(); // B = Y1^2
348 alt_bn128_Fq C = B.squared(); // C = B^2
349 alt_bn128_Fq D = (this->X + B).squared() - A - C;
350 D = D+D; // D = 2 * ((X1 + B)^2 - A - C)
351 alt_bn128_Fq E = A + A + A; // E = 3 * A
352 alt_bn128_Fq F = E.squared(); // F = E^2
353 alt_bn128_Fq X3 = F - (D+D); // X3 = F - 2 D
354 alt_bn128_Fq eightC = C+C;
355 eightC = eightC + eightC;
356 eightC = eightC + eightC;
357 alt_bn128_Fq Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C
358 alt_bn128_Fq Y1Z1 = (this->Y)*(this->Z);
359 alt_bn128_Fq Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1
360
361 return alt_bn128_G1(X3, Y3, Z3);
362}
363
365{
366 if (this->is_zero())
367 {
368 return true;
369 }
370 else
371 {
372 /*
373 y^2 = x^3 + b
374
375 We are using Jacobian coordinates, so equation we need to check is actually
376
377 (y/z^3)^2 = (x/z^2)^3 + b
378 y^2 / z^6 = x^3 / z^6 + b
379 y^2 = x^3 + b z^6
380 */
381 alt_bn128_Fq X2 = this->X.squared();
382 alt_bn128_Fq Y2 = this->Y.squared();
383 alt_bn128_Fq Z2 = this->Z.squared();
384
385 alt_bn128_Fq X3 = this->X * X2;
386 alt_bn128_Fq Z3 = this->Z * Z2;
387 alt_bn128_Fq Z6 = Z3.squared();
388
389 return (Y2 == X3 + alt_bn128_coeff_b * Z6);
390 }
391}
392
397
399{
400 return G1_one;
401}
402
407
408std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g)
409{
410 alt_bn128_G1 copy(g);
411 copy.to_affine_coordinates();
412
413 out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR;
414#ifdef NO_PT_COMPRESSION
415 out << copy.X << OUTPUT_SEPARATOR << copy.Y;
416#else
417 /* storing LSB of Y */
418 out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1);
419#endif
420
421 return out;
422}
423
424std::istream& operator>>(std::istream &in, alt_bn128_G1 &g)
425{
426 char is_zero;
427 alt_bn128_Fq tX, tY;
428
429#ifdef NO_PT_COMPRESSION
430 in >> is_zero >> tX >> tY;
431 is_zero -= '0';
432#else
433 in.read((char*)&is_zero, 1); // this reads is_zero;
434 is_zero -= '0';
436
437 unsigned char Y_lsb;
438 in >> tX;
440 in.read((char*)&Y_lsb, 1);
441 Y_lsb -= '0';
442
443 // y = +/- sqrt(x^3 + b)
444 if (!is_zero)
445 {
446 alt_bn128_Fq tX2 = tX.squared();
447 alt_bn128_Fq tY2 = tX2*tX + alt_bn128_coeff_b;
448 tY = tY2.sqrt();
449
450 if ((tY.as_bigint().data[0] & 1) != Y_lsb)
451 {
452 tY = -tY;
453 }
454 }
455#endif
456 // using Jacobian coordinates
457 if (!is_zero)
458 {
459 g.X = tX;
460 g.Y = tY;
461 g.Z = alt_bn128_Fq::one();
462 }
463 else
464 {
465 g = alt_bn128_G1::zero();
466 }
467
468 return in;
469}
470
471std::ostream& operator<<(std::ostream& out, const std::vector<alt_bn128_G1> &v)
472{
473 out << v.size() << "\n";
474 for (const alt_bn128_G1& t : v)
475 {
476 out << t << OUTPUT_NEWLINE;
477 }
478
479 return out;
480}
481
482std::istream& operator>>(std::istream& in, std::vector<alt_bn128_G1> &v)
483{
484 v.clear();
485
486 size_t s;
487 in >> s;
488 consume_newline(in);
489
490 v.reserve(s);
491
492 for (size_t i = 0; i < s; ++i)
493 {
494 alt_bn128_G1 g;
495 in >> g;
497 v.emplace_back(g);
498 }
499
500 return in;
501}
502
503void alt_bn128_G1::batch_to_special_all_non_zeros(std::vector<alt_bn128_G1> &vec)
504{
505 std::vector<alt_bn128_Fq> Z_vec;
506 Z_vec.reserve(vec.size());
507
508 for (auto &el: vec)
509 {
510 Z_vec.emplace_back(el.Z);
511 }
513
515
516 for (size_t i = 0; i < vec.size(); ++i)
517 {
518 alt_bn128_Fq Z2 = Z_vec[i].squared();
519 alt_bn128_Fq Z3 = Z_vec[i] * Z2;
520
521 vec[i].X = vec[i].X * Z2;
522 vec[i].Y = vec[i].Y * Z3;
523 vec[i].Z = one;
524 }
525}
526
527} // libff
const mie::Vuint & r
Definition bn.cpp:28
bool is_zero() const
Fp_model sqrt() const
Fp_model squared() const
Fp_model inverse() const
bigint< n > as_bigint() const
static Fp_model< n, modulus > random_element()
static bool initialized
static std::vector< size_t > wnaf_window_table
bool operator!=(const alt_bn128_G1 &other) const
static std::vector< size_t > fixed_base_exp_window_table
static alt_bn128_G1 zero()
static alt_bn128_G1 G1_one
bool is_well_formed() const
alt_bn128_G1 dbl() const
static alt_bn128_G1 one()
bool operator==(const alt_bn128_G1 &other) const
static void batch_to_special_all_non_zeros(std::vector< alt_bn128_G1 > &vec)
void print_coordinates() const
static alt_bn128_G1 G1_zero
alt_bn128_G1 mixed_add(const alt_bn128_G1 &other) const
alt_bn128_G1 operator-() const
alt_bn128_G1 add(const alt_bn128_G1 &other) const
bool is_special() const
alt_bn128_G1 operator+(const alt_bn128_G1 &other) const
static alt_bn128_G1 random_element()
#define D(var, file, col, who, lev,...)
Definition debug.h:44
#define OUTPUT_NEWLINE
#define OUTPUT_SEPARATOR
void consume_OUTPUT_NEWLINE(std::istream &in)
std::istream & operator>>(std::istream &in, alt_bn128_G1 &g)
void consume_OUTPUT_SEPARATOR(std::istream &in)
alt_bn128_Fq alt_bn128_coeff_b
std::ostream & operator<<(std::ostream &out, const alt_bn128_G1 &g)
void consume_newline(std::istream &in)
void batch_invert(std::vector< FieldT > &vec)
Definition test_zm.cpp:19
Definition lib.h:43
#define A
char * s