Coverage Report

Created: 2021-02-21 07:20

/src/botan/src/lib/pubkey/ec_group/point_gfp.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Point arithmetic on elliptic curves over GF(p)
3
*
4
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
5
*     2008-2011,2012,2014,2015,2018 Jack Lloyd
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9
10
#include <botan/point_gfp.h>
11
#include <botan/numthry.h>
12
#include <botan/rng.h>
13
#include <botan/internal/ct_utils.h>
14
15
namespace Botan {
16
17
PointGFp::PointGFp(const CurveGFp& curve) :
18
   m_curve(curve),
19
   m_coord_x(0),
20
   m_coord_y(curve.get_1_rep()),
21
   m_coord_z(0)
22
88.8k
   {
23
   // Assumes Montgomery rep of zero is zero
24
88.8k
   }
25
26
PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
27
   m_curve(curve),
28
   m_coord_x(x),
29
   m_coord_y(y),
30
   m_coord_z(m_curve.get_1_rep())
31
19.0k
   {
32
19.0k
   if(x < 0 || x >= curve.get_p())
33
1.50k
      throw Invalid_Argument("Invalid PointGFp affine x");
34
17.5k
   if(y < 0 || y >= curve.get_p())
35
1.99k
      throw Invalid_Argument("Invalid PointGFp affine y");
36
37
15.5k
   secure_vector<word> monty_ws(m_curve.get_ws_size());
38
15.5k
   m_curve.to_rep(m_coord_x, monty_ws);
39
15.5k
   m_curve.to_rep(m_coord_y, monty_ws);
40
15.5k
   }
41
42
void PointGFp::randomize_repr(RandomNumberGenerator& rng)
43
6.99k
   {
44
6.99k
   secure_vector<word> ws(m_curve.get_ws_size());
45
6.99k
   randomize_repr(rng, ws);
46
6.99k
   }
47
48
void PointGFp::randomize_repr(RandomNumberGenerator& rng, secure_vector<word>& ws)
49
57.8k
   {
50
57.8k
   const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p());
51
52
   /*
53
   * No reason to convert this to Montgomery representation first,
54
   * just pretend the random mask was chosen as Redc(mask) and the
55
   * random mask we generated above is in the Montgomery
56
   * representation.
57
   * //m_curve.to_rep(mask, ws);
58
   */
59
57.8k
   const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws);
60
57.8k
   const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws);
61
62
57.8k
   m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws);
63
57.8k
   m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws);
64
57.8k
   m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws);
65
57.8k
   }
66
67
namespace {
68
69
inline void resize_ws(std::vector<BigInt>& ws_bn, size_t cap_size)
70
22.3M
   {
71
22.3M
   BOTAN_ASSERT(ws_bn.size() >= PointGFp::WORKSPACE_SIZE,
72
22.3M
                "Expected size for PointGFp workspace");
73
74
201M
   for(size_t i = 0; i != ws_bn.size(); ++i)
75
179M
      if(ws_bn[i].size() < cap_size)
76
13.6M
         ws_bn[i].get_word_vector().resize(cap_size);
77
22.3M
   }
78
79
inline word all_zeros(const word x[], size_t len)
80
22.0M
   {
81
22.0M
   word z = 0;
82
180M
   for(size_t i = 0; i != len; ++i)
83
158M
      z |= x[i];
84
22.0M
   return CT::Mask<word>::is_zero(z).value();
85
22.0M
   }
86
87
}
88
89
void PointGFp::add_affine(const word x_words[], size_t x_size,
90
                          const word y_words[], size_t y_size,
91
                          std::vector<BigInt>& ws_bn)
92
6.67M
   {
93
6.67M
   if(all_zeros(x_words, x_size) & all_zeros(y_words, y_size))
94
826k
      {
95
826k
      return;
96
826k
      }
97
98
5.85M
   if(is_zero())
99
31.6k
      {
100
31.6k
      m_coord_x.set_words(x_words, x_size);
101
31.6k
      m_coord_y.set_words(y_words, y_size);
102
31.6k
      m_coord_z = m_curve.get_1_rep();
103
31.6k
      return;
104
31.6k
      }
105
106
5.81M
   resize_ws(ws_bn, m_curve.get_ws_size());
107
108
5.81M
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
109
5.81M
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
110
111
5.81M
   BigInt& T0 = ws_bn[2];
112
5.81M
   BigInt& T1 = ws_bn[3];
113
5.81M
   BigInt& T2 = ws_bn[4];
114
5.81M
   BigInt& T3 = ws_bn[5];
115
5.81M
   BigInt& T4 = ws_bn[6];
116
117
   /*
118
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
119
   simplified with Z2 = 1
120
   */
121
122
5.81M
   const BigInt& p = m_curve.get_p();
123
124
5.81M
   m_curve.sqr(T3, m_coord_z, ws); // z1^2
125
5.81M
   m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2
126
127
5.81M
   m_curve.mul(T2, m_coord_z, T3, ws); // z1^3
128
5.81M
   m_curve.mul(T0, y_words, y_size, T2, ws); // y2*z1^3
129
130
5.81M
   T4.mod_sub(m_coord_x, p, sub_ws); // x2*z1^2 - x1*z2^2
131
132
5.81M
   T0.mod_sub(m_coord_y, p, sub_ws);
133
134
5.81M
   if(T4.is_zero())
135
941
      {
136
941
      if(T0.is_zero())
137
41
         {
138
41
         mult2(ws_bn);
139
41
         return;
140
41
         }
141
142
      // setting to zero:
143
900
      m_coord_x.clear();
144
900
      m_coord_y = m_curve.get_1_rep();
145
900
      m_coord_z.clear();
146
900
      return;
147
900
      }
148
149
5.81M
   m_curve.sqr(T2, T4, ws);
150
151
5.81M
   m_curve.mul(T3, m_coord_x, T2, ws);
152
153
5.81M
   m_curve.mul(T1, T2, T4, ws);
154
155
5.81M
   m_curve.sqr(m_coord_x, T0, ws);
156
5.81M
   m_coord_x.mod_sub(T1, p, sub_ws);
157
158
5.81M
   m_coord_x.mod_sub(T3, p, sub_ws);
159
5.81M
   m_coord_x.mod_sub(T3, p, sub_ws);
160
161
5.81M
   T3.mod_sub(m_coord_x, p, sub_ws);
162
163
5.81M
   m_curve.mul(T2, T0, T3, ws);
164
5.81M
   m_curve.mul(T0, m_coord_y, T1, ws);
165
5.81M
   T2.mod_sub(T0, p, sub_ws);
166
5.81M
   m_coord_y.swap(T2);
167
168
5.81M
   m_curve.mul(T0, m_coord_z, T4, ws);
169
5.81M
   m_coord_z.swap(T0);
170
5.81M
   }
171
172
void PointGFp::add(const word x_words[], size_t x_size,
173
                   const word y_words[], size_t y_size,
174
                   const word z_words[], size_t z_size,
175
                   std::vector<BigInt>& ws_bn)
176
4.33M
   {
177
4.33M
   if(all_zeros(x_words, x_size) & all_zeros(z_words, z_size))
178
216k
      return;
179
180
4.11M
   if(is_zero())
181
40.7k
      {
182
40.7k
      m_coord_x.set_words(x_words, x_size);
183
40.7k
      m_coord_y.set_words(y_words, y_size);
184
40.7k
      m_coord_z.set_words(z_words, z_size);
185
40.7k
      return;
186
40.7k
      }
187
188
4.07M
   resize_ws(ws_bn, m_curve.get_ws_size());
189
190
4.07M
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
191
4.07M
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
192
193
4.07M
   BigInt& T0 = ws_bn[2];
194
4.07M
   BigInt& T1 = ws_bn[3];
195
4.07M
   BigInt& T2 = ws_bn[4];
196
4.07M
   BigInt& T3 = ws_bn[5];
197
4.07M
   BigInt& T4 = ws_bn[6];
198
4.07M
   BigInt& T5 = ws_bn[7];
199
200
   /*
201
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
202
   */
203
204
4.07M
   const BigInt& p = m_curve.get_p();
205
206
4.07M
   m_curve.sqr(T0, z_words, z_size, ws); // z2^2
207
4.07M
   m_curve.mul(T1, m_coord_x, T0, ws); // x1*z2^2
208
4.07M
   m_curve.mul(T3, z_words, z_size, T0, ws); // z2^3
209
4.07M
   m_curve.mul(T2, m_coord_y, T3, ws); // y1*z2^3
210
211
4.07M
   m_curve.sqr(T3, m_coord_z, ws); // z1^2
212
4.07M
   m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2
213
214
4.07M
   m_curve.mul(T5, m_coord_z, T3, ws); // z1^3
215
4.07M
   m_curve.mul(T0, y_words, y_size, T5, ws); // y2*z1^3
216
217
4.07M
   T4.mod_sub(T1, p, sub_ws); // x2*z1^2 - x1*z2^2
218
219
4.07M
   T0.mod_sub(T2, p, sub_ws);
220
221
4.07M
   if(T4.is_zero())
222
5.80k
      {
223
5.80k
      if(T0.is_zero())
224
2.21k
         {
225
2.21k
         mult2(ws_bn);
226
2.21k
         return;
227
2.21k
         }
228
229
      // setting to zero:
230
3.58k
      m_coord_x.clear();
231
3.58k
      m_coord_y = m_curve.get_1_rep();
232
3.58k
      m_coord_z.clear();
233
3.58k
      return;
234
3.58k
      }
235
236
4.07M
   m_curve.sqr(T5, T4, ws);
237
238
4.07M
   m_curve.mul(T3, T1, T5, ws);
239
240
4.07M
   m_curve.mul(T1, T5, T4, ws);
241
242
4.07M
   m_curve.sqr(m_coord_x, T0, ws);
243
4.07M
   m_coord_x.mod_sub(T1, p, sub_ws);
244
4.07M
   m_coord_x.mod_sub(T3, p, sub_ws);
245
4.07M
   m_coord_x.mod_sub(T3, p, sub_ws);
246
247
4.07M
   T3.mod_sub(m_coord_x, p, sub_ws);
248
249
4.07M
   m_curve.mul(m_coord_y, T0, T3, ws);
250
4.07M
   m_curve.mul(T3, T2, T1, ws);
251
252
4.07M
   m_coord_y.mod_sub(T3, p, sub_ws);
253
254
4.07M
   m_curve.mul(T3, z_words, z_size, m_coord_z, ws);
255
4.07M
   m_curve.mul(m_coord_z, T3, T4, ws);
256
4.07M
   }
257
258
void PointGFp::mult2i(size_t iterations, std::vector<BigInt>& ws_bn)
259
2.86M
   {
260
2.86M
   if(iterations == 0)
261
0
      return;
262
263
2.86M
   if(m_coord_y.is_zero())
264
0
      {
265
0
      *this = PointGFp(m_curve); // setting myself to zero
266
0
      return;
267
0
      }
268
269
   /*
270
   TODO we can save 2 squarings per iteration by computing
271
   a*Z^4 using values cached from previous iteration
272
   */
273
14.1M
   for(size_t i = 0; i != iterations; ++i)
274
11.3M
      mult2(ws_bn);
275
2.86M
   }
276
277
// *this *= 2
278
void PointGFp::mult2(std::vector<BigInt>& ws_bn)
279
12.5M
   {
280
12.5M
   if(is_zero())
281
115k
      return;
282
283
12.4M
   if(m_coord_y.is_zero())
284
22
      {
285
22
      *this = PointGFp(m_curve); // setting myself to zero
286
22
      return;
287
22
      }
288
289
12.4M
   resize_ws(ws_bn, m_curve.get_ws_size());
290
291
12.4M
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
292
12.4M
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
293
294
12.4M
   BigInt& T0 = ws_bn[2];
295
12.4M
   BigInt& T1 = ws_bn[3];
296
12.4M
   BigInt& T2 = ws_bn[4];
297
12.4M
   BigInt& T3 = ws_bn[5];
298
12.4M
   BigInt& T4 = ws_bn[6];
299
300
   /*
301
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc
302
   */
303
12.4M
   const BigInt& p = m_curve.get_p();
304
305
12.4M
   m_curve.sqr(T0, m_coord_y, ws);
306
307
12.4M
   m_curve.mul(T1, m_coord_x, T0, ws);
308
12.4M
   T1.mod_mul(4, p, sub_ws);
309
310
12.4M
   if(m_curve.a_is_zero())
311
136k
      {
312
      // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2
313
136k
      m_curve.sqr(T4, m_coord_x, ws); // x^2
314
136k
      T4.mod_mul(3, p, sub_ws); // 3*x^2
315
136k
      }
316
12.3M
   else if(m_curve.a_is_minus_3())
317
8.63M
      {
318
      /*
319
      if a == -3 then
320
        3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2)
321
      */
322
8.63M
      m_curve.sqr(T3, m_coord_z, ws); // z^2
323
324
      // (x-z^2)
325
8.63M
      T2 = m_coord_x;
326
8.63M
      T2.mod_sub(T3, p, sub_ws);
327
328
      // (x+z^2)
329
8.63M
      T3.mod_add(m_coord_x, p, sub_ws);
330
331
8.63M
      m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2)
332
333
8.63M
      T4.mod_mul(3, p, sub_ws); // 3*(x-z^2)*(x+z^2)
334
8.63M
      }
335
3.70M
   else
336
3.70M
      {
337
3.70M
      m_curve.sqr(T3, m_coord_z, ws); // z^2
338
3.70M
      m_curve.sqr(T4, T3, ws); // z^4
339
3.70M
      m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4
340
341
3.70M
      m_curve.sqr(T4, m_coord_x, ws); // x^2
342
3.70M
      T4.mod_mul(3, p, sub_ws);
343
3.70M
      T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4
344
3.70M
      }
345
346
12.4M
   m_curve.sqr(T2, T4, ws);
347
12.4M
   T2.mod_sub(T1, p, sub_ws);
348
12.4M
   T2.mod_sub(T1, p, sub_ws);
349
350
12.4M
   m_curve.sqr(T3, T0, ws);
351
12.4M
   T3.mod_mul(8, p, sub_ws);
352
353
12.4M
   T1.mod_sub(T2, p, sub_ws);
354
355
12.4M
   m_curve.mul(T0, T4, T1, ws);
356
12.4M
   T0.mod_sub(T3, p, sub_ws);
357
358
12.4M
   m_coord_x.swap(T2);
359
360
12.4M
   m_curve.mul(T2, m_coord_y, m_coord_z, ws);
361
12.4M
   T2.mod_mul(2, p, sub_ws);
362
363
12.4M
   m_coord_y.swap(T0);
364
12.4M
   m_coord_z.swap(T2);
365
12.4M
   }
366
367
// arithmetic operators
368
PointGFp& PointGFp::operator+=(const PointGFp& rhs)
369
20.8k
   {
370
20.8k
   std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE);
371
20.8k
   add(rhs, ws);
372
20.8k
   return *this;
373
20.8k
   }
374
375
PointGFp& PointGFp::operator-=(const PointGFp& rhs)
376
0
   {
377
0
   PointGFp minus_rhs = PointGFp(rhs).negate();
378
379
0
   if(is_zero())
380
0
      *this = minus_rhs;
381
0
   else
382
0
      *this += minus_rhs;
383
384
0
   return *this;
385
0
   }
386
387
PointGFp& PointGFp::operator*=(const BigInt& scalar)
388
0
   {
389
0
   *this = scalar * *this;
390
0
   return *this;
391
0
   }
392
393
PointGFp operator*(const BigInt& scalar, const PointGFp& point)
394
17.8k
   {
395
17.8k
   BOTAN_DEBUG_ASSERT(point.on_the_curve());
396
397
17.8k
   const size_t scalar_bits = scalar.bits();
398
399
17.8k
   std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE);
400
401
17.8k
   PointGFp R[2] = { point.zero(), point };
402
403
569k
   for(size_t i = scalar_bits; i > 0; i--)
404
551k
      {
405
551k
      const size_t b = scalar.get_bit(i - 1);
406
551k
      R[b ^ 1].add(R[b], ws);
407
551k
      R[b].mult2(ws);
408
551k
      }
409
410
17.8k
   if(scalar.is_negative())
411
0
      R[0].negate();
412
413
17.8k
   BOTAN_DEBUG_ASSERT(R[0].on_the_curve());
414
415
17.8k
   return R[0];
416
17.8k
   }
417
418
//static
419
void PointGFp::force_all_affine(std::vector<PointGFp>& points,
420
                                secure_vector<word>& ws)
421
2.28k
   {
422
2.28k
   if(points.size() <= 1)
423
0
      {
424
0
      for(size_t i = 0; i != points.size(); ++i)
425
0
         points[i].force_affine();
426
0
      return;
427
0
      }
428
429
1.34M
   for(size_t i = 0; i != points.size(); ++i)
430
1.34M
      {
431
1.34M
      if(points[i].is_zero())
432
35
         throw Invalid_State("Cannot convert zero ECC point to affine");
433
1.34M
      }
434
435
   /*
436
   For >= 2 points use Montgomery's trick
437
438
   See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography"
439
   (Hankerson, Menezes, Vanstone)
440
441
   TODO is it really necessary to save all k points in c?
442
   */
443
444
2.24k
   const CurveGFp& curve = points[0].m_curve;
445
2.24k
   const BigInt& rep_1 = curve.get_1_rep();
446
447
2.24k
   if(ws.size() < curve.get_ws_size())
448
0
      ws.resize(curve.get_ws_size());
449
450
2.24k
   std::vector<BigInt> c(points.size());
451
2.24k
   c[0] = points[0].m_coord_z;
452
453
1.34M
   for(size_t i = 1; i != points.size(); ++i)
454
1.34M
      {
455
1.34M
      curve.mul(c[i], c[i-1], points[i].m_coord_z, ws);
456
1.34M
      }
457
458
2.24k
   BigInt s_inv = curve.invert_element(c[c.size()-1], ws);
459
460
2.24k
   BigInt z_inv, z2_inv, z3_inv;
461
462
1.34M
   for(size_t i = points.size() - 1; i != 0; i--)
463
1.34M
      {
464
1.34M
      PointGFp& point = points[i];
465
466
1.34M
      curve.mul(z_inv, s_inv, c[i-1], ws);
467
468
1.34M
      s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws);
469
470
1.34M
      curve.sqr(z2_inv, z_inv, ws);
471
1.34M
      curve.mul(z3_inv, z2_inv, z_inv, ws);
472
1.34M
      point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws);
473
1.34M
      point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws);
474
1.34M
      point.m_coord_z = rep_1;
475
1.34M
      }
476
477
2.24k
   curve.sqr(z2_inv, s_inv, ws);
478
2.24k
   curve.mul(z3_inv, z2_inv, s_inv, ws);
479
2.24k
   points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws);
480
2.24k
   points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws);
481
2.24k
   points[0].m_coord_z = rep_1;
482
2.24k
   }
483
484
void PointGFp::force_affine()
485
0
   {
486
0
   if(is_zero())
487
0
      throw Invalid_State("Cannot convert zero ECC point to affine");
488
489
0
   secure_vector<word> ws;
490
491
0
   const BigInt z_inv = m_curve.invert_element(m_coord_z, ws);
492
0
   const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws);
493
0
   const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws);
494
0
   m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws);
495
0
   m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws);
496
0
   m_coord_z = m_curve.get_1_rep();
497
0
   }
498
499
bool PointGFp::is_affine() const
500
167k
   {
501
167k
   return m_curve.is_one(m_coord_z);
502
167k
   }
503
504
BigInt PointGFp::get_affine_x() const
505
87.3k
   {
506
87.3k
   if(is_zero())
507
179
      throw Invalid_State("Cannot convert zero point to affine");
508
509
87.1k
   secure_vector<word> monty_ws;
510
511
87.1k
   if(is_affine())
512
747
      return m_curve.from_rep_to_tmp(m_coord_x, monty_ws);
513
514
86.4k
   BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
515
86.4k
   z2 = m_curve.invert_element(z2, monty_ws);
516
517
86.4k
   BigInt r;
518
86.4k
   m_curve.mul(r, m_coord_x, z2, monty_ws);
519
86.4k
   m_curve.from_rep(r, monty_ws);
520
86.4k
   return r;
521
86.4k
   }
522
523
BigInt PointGFp::get_affine_y() const
524
79.9k
   {
525
79.9k
   if(is_zero())
526
0
      throw Invalid_State("Cannot convert zero point to affine");
527
528
79.9k
   secure_vector<word> monty_ws;
529
530
79.9k
   if(is_affine())
531
747
      return m_curve.from_rep_to_tmp(m_coord_y, monty_ws);
532
533
79.2k
   const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
534
79.2k
   const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
535
79.2k
   const BigInt z3_inv = m_curve.invert_element(z3, monty_ws);
536
537
79.2k
   BigInt r;
538
79.2k
   m_curve.mul(r, m_coord_y, z3_inv, monty_ws);
539
79.2k
   m_curve.from_rep(r, monty_ws);
540
79.2k
   return r;
541
79.2k
   }
542
543
bool PointGFp::on_the_curve() const
544
42.9k
   {
545
   /*
546
   Is the point still on the curve?? (If everything is correct, the
547
   point is always on its curve; then the function will return true.
548
   If somehow the state is corrupted, which suggests a fault attack
549
   (or internal computational error), then return false.
550
   */
551
42.9k
   if(is_zero())
552
427
      return true;
553
554
42.5k
   secure_vector<word> monty_ws;
555
556
42.5k
   const BigInt y2 = m_curve.from_rep_to_tmp(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws);
557
42.5k
   const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws);
558
42.5k
   const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws);
559
42.5k
   const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
560
561
42.5k
   if(m_coord_z == z2) // Is z equal to 1 (in Montgomery form)?
562
14.3k
      {
563
14.3k
      if(y2 != m_curve.from_rep_to_tmp(x3 + ax + m_curve.get_b_rep(), monty_ws))
564
332
         return false;
565
42.1k
      }
566
567
42.1k
   const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
568
42.1k
   const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws);
569
42.1k
   const BigInt b_z6 = m_curve.mul_to_tmp(m_curve.get_b_rep(), m_curve.sqr_to_tmp(z3, monty_ws), monty_ws);
570
571
42.1k
   if(y2 != m_curve.from_rep_to_tmp(x3 + ax_z4 + b_z6, monty_ws))
572
8
      return false;
573
574
42.1k
   return true;
575
42.1k
   }
576
577
// swaps the states of *this and other, does not throw!
578
void PointGFp::swap(PointGFp& other)
579
1.49M
   {
580
1.49M
   m_curve.swap(other.m_curve);
581
1.49M
   m_coord_x.swap(other.m_coord_x);
582
1.49M
   m_coord_y.swap(other.m_coord_y);
583
1.49M
   m_coord_z.swap(other.m_coord_z);
584
1.49M
   }
585
586
bool PointGFp::operator==(const PointGFp& other) const
587
27.8k
   {
588
27.8k
   if(m_curve != other.m_curve)
589
0
      return false;
590
591
   // If this is zero, only equal if other is also zero
592
27.8k
   if(is_zero())
593
112
      return other.is_zero();
594
595
27.7k
   return (get_affine_x() == other.get_affine_x() &&
596
27.7k
           get_affine_y() == other.get_affine_y());
597
27.7k
   }
598
599
// encoding and decoding
600
std::vector<uint8_t> PointGFp::encode(PointGFp::Compression_Type format) const
601
24.5k
   {
602
24.5k
   if(is_zero())
603
11
      return std::vector<uint8_t>(1); // single 0 byte
604
605
24.5k
   const size_t p_bytes = m_curve.get_p().bytes();
606
607
24.5k
   const BigInt x = get_affine_x();
608
24.5k
   const BigInt y = get_affine_y();
609
610
24.5k
   std::vector<uint8_t> result;
611
612
24.5k
   if(format == PointGFp::UNCOMPRESSED)
613
16.2k
      {
614
16.2k
      result.resize(1 + 2*p_bytes);
615
16.2k
      result[0] = 0x04;
616
16.2k
      BigInt::encode_1363(&result[1], p_bytes, x);
617
16.2k
      BigInt::encode_1363(&result[1+p_bytes], p_bytes, y);
618
16.2k
      }
619
8.25k
   else if(format == PointGFp::COMPRESSED)
620
8.25k
      {
621
8.25k
      result.resize(1 + p_bytes);
622
8.25k
      result[0] = 0x02 | static_cast<uint8_t>(y.get_bit(0));
623
8.25k
      BigInt::encode_1363(&result[1], p_bytes, x);
624
8.25k
      }
625
0
   else if(format == PointGFp::HYBRID)
626
0
      {
627
0
      result.resize(1 + 2*p_bytes);
628
0
      result[0] = 0x06 | static_cast<uint8_t>(y.get_bit(0));
629
0
      BigInt::encode_1363(&result[1], p_bytes, x);
630
0
      BigInt::encode_1363(&result[1+p_bytes], p_bytes, y);
631
0
      }
632
0
   else
633
0
      throw Invalid_Argument("EC2OSP illegal point encoding");
634
635
24.5k
   return result;
636
24.5k
   }
637
638
namespace {
639
640
BigInt decompress_point(bool yMod2,
641
                        const BigInt& x,
642
                        const BigInt& curve_p,
643
                        const BigInt& curve_a,
644
                        const BigInt& curve_b)
645
19.1k
   {
646
19.1k
   BigInt xpow3 = x * x * x;
647
648
19.1k
   BigInt g = curve_a * x;
649
19.1k
   g += xpow3;
650
19.1k
   g += curve_b;
651
19.1k
   g = g % curve_p;
652
653
19.1k
   BigInt z = ressol(g, curve_p);
654
655
19.1k
   if(z < 0)
656
6.26k
      throw Decoding_Error("Error during EC point decompression");
657
658
12.8k
   if(z.get_bit(0) != yMod2)
659
5.36k
      z = curve_p - z;
660
661
12.8k
   return z;
662
12.8k
   }
663
664
}
665
666
PointGFp OS2ECP(const uint8_t data[], size_t data_len,
667
                const CurveGFp& curve)
668
21.4k
   {
669
   // Should we really be doing this?
670
21.4k
   if(data_len <= 1)
671
499
      return PointGFp(curve); // return zero
672
673
20.9k
   std::pair<BigInt, BigInt> xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b());
674
675
20.9k
   PointGFp point(curve, xy.first, xy.second);
676
677
20.9k
   if(!point.on_the_curve())
678
332
      throw Decoding_Error("OS2ECP: Decoded point was not on the curve");
679
680
20.5k
   return point;
681
20.5k
   }
682
683
std::pair<BigInt, BigInt> OS2ECP(const uint8_t data[], size_t data_len,
684
                                 const BigInt& curve_p,
685
                                 const BigInt& curve_a,
686
                                 const BigInt& curve_b)
687
21.1k
   {
688
21.1k
   if(data_len <= 1)
689
1
      throw Decoding_Error("OS2ECP invalid point");
690
691
21.1k
   const uint8_t pc = data[0];
692
693
21.1k
   BigInt x, y;
694
695
21.1k
   if(pc == 2 || pc == 3)
696
17.8k
      {
697
      //compressed form
698
17.8k
      x = BigInt::decode(&data[1], data_len - 1);
699
700
17.8k
      const bool y_mod_2 = ((pc & 0x01) == 1);
701
17.8k
      y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b);
702
17.8k
      }
703
3.21k
   else if(pc == 4)
704
1.78k
      {
705
1.78k
      const size_t l = (data_len - 1) / 2;
706
707
      // uncompressed form
708
1.78k
      x = BigInt::decode(&data[1], l);
709
1.78k
      y = BigInt::decode(&data[l+1], l);
710
1.78k
      }
711
1.42k
   else if(pc == 6 || pc == 7)
712
1.22k
      {
713
1.22k
      const size_t l = (data_len - 1) / 2;
714
715
      // hybrid form
716
1.22k
      x = BigInt::decode(&data[1], l);
717
1.22k
      y = BigInt::decode(&data[l+1], l);
718
719
1.22k
      const bool y_mod_2 = ((pc & 0x01) == 1);
720
721
1.22k
      if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y)
722
702
         throw Decoding_Error("OS2ECP: Decoding error in hybrid format");
723
206
      }
724
206
   else
725
206
      throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc));
726
727
20.2k
   return std::make_pair(x, y);
728
20.2k
   }
729
730
}