Coverage Report

Created: 2020-02-14 15:38

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