Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
bw6_761_g1.cpp
Go to the documentation of this file.
2 
3 namespace libff
4 {
5 
6 #ifdef PROFILE_OP_COUNTS
7 long long bw6_761_G1::add_cnt = 0;
8 long long bw6_761_G1::dbl_cnt = 0;
9 #endif
10 
11 std::vector<size_t> bw6_761_G1::wnaf_window_table;
12 std::vector<size_t> bw6_761_G1::fixed_base_exp_window_table;
13 bw6_761_G1 bw6_761_G1::G1_zero;
14 bw6_761_G1 bw6_761_G1::G1_one;
17 bigint<bw6_761_G1::h_limbs> bw6_761_G1::h;
18 
20 {
21  this->X = G1_zero.X;
22  this->Y = G1_zero.Y;
23  this->Z = G1_zero.Z;
24 }
25 
26 void bw6_761_G1::print() const
27 {
28  if (this->is_zero()) {
29  printf("O\n");
30  } else {
31  bw6_761_G1 copy(*this);
32  copy.to_affine_coordinates();
33  gmp_printf(
34  "(%Nd , %Nd)\n",
35  copy.X.as_bigint().data,
37  copy.Y.as_bigint().data,
39  }
40 }
41 
43 {
44  if (this->is_zero()) {
45  printf("O\n");
46  } else {
47  gmp_printf(
48  "(%Nd : %Nd : %Nd)\n",
49  this->X.as_bigint().data,
51  this->Y.as_bigint().data,
53  this->Z.as_bigint().data,
55  }
56 }
57 
59 {
60  if (this->is_zero()) {
61  this->X = bw6_761_Fq::zero();
62  this->Y = bw6_761_Fq::one();
63  this->Z = bw6_761_Fq::zero();
64  } else {
65  const bw6_761_Fq Z_inv = Z.inverse();
66  this->X = this->X * Z_inv;
67  this->Y = this->Y * Z_inv;
68  this->Z = bw6_761_Fq::one();
69  }
70 }
71 
73 
75 {
76  return (this->is_zero() || this->Z == bw6_761_Fq::one());
77 }
78 
79 bool bw6_761_G1::is_zero() const
80 {
81  return (this->X.is_zero() && this->Z.is_zero());
82 }
83 
84 bool bw6_761_G1::operator==(const bw6_761_G1 &other) const
85 {
86  if (this->is_zero()) {
87  return other.is_zero();
88  }
89 
90  if (other.is_zero()) {
91  return false;
92  }
93 
94  // Using Projective coordinates so:
95  // (X1:Y1:Z1) = (X2:Y2:Z2) <=>
96  // X1/Z1 = X2/Z2 AND Y1/Z1 = Y2/Z2 <=>
97  // X1*Z2 = X2*Z1 AND Y1*Z2 = Y2*Z1
98  if (((this->X * other.Z) != (other.X * this->Z)) ||
99  ((this->Y * other.Z) != (other.Y * this->Z))) {
100  return false;
101  }
102 
103  return true;
104 }
105 
106 bool bw6_761_G1::operator!=(const bw6_761_G1 &other) const
107 {
108  return !(operator==(other));
109 }
110 
112 {
113  // Handle special cases having to do with O
114  if (this->is_zero()) {
115  return other;
116  }
117 
118  if (other.is_zero()) {
119  return *this;
120  }
121 
122  // No need to handle points of order 2,4
123  // (they cannot exist in a prime-order subgroup)
124 
125  // X1Z2 = X1*Z2
126  const bw6_761_Fq X1Z2 = (this->X) * (other.Z);
127  // X2Z1 = X2*Z1
128  const bw6_761_Fq X2Z1 = (this->Z) * (other.X);
129 
130  // Y1Z2 = Y1*Z2
131  const bw6_761_Fq Y1Z2 = (this->Y) * (other.Z);
132  // Y2Z1 = Y2*Z1
133  const bw6_761_Fq Y2Z1 = (this->Z) * (other.Y);
134 
135  // Check if the 2 points are equal, in which can we do a point doubling
136  // (i.e. P + P)
137  // https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/doubling/dbl-2007-bl
138  if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) {
139  // XX = X1^2
140  const bw6_761_Fq XX = (this->X).squared();
141  // w = a*ZZ + 3*XX = 3*XX (since a=0)
142  const bw6_761_Fq w = XX + XX + XX;
143  const bw6_761_Fq Y1Z1 = (this->Y) * (this->Z);
144  // s = 2*Y1*Z1
145  const bw6_761_Fq s = Y1Z1 + Y1Z1;
146  // ss = s^2
147  const bw6_761_Fq ss = s.squared();
148  // sss = s*ss
149  const bw6_761_Fq sss = s * ss;
150  // R = Y1*s
151  const bw6_761_Fq R = (this->Y) * s;
152  // RR = R^2
153  const bw6_761_Fq RR = R.squared();
154  // B = (X1+R)^2 - XX - RR
155  const bw6_761_Fq B = ((this->X) + R).squared() - XX - RR;
156  // h = w^2 - 2*B
157  const bw6_761_Fq h = w.squared() - (B + B);
158  // X3 = h*s
159  const bw6_761_Fq X3 = h * s;
160  // Y3 = w*(B-h) - 2*RR
161  const bw6_761_Fq Y3 = w * (B - h) - (RR + RR);
162  // Z3 = sss
163  const bw6_761_Fq Z3 = sss;
164 
165  return bw6_761_G1(X3, Y3, Z3);
166  }
167 
168  // Point addition (i.e. P + Q, P =/= Q)
169  // https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/add-1998-cmo-2
170  // Z1Z2 = Z1*Z2
171  const bw6_761_Fq Z1Z2 = (this->Z) * (other.Z);
172  // u = Y2*Z1-Y1Z2
173  const bw6_761_Fq u = Y2Z1 - Y1Z2;
174  // uu = u^2
175  const bw6_761_Fq uu = u.squared();
176  // v = X2*Z1-X1Z2
177  const bw6_761_Fq v = X2Z1 - X1Z2;
178  // vv = v^2
179  const bw6_761_Fq vv = v.squared();
180  // vvv = v*vv
181  const bw6_761_Fq vvv = v * vv;
182  // R = vv*X1Z2
183  const bw6_761_Fq R = vv * X1Z2;
184  // A = uu*Z1Z2 - vvv - 2*R
185  const bw6_761_Fq A = uu * Z1Z2 - (vvv + R + R);
186  // X3 = v*A
187  const bw6_761_Fq X3 = v * A;
188  // Y3 = u*(R-A) - vvv*Y1Z2
189  const bw6_761_Fq Y3 = u * (R - A) - vvv * Y1Z2;
190  // Z3 = vvv*Z1Z2
191  const bw6_761_Fq Z3 = vvv * Z1Z2;
192 
193  return bw6_761_G1(X3, Y3, Z3);
194 }
195 
197 {
198  return bw6_761_G1(this->X, -(this->Y), this->Z);
199 }
200 
202 {
203  return (*this) + (-other);
204 }
205 
207 {
208  if (this->is_zero()) {
209  return other;
210  }
211 
212  if (other.is_zero()) {
213  return (*this);
214  }
215 
216  // No need to handle points of order 2,4
217  // (they cannot exist in a prime-order subgroup)
218 
219  // Point doubling (i.e. P + P)
220  if (this->operator==(other)) {
221  return this->dbl();
222  }
223 
224 #ifdef PROFILE_OP_COUNTS
225  this->add_cnt++;
226 #endif
227  // NOTE: does not handle O and pts of order 2,4
228  // Point addition (i.e. P + Q, P =/= Q)
229  // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2
230  // Y1Z2 = Y1*Z2
231  const bw6_761_Fq Y1Z2 = (this->Y) * (other.Z);
232  // X1Z2 = X1*Z2
233  const bw6_761_Fq X1Z2 = (this->X) * (other.Z);
234  // Z1Z2 = Z1*Z2
235  const bw6_761_Fq Z1Z2 = (this->Z) * (other.Z);
236  // u = Y2*Z1-Y1Z2
237  const bw6_761_Fq u = (other.Y) * (this->Z) - Y1Z2;
238  // uu = u^2
239  const bw6_761_Fq uu = u.squared();
240  // v = X2*Z1-X1Z2
241  const bw6_761_Fq v = (other.X) * (this->Z) - X1Z2;
242  // vv = v^2
243  const bw6_761_Fq vv = v.squared();
244  // vvv = v*vv
245  const bw6_761_Fq vvv = v * vv;
246  // R = vv*X1Z2
247  const bw6_761_Fq R = vv * X1Z2;
248  // A = uu*Z1Z2 - vvv - 2*R
249  const bw6_761_Fq A = uu * Z1Z2 - (vvv + R + R);
250  // X3 = v*A
251  const bw6_761_Fq X3 = v * A;
252  // Y3 = u*(R-A) - vvv*Y1Z2
253  const bw6_761_Fq Y3 = u * (R - A) - vvv * Y1Z2;
254  // Z3 = vvv*Z1Z2
255  const bw6_761_Fq Z3 = vvv * Z1Z2;
256 
257  return bw6_761_G1(X3, Y3, Z3);
258 }
259 
260 // This function assumes that:
261 // *this is of the form (X1/Z1, Y1/Z1), and that
262 // other is of the form (X2, Y2), i.e. Z2=1
264 {
265 #ifdef DEBUG
266  assert(other.is_special());
267 #endif
268 
269  if (this->is_zero()) {
270  return other;
271  }
272 
273  if (other.is_zero()) {
274  return (*this);
275  }
276 
277  // X2Z1 = X2*Z1
278  const bw6_761_Fq X2Z1 = (this->Z) * (other.X);
279  // Y2Z1 = Y2*Z1
280  const bw6_761_Fq Y2Z1 = (this->Z) * (other.Y);
281 
282  // (X1/Z1) == X2 => X1 == X2Z1
283  // (Y1/Z1) == Y2 => Y1 == Y2Z1
284  if (this->X == X2Z1 && this->Y == Y2Z1) {
285  return this->dbl();
286  }
287 
288 #ifdef PROFILE_OP_COUNTS
289  this->add_cnt++;
290 #endif
291 
292  // Mixed point addition
293  // https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/madd-1998-cmo
294  // u = Y2*Z1-Y1
295  bw6_761_Fq u = Y2Z1 - this->Y;
296  // uu = u2
297  bw6_761_Fq uu = u.squared();
298  // v = X2*Z1-X1
299  bw6_761_Fq v = X2Z1 - this->X;
300  // vv = v2
301  bw6_761_Fq vv = v.squared();
302  // vvv = v*vv
303  bw6_761_Fq vvv = v * vv;
304  // R = vv*X1
305  bw6_761_Fq R = vv * this->X;
306  // A = uu*Z1-vvv-2*R
307  bw6_761_Fq A = uu * this->Z - vvv - R - R;
308  // X3 = v*A
309  bw6_761_Fq X3 = v * A;
310  // Y3 = u*(R-A)-vvv*Y1
311  bw6_761_Fq Y3 = u * (R - A) - vvv * this->Y;
312  // Z3 = vvv*Z1
313  bw6_761_Fq Z3 = vvv * this->Z;
314 
315  return bw6_761_G1(X3, Y3, Z3);
316 }
317 
319 {
320 #ifdef PROFILE_OP_COUNTS
321  this->dbl_cnt++;
322 #endif
323  if (this->is_zero()) {
324  return (*this);
325  }
326 
327  // NOTE: does not handle O and pts of order 2,4
328  // (they cannot exist in a prime-order subgroup)
329 
330  // Point doubling (i.e. P + P)
331  // https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/doubling/dbl-2007-bl
332  // XX = X1^2
333  const bw6_761_Fq XX = (this->X).squared();
334  // w = a*ZZ + 3*XX = 3*XX (since a=0)
335  const bw6_761_Fq w = XX + XX + XX;
336  const bw6_761_Fq Y1Z1 = (this->Y) * (this->Z);
337  // s = 2*Y1*Z1
338  const bw6_761_Fq s = Y1Z1 + Y1Z1;
339  // ss = s^2
340  const bw6_761_Fq ss = s.squared();
341  // sss = s*ss
342  const bw6_761_Fq sss = s * ss;
343  // R = Y1*s
344  const bw6_761_Fq R = (this->Y) * s;
345  // RR = R^2
346  const bw6_761_Fq RR = R.squared();
347  // B = (X1+R)^2 - XX - RR
348  const bw6_761_Fq B = ((this->X) + R).squared() - XX - RR;
349  // h = w^2 - 2*B
350  const bw6_761_Fq h = w.squared() - (B + B);
351  // X3 = h*s
352  const bw6_761_Fq X3 = h * s;
353  // Y3 = w*(B-h) - 2*RR
354  const bw6_761_Fq Y3 = w * (B - h) - (RR + RR);
355  // Z3 = sss
356  const bw6_761_Fq Z3 = sss;
357  return bw6_761_G1(X3, Y3, Z3);
358 }
359 
361 {
362  return bw6_761_G1::h * (*this);
363 }
364 
366 {
367  if (this->is_zero()) {
368  return true;
369  }
370 
371  // The curve equation is
372  // y^2 = x^3 + ax + b, where a=0 and b=-1
373  // We are using Projective coordinates. As such, the equation becomes:
374  // (y/z)^2 = (x/z)^3 + a (x/z) + b
375  // = z y^2 = x^3 + a z^2 x + b z^3
376  // = z (y^2 - b z^2) = x ( x^2 + a z^2)
377  // = z (y^2 - b z^2) = x^3, since a = 0
378  const bw6_761_Fq X2 = this->X.squared();
379  const bw6_761_Fq Y2 = this->Y.squared();
380  const bw6_761_Fq Z2 = this->Z.squared();
381 
382  return (this->Z * (Y2 - bw6_761_coeff_b * Z2) == this->X * X2);
383 }
384 
386 {
387  return zero() == scalar_field::mod * (*this);
388 }
389 
390 const bw6_761_G1 &bw6_761_G1::zero() { return G1_zero; }
391 
392 const bw6_761_G1 &bw6_761_G1::one() { return G1_one; }
393 
395 {
396  return (scalar_field::random_element().as_bigint()) * G1_one;
397 }
398 
399 void bw6_761_G1::write_uncompressed(std::ostream &out) const
400 {
401  bw6_761_G1 copy(*this);
402  copy.to_affine_coordinates();
403  out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR;
404  out << copy.X << OUTPUT_SEPARATOR << copy.Y;
405 }
406 
407 void bw6_761_G1::write_compressed(std::ostream &out) const
408 {
409  bw6_761_G1 copy(*this);
410  copy.to_affine_coordinates();
411  out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR;
412  /* storing LSB of Y */
413  out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1);
414 }
415 
416 std::ostream &operator<<(std::ostream &out, const bw6_761_G1 &g)
417 {
418 #ifdef NO_PT_COMPRESSION
419  g.write_uncompressed(out);
420 #else
421  g.write_compressed(out);
422 #endif
423  return out;
424 }
425 
426 void bw6_761_G1::read_uncompressed(std::istream &in, bw6_761_G1 &g)
427 {
428  char is_zero;
429  bw6_761_Fq tX, tY;
430 
431  in >> is_zero >> tX >> tY;
432  is_zero -= '0';
433 
434  // using projective coordinates
435  if (!is_zero) {
436  g.X = tX;
437  g.Y = tY;
438  g.Z = bw6_761_Fq::one();
439  } else {
440  g = bw6_761_G1::zero();
441  }
442 }
443 
444 void bw6_761_G1::read_compressed(std::istream &in, bw6_761_G1 &g)
445 {
446  char is_zero;
447  bw6_761_Fq tX, tY;
448 
449  // this reads is_zero;
450  in.read((char *)&is_zero, 1);
451  is_zero -= '0';
453 
454  unsigned char Y_lsb;
455  in >> tX;
457  in.read((char *)&Y_lsb, 1);
458  Y_lsb -= '0';
459 
460  // y = +/- sqrt(x^3 + a*x + b)
461  if (!is_zero) {
462  // using Projective coordinates
463  bw6_761_Fq tX2 = tX.squared();
464  bw6_761_Fq tY2 = tX2 * tX + bw6_761_coeff_b;
465  tY = tY2.sqrt();
466 
467  if ((tY.as_bigint().data[0] & 1) != Y_lsb) {
468  tY = -tY;
469  }
470 
471  g.X = tX;
472  g.Y = tY;
473  g.Z = bw6_761_Fq::one();
474  } else {
475  g = bw6_761_G1::zero();
476  }
477 }
478 
479 std::istream &operator>>(std::istream &in, bw6_761_G1 &g)
480 {
481 #ifdef NO_PT_COMPRESSION
483 #else
485 #endif
486  return in;
487 }
488 
489 void bw6_761_G1::batch_to_special_all_non_zeros(std::vector<bw6_761_G1> &vec)
490 {
491  std::vector<bw6_761_Fq> Z_vec;
492  Z_vec.reserve(vec.size());
493 
494  for (auto &el : vec) {
495  Z_vec.emplace_back(el.Z);
496  }
497  batch_invert<bw6_761_Fq>(Z_vec);
498 
499  const bw6_761_Fq one = bw6_761_Fq::one();
500 
501  for (size_t i = 0; i < vec.size(); ++i) {
502  vec[i].X = vec[i].X * Z_vec[i];
503  vec[i].Y = vec[i].Y * Z_vec[i];
504  vec[i].Z = one;
505  }
506 }
507 
508 } // namespace libff
libff::bw6_761_G1::fixed_base_exp_window_table
static std::vector< size_t > fixed_base_exp_window_table
Definition: bw6_761_g1.hpp:22
libff::bw6_761_G1::is_well_formed
bool is_well_formed() const
Definition: bw6_761_g1.cpp:365
libff::Fp_model::random_element
static Fp_model< n, modulus > random_element()
returns random element of Fp_model
libff::bw6_761_G1::operator-
bw6_761_G1 operator-() const
Definition: bw6_761_g1.cpp:196
libff
Definition: ffi.cpp:8
libff::bw6_761_G1::G1_zero
static bw6_761_G1 G1_zero
Definition: bw6_761_g1.hpp:23
libff::bw6_761_G1::operator==
bool operator==(const bw6_761_G1 &other) const
Definition: bw6_761_g1.cpp:84
libff::Fp_model::squared
Fp_model squared() const
libff::bw6_761_G1::coeff_b
static bw6_761_Fq coeff_b
Definition: bw6_761_g1.hpp:26
libff::bw6_761_G1::wnaf_window_table
static std::vector< size_t > wnaf_window_table
Definition: bw6_761_g1.hpp:21
libff::bw6_761_G1::zero
static const bw6_761_G1 & zero()
Definition: bw6_761_g1.cpp:390
libff::bw6_761_Fq
Fp_model< bw6_761_q_limbs, bw6_761_modulus_q > bw6_761_Fq
Definition: bw6_761_init.hpp:24
libff::Fp_model< bw6_761_q_limbs, bw6_761_modulus_q >::zero
static const Fp_model< n, modulus > & zero()
libff::Fp_model::is_zero
bool is_zero() const
libff::operator>>
std::istream & operator>>(std::istream &in, alt_bn128_G1 &g)
Definition: alt_bn128_g1.cpp:446
libff::bw6_761_G1::add
bw6_761_G1 add(const bw6_761_G1 &other) const
Definition: bw6_761_g1.cpp:206
libff::Fp_model::inverse
Fp_model inverse() const
libff::bw6_761_G1::print
void print() const
Definition: bw6_761_g1.cpp:26
libff::bw6_761_G1::operator+
bw6_761_G1 operator+(const bw6_761_G1 &other) const
Definition: bw6_761_g1.cpp:111
libff::bw6_761_G1::print_coordinates
void print_coordinates() const
Definition: bw6_761_g1.cpp:42
libff::bw6_761_G1::read_uncompressed
static void read_uncompressed(std::istream &, bw6_761_G1 &)
Definition: bw6_761_g1.cpp:426
libff::bw6_761_G1::read_compressed
static void read_compressed(std::istream &, bw6_761_G1 &)
Definition: bw6_761_g1.cpp:444
libff::Fp_model::sqrt
Fp_model sqrt() const
HAS TO BE A SQUARE (else does not terminate)
libff::Fp_model< bw6_761_q_limbs, bw6_761_modulus_q >::one
static const Fp_model< n, modulus > & one()
libff::bw6_761_G1::write_uncompressed
void write_uncompressed(std::ostream &) const
Definition: bw6_761_g1.cpp:399
OUTPUT_SEPARATOR
#define OUTPUT_SEPARATOR
Definition: serialization.hpp:69
libff::bw6_761_G1::operator!=
bool operator!=(const bw6_761_G1 &other) const
Definition: bw6_761_g1.cpp:106
libff::bw6_761_G1::one
static const bw6_761_G1 & one()
Definition: bw6_761_g1.cpp:392
libff::bw6_761_G1::is_zero
bool is_zero() const
Definition: bw6_761_g1.cpp:79
libff::bw6_761_G1::coeff_a
static bw6_761_Fq coeff_a
Definition: bw6_761_g1.hpp:25
libff::bw6_761_G1::dbl
bw6_761_G1 dbl() const
Definition: bw6_761_g1.cpp:318
libff::bw6_761_G1::is_in_safe_subgroup
bool is_in_safe_subgroup() const
Definition: bw6_761_g1.cpp:385
libff::bw6_761_G1::mul_by_cofactor
bw6_761_G1 mul_by_cofactor() const
Definition: bw6_761_g1.cpp:360
libff::consume_OUTPUT_SEPARATOR
void consume_OUTPUT_SEPARATOR(std::istream &in)
libff::Fp_model< bw6_761_q_limbs, bw6_761_modulus_q >::num_limbs
static const mp_size_t num_limbs
Definition: fp.hpp:47
libff::bw6_761_G1::to_special
void to_special()
Definition: bw6_761_g1.cpp:72
libff::bw6_761_G1::Z
bw6_761_Fq Z
Definition: bw6_761_g1.hpp:37
libff::bw6_761_G1::batch_to_special_all_non_zeros
static void batch_to_special_all_non_zeros(std::vector< bw6_761_G1 > &vec)
Definition: bw6_761_g1.cpp:489
libff::bw6_761_G1::Y
bw6_761_Fq Y
Definition: bw6_761_g1.hpp:37
libff::bw6_761_coeff_b
bw6_761_Fq bw6_761_coeff_b
Definition: bw6_761_init.cpp:17
libff::Fp_model::as_bigint
bigint< n > as_bigint() const
libff::Fp_model
Definition: fp.hpp:20
libff::bw6_761_G1::write_compressed
void write_compressed(std::ostream &) const
Definition: bw6_761_g1.cpp:407
libff::bw6_761_G1::X
bw6_761_Fq X
Definition: bw6_761_g1.hpp:37
libff::operator<<
std::ostream & operator<<(std::ostream &out, const alt_bn128_G1 &g)
Definition: alt_bn128_g1.cpp:436
libff::bw6_761_G1::h
static bigint< h_limbs > h
Definition: bw6_761_g1.hpp:35
libff::bw6_761_G1::G1_one
static bw6_761_G1 G1_one
Definition: bw6_761_g1.hpp:24
libff::bw6_761_G1::is_special
bool is_special() const
Definition: bw6_761_g1.cpp:74
bw6_761_g1.hpp
libff::Fp_model::mod
static const constexpr bigint< n > & mod
Definition: fp.hpp:48
libff::bw6_761_G1::mixed_add
bw6_761_G1 mixed_add(const bw6_761_G1 &other) const
Definition: bw6_761_g1.cpp:263
libff::bw6_761_G1::bw6_761_G1
bw6_761_G1()
Definition: bw6_761_g1.cpp:19
libff::bw6_761_G1
Definition: bw6_761_g1.hpp:14
libff::bw6_761_G1::random_element
static bw6_761_G1 random_element()
Definition: bw6_761_g1.cpp:394
libff::bw6_761_G1::to_affine_coordinates
void to_affine_coordinates()
Definition: bw6_761_g1.cpp:58