Botan  1.10.17
point_gfp.cpp
Go to the documentation of this file.
1 /*
2 * Point arithmetic on elliptic curves over GF(p)
3 *
4 * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
5 * 2008-2011 Jack Lloyd
6 *
7 * Distributed under the terms of the Botan license
8 */
9 
10 #include <botan/point_gfp.h>
11 #include <botan/numthry.h>
12 #include <botan/reducer.h>
13 #include <botan/internal/mp_core.h>
14 #include <botan/internal/assert.h>
15 
16 namespace Botan {
17 
19  curve(curve), ws(2 * (curve.get_p_words() + 2))
20  {
21  coord_x = 0;
22  coord_y = monty_mult(1, curve.get_r2());
23  coord_z = 0;
24  }
25 
26 PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
27  curve(curve), ws(2 * (curve.get_p_words() + 2))
28  {
29  if(x <= 0 || x >= curve.get_p())
30  throw Invalid_Argument("Invalid PointGFp x");
31  if(y <= 0 || y >= curve.get_p())
32  throw Invalid_Argument("Invalid PointGFp y");
33  coord_x = monty_mult(x, curve.get_r2());
34  coord_y = monty_mult(y, curve.get_r2());
35  coord_z = monty_mult(1, curve.get_r2());
36  }
37 
38 // Montgomery multiplication
39 void PointGFp::monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const
40  {
41  //assert(&z != &x && &z != &y);
42 
43  if(x.is_zero() || y.is_zero())
44  {
45  z = 0;
46  return;
47  }
48 
49  const BigInt& p = curve.get_p();
50  const size_t p_size = curve.get_p_words();
51  const word p_dash = curve.get_p_dash();
52 
53  SecureVector<word>& z_reg = z.get_reg();
54  z_reg.resize(2*p_size+1);
55  zeroise(z_reg);
56 
57  bigint_monty_mul(&z_reg[0], z_reg.size(),
58  x.data(), x.size(), x.sig_words(),
59  y.data(), y.size(), y.sig_words(),
60  p.data(), p_size, p_dash,
61  &ws[0]);
62  }
63 
64 // Montgomery squaring
65 void PointGFp::monty_sqr(BigInt& z, const BigInt& x) const
66  {
67  //assert(&z != &x);
68 
69  if(x.is_zero())
70  {
71  z = 0;
72  return;
73  }
74 
75  const BigInt& p = curve.get_p();
76  const word p_dash = curve.get_p_dash();
77  const size_t p_size = curve.get_p_words();
78 
79  const size_t x_sw = x.sig_words();
80  BOTAN_ASSERT(x_sw <= p_size, "x value in range");
81 
82  SecureVector<word>& z_reg = z.get_reg();
83  z_reg.resize(2*p_size+1);
84  zeroise(z_reg);
85 
86  bigint_monty_sqr(&z_reg[0], z_reg.size(),
87  x.data(), x.size(), x_sw,
88  p.data(), p_size, p_dash,
89  &ws[0]);
90  }
91 
92 // Point addition
93 void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn)
94  {
95  if(is_zero())
96  {
97  coord_x = rhs.coord_x;
98  coord_y = rhs.coord_y;
99  coord_z = rhs.coord_z;
100  return;
101  }
102  else if(rhs.is_zero())
103  return;
104 
105  const BigInt& p = curve.get_p();
106 
107  BigInt& rhs_z2 = ws_bn[0];
108  BigInt& U1 = ws_bn[1];
109  BigInt& S1 = ws_bn[2];
110 
111  BigInt& lhs_z2 = ws_bn[3];
112  BigInt& U2 = ws_bn[4];
113  BigInt& S2 = ws_bn[5];
114 
115  BigInt& H = ws_bn[6];
116  BigInt& r = ws_bn[7];
117 
118  monty_sqr(rhs_z2, rhs.coord_z);
119  monty_mult(U1, coord_x, rhs_z2);
120  monty_mult(S1, coord_y, monty_mult(rhs.coord_z, rhs_z2));
121 
122  monty_sqr(lhs_z2, coord_z);
123  monty_mult(U2, rhs.coord_x, lhs_z2);
124  monty_mult(S2, rhs.coord_y, monty_mult(coord_z, lhs_z2));
125 
126  H = U2;
127  H -= U1;
128  if(H.is_negative())
129  H += p;
130 
131  r = S2;
132  r -= S1;
133  if(r.is_negative())
134  r += p;
135 
136  if(H.is_zero())
137  {
138  if(r.is_zero())
139  {
140  mult2(ws_bn);
141  return;
142  }
143 
144  *this = PointGFp(curve); // setting myself to zero
145  return;
146  }
147 
148  monty_sqr(U2, H);
149 
150  monty_mult(S2, U2, H);
151 
152  U2 = monty_mult(U1, U2);
153 
154  monty_sqr(coord_x, r);
155  coord_x -= S2;
156  coord_x -= (U2 << 1);
157  while(coord_x.is_negative())
158  coord_x += p;
159 
160  U2 -= coord_x;
161  if(U2.is_negative())
162  U2 += p;
163 
164  monty_mult(coord_y, r, U2);
165  coord_y -= monty_mult(S1, S2);
166  if(coord_y.is_negative())
167  coord_y += p;
168 
169  monty_mult(coord_z, monty_mult(coord_z, rhs.coord_z), H);
170  }
171 
172 // *this *= 2
173 void PointGFp::mult2(std::vector<BigInt>& ws_bn)
174  {
175  if(is_zero())
176  return;
177  else if(coord_y.is_zero())
178  {
179  *this = PointGFp(curve); // setting myself to zero
180  return;
181  }
182 
183  const BigInt& p = curve.get_p();
184 
185  BigInt& y_2 = ws_bn[0];
186  BigInt& S = ws_bn[1];
187  BigInt& z4 = ws_bn[2];
188  BigInt& a_z4 = ws_bn[3];
189  BigInt& M = ws_bn[4];
190  BigInt& U = ws_bn[5];
191  BigInt& x = ws_bn[6];
192  BigInt& y = ws_bn[7];
193  BigInt& z = ws_bn[8];
194 
195  monty_sqr(y_2, coord_y);
196 
197  monty_mult(S, coord_x, y_2);
198  S <<= 2; // * 4
199  while(S >= p)
200  S -= p;
201 
202  monty_sqr(z4, monty_sqr(coord_z));
203  monty_mult(a_z4, curve.get_a_r(), z4);
204 
205  M = 3 * monty_sqr(coord_x);
206  M += a_z4;
207  while(M >= p)
208  M -= p;
209 
210  monty_sqr(x, M);
211  x -= (S << 1);
212  while(x.is_negative())
213  x += p;
214 
215  monty_sqr(U, y_2);
216  U <<= 3;
217  while(U >= p)
218  U -= p;
219 
220  S -= x;
221  while(S.is_negative())
222  S += p;
223 
224  monty_mult(y, M, S);
225  y -= U;
226  if(y.is_negative())
227  y += p;
228 
229  monty_mult(z, coord_y, coord_z);
230  z <<= 1;
231  if(z >= p)
232  z -= p;
233 
234  coord_x = x;
235  coord_y = y;
236  coord_z = z;
237  }
238 
239 // arithmetic operators
241  {
242  std::vector<BigInt> ws(9);
243  add(rhs, ws);
244  return *this;
245  }
246 
248  {
249  PointGFp minus_rhs = PointGFp(rhs).negate();
250 
251  if(is_zero())
252  *this = minus_rhs;
253  else
254  *this += minus_rhs;
255 
256  return *this;
257  }
258 
260  {
261  *this = scalar * *this;
262  return *this;
263  }
264 
266  const PointGFp& p2, const BigInt& z2)
267  {
268  const PointGFp p3 = p1 + p2;
269 
270  PointGFp H(p1.curve); // create as zero
271  size_t bits_left = std::max(z1.bits(), z2.bits());
272 
273  std::vector<BigInt> ws(9);
274 
275  while(bits_left)
276  {
277  H.mult2(ws);
278 
279  const bool z1_b = z1.get_bit(bits_left - 1);
280  const bool z2_b = z2.get_bit(bits_left - 1);
281 
282  if(z1_b == true && z2_b == true)
283  H.add(p3, ws);
284  else if(z1_b)
285  H.add(p1, ws);
286  else if(z2_b)
287  H.add(p2, ws);
288 
289  --bits_left;
290  }
291 
292  if(z1.is_negative() != z2.is_negative())
293  H.negate();
294 
295  return H;
296  }
297 
298 PointGFp operator*(const BigInt& scalar, const PointGFp& point)
299  {
300  const CurveGFp& curve = point.get_curve();
301 
302  if(scalar.is_zero())
303  return PointGFp(curve); // zero point
304 
305  std::vector<BigInt> ws(9);
306 
307  if(scalar.abs() <= 2) // special cases for small values
308  {
309  byte value = scalar.abs().byte_at(0);
310 
311  PointGFp result = point;
312 
313  if(value == 2)
314  result.mult2(ws);
315 
316  if(scalar.is_negative())
317  result.negate();
318 
319  return result;
320  }
321 
322  const size_t scalar_bits = scalar.bits();
323 
324 #if 0
325 
326  PointGFp x1 = PointGFp(curve);
327  PointGFp x2 = point;
328 
329  size_t bits_left = scalar_bits;
330 
331  // Montgomery Ladder
332  while(bits_left)
333  {
334  const bool bit_set = scalar.get_bit(bits_left - 1);
335 
336  if(bit_set)
337  {
338  x1.add(x2, ws);
339  x2.mult2(ws);
340  }
341  else
342  {
343  x2.add(x1, ws);
344  x1.mult2(ws);
345  }
346 
347  --bits_left;
348  }
349 
350  if(scalar.is_negative())
351  x1.negate();
352 
353  return x1;
354 
355 #else
356  const size_t window_size = 4;
357 
358  std::vector<PointGFp> Ps(1 << window_size);
359  Ps[0] = PointGFp(curve);
360  Ps[1] = point;
361 
362  for(size_t i = 2; i != Ps.size(); ++i)
363  {
364  Ps[i] = Ps[i-1];
365  Ps[i].add(point, ws);
366  }
367 
368  PointGFp H(curve); // create as zero
369  size_t bits_left = scalar_bits;
370 
371  while(bits_left >= window_size)
372  {
373  for(size_t i = 0; i != window_size; ++i)
374  H.mult2(ws);
375 
376  const u32bit nibble = scalar.get_substring(bits_left - window_size,
377  window_size);
378 
379  H.add(Ps[nibble], ws);
380 
381  bits_left -= window_size;
382  }
383 
384  while(bits_left)
385  {
386  H.mult2(ws);
387  if(scalar.get_bit(bits_left-1))
388  H.add(point, ws);
389 
390  --bits_left;
391  }
392 
393  if(scalar.is_negative())
394  H.negate();
395 
396  return H;
397 #endif
398  }
399 
401  {
402  if(is_zero())
403  throw Illegal_Transformation("Cannot convert zero point to affine");
404 
405  const BigInt& r2 = curve.get_r2();
406 
407  BigInt z2 = monty_sqr(coord_z);
408  z2 = inverse_mod(z2, curve.get_p());
409 
410  z2 = monty_mult(z2, r2);
411  return monty_mult(coord_x, z2);
412  }
413 
415  {
416  if(is_zero())
417  throw Illegal_Transformation("Cannot convert zero point to affine");
418 
419  const BigInt& r2 = curve.get_r2();
420 
421  BigInt z3 = monty_mult(coord_z, monty_sqr(coord_z));
422  z3 = inverse_mod(z3, curve.get_p());
423  z3 = monty_mult(z3, r2);
424  return monty_mult(coord_y, z3);
425  }
426 
428  {
429  /*
430  Is the point still on the curve?? (If everything is correct, the
431  point is always on its curve; then the function will return true.
432  If somehow the state is corrupted, which suggests a fault attack
433  (or internal computational error), then return false.
434  */
435 
436  if(is_zero())
437  return true;
438 
439  BigInt y2 = monty_mult(monty_sqr(coord_y), 1);
440  BigInt x3 = monty_mult(coord_x, monty_sqr(coord_x));
441 
442  BigInt ax = monty_mult(coord_x, curve.get_a_r());
443 
444  const BigInt& b_r = curve.get_b_r();
445 
446  BigInt z2 = monty_sqr(coord_z);
447 
448  if(coord_z == z2) // Is z equal to 1 (in Montgomery form)?
449  {
450  if(y2 != monty_mult(x3 + ax + b_r, 1))
451  return false;
452  }
453 
454  BigInt z3 = monty_mult(coord_z, z2);
455 
456  BigInt ax_z4 = monty_mult(ax, monty_sqr(z2));
457 
458  BigInt b_z6 = monty_mult(b_r, monty_sqr(z3));
459 
460  if(y2 != monty_mult(x3 + ax_z4 + b_z6, 1))
461  return false;
462 
463  return true;
464  }
465 
466 // swaps the states of *this and other, does not throw!
468  {
469  curve.swap(other.curve);
470  coord_x.swap(other.coord_x);
471  coord_y.swap(other.coord_y);
472  coord_z.swap(other.coord_z);
473  ws.swap(other.ws);
474  }
475 
476 bool PointGFp::operator==(const PointGFp& other) const
477  {
478  if(get_curve() != other.get_curve())
479  return false;
480 
481  // If this is zero, only equal if other is also zero
482  if(is_zero())
483  return other.is_zero();
484 
485  return (get_affine_x() == other.get_affine_x() &&
486  get_affine_y() == other.get_affine_y());
487  }
488 
489 // encoding and decoding
490 SecureVector<byte> EC2OSP(const PointGFp& point, byte format)
491  {
492  if(point.is_zero())
493  return SecureVector<byte>(1); // single 0 byte
494 
495  const size_t p_bytes = point.get_curve().get_p().bytes();
496 
497  BigInt x = point.get_affine_x();
498  BigInt y = point.get_affine_y();
499 
500  SecureVector<byte> bX = BigInt::encode_1363(x, p_bytes);
501  SecureVector<byte> bY = BigInt::encode_1363(y, p_bytes);
502 
503  if(format == PointGFp::UNCOMPRESSED)
504  {
505  SecureVector<byte> result;
506  result.push_back(0x04);
507 
508  result += bX;
509  result += bY;
510 
511  return result;
512  }
513  else if(format == PointGFp::COMPRESSED)
514  {
515  SecureVector<byte> result;
516  result.push_back(0x02 | static_cast<byte>(y.get_bit(0)));
517 
518  result += bX;
519 
520  return result;
521  }
522  else if(format == PointGFp::HYBRID)
523  {
524  SecureVector<byte> result;
525  result.push_back(0x06 | static_cast<byte>(y.get_bit(0)));
526 
527  result += bX;
528  result += bY;
529 
530  return result;
531  }
532  else
533  throw Invalid_Argument("illegal point encoding format specification");
534  }
535 
536 namespace {
537 
538 BigInt decompress_point(bool yMod2,
539  const BigInt& x,
540  const CurveGFp& curve)
541  {
542  BigInt xpow3 = x * x * x;
543 
544  BigInt g = curve.get_a() * x;
545  g += xpow3;
546  g += curve.get_b();
547  g = g % curve.get_p();
548 
549  BigInt z = ressol(g, curve.get_p());
550 
551  if(z < 0)
552  throw Illegal_Point("error during decompression");
553 
554  if(z.get_bit(0) != yMod2)
555  z = curve.get_p() - z;
556 
557  return z;
558  }
559 
560 }
561 
562 PointGFp OS2ECP(const byte data[], size_t data_len,
563  const CurveGFp& curve)
564  {
565  if(data_len <= 1)
566  return PointGFp(curve); // return zero
567 
568  const byte pc = data[0];
569 
570  BigInt x, y;
571 
572  if(pc == 2 || pc == 3)
573  {
574  //compressed form
575  x = BigInt::decode(&data[1], data_len - 1);
576 
577  const bool y_mod_2 = ((pc & 0x01) == 1);
578  y = decompress_point(y_mod_2, x, curve);
579  }
580  else if(pc == 4)
581  {
582  const size_t l = (data_len - 1) / 2;
583 
584  // uncompressed form
585  x = BigInt::decode(&data[1], l);
586  y = BigInt::decode(&data[l+1], l);
587  }
588  else if(pc == 6 || pc == 7)
589  {
590  const size_t l = (data_len - 1) / 2;
591 
592  // hybrid form
593  x = BigInt::decode(&data[1], l);
594  y = BigInt::decode(&data[l+1], l);
595 
596  const bool y_mod_2 = ((pc & 0x01) == 1);
597 
598  if(decompress_point(y_mod_2, x, curve) != y)
599  throw Illegal_Point("OS2ECP: Decoding error in hybrid format");
600  }
601  else
602  throw Invalid_Argument("OS2ECP: Unknown format type");
603 
604  PointGFp result(curve, x, y);
605 
606  if(!result.on_the_curve())
607  throw Illegal_Point("OS2ECP: Decoded point was not on the curve");
608 
609  return result;
610  }
611 
612 }
bool get_bit(size_t n) const
Definition: bigint.cpp:161
void resize(size_t n)
Definition: secmem.h:217
bool is_negative() const
Definition: bigint.h:245
PointGFp & operator*=(const BigInt &scalar)
Definition: point_gfp.cpp:259
size_t get_p_words() const
Definition: curve_gfp.h:89
size_t bits() const
Definition: bigint.cpp:254
u32bit get_substring(size_t offset, size_t length) const
Definition: bigint.cpp:169
PointGFp OS2ECP(const byte data[], size_t data_len, const CurveGFp &curve)
Definition: point_gfp.cpp:562
SecureVector< word > & get_reg()
Definition: bigint.h:325
bool is_zero() const
Definition: bigint.h:176
void push_back(T x)
Definition: secmem.h:149
BigInt BOTAN_DLL ressol(const BigInt &x, const BigInt &p)
Definition: ressol.cpp:17
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
void bigint_monty_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word p[], size_t p_size, word p_dash, word workspace[])
Definition: mp_monty.cpp:84
void swap(BigInt &other)
Definition: bigint.cpp:107
BigInt get_affine_x() const
Definition: point_gfp.cpp:400
BigInt get_affine_y() const
Definition: point_gfp.cpp:414
const word * data() const
Definition: bigint.h:317
#define BOTAN_ASSERT(expr, msg)
Definition: assert.h:19
unsigned char byte
Definition: types.h:22
SecureVector< byte > EC2OSP(const PointGFp &point, byte format)
Definition: point_gfp.cpp:490
void swap(PointGFp &other)
Definition: point_gfp.cpp:467
word get_p_dash() const
Definition: curve_gfp.h:84
const BigInt & get_b_r() const
Definition: curve_gfp.h:79
size_t size() const
Definition: bigint.h:284
PointGFp & negate()
Definition: point_gfp.h:117
BigInt operator*(const BigInt &x, const BigInt &y)
Definition: big_ops3.cpp:83
void swap(CurveGFp &other)
Definition: curve_gfp.h:95
size_t sig_words() const
Definition: bigint.h:290
size_t bytes() const
Definition: bigint.cpp:246
T max(T a, T b)
Definition: ct_utils.h:120
byte byte_at(size_t n) const
Definition: bigint.cpp:148
void bigint_monty_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, const word p[], size_t p_size, word p_dash, word workspace[])
Definition: mp_monty.cpp:69
bool on_the_curve() const
Definition: point_gfp.cpp:427
void swap(MemoryRegion< T > &other)
Definition: secmem.h:260
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition: numthry.cpp:314
BigInt abs() const
Definition: bigint.cpp:331
bool operator==(const PointGFp &other) const
Definition: point_gfp.cpp:476
static BigInt decode(const byte buf[], size_t length, Base base=Binary)
Definition: big_code.cpp:102
const BigInt & get_r2() const
Definition: curve_gfp.h:69
bool is_zero() const
Definition: point_gfp.h:146
const BigInt & get_a_r() const
Definition: curve_gfp.h:74
const CurveGFp & get_curve() const
Definition: point_gfp.h:128
PointGFp & operator+=(const PointGFp &rhs)
Definition: point_gfp.cpp:240
const BigInt & get_p() const
Definition: curve_gfp.h:64
PointGFp & operator-=(const PointGFp &rhs)
Definition: point_gfp.cpp:247
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:428
static SecureVector< byte > encode_1363(const BigInt &n, size_t bytes)
Definition: big_code.cpp:78
PointGFp multi_exponentiate(const PointGFp &p1, const BigInt &z1, const PointGFp &p2, const BigInt &z2)
Definition: point_gfp.cpp:265
unsigned int u32bit
Definition: types.h:32