• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 4801177854

25 Apr 2023 07:30PM UTC coverage: 92.162% (+0.02%) from 92.146%
4801177854

push

github

77592 of 84191 relevant lines covered (92.16%)

11895061.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.32
/src/lib/pubkey/ec_group/ec_point.cpp
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/ec_point.h>
11

12
#include <botan/numthry.h>
13
#include <botan/rng.h>
14
#include <botan/internal/ct_utils.h>
15

16
namespace Botan {
17

18
EC_Point::EC_Point(const CurveGFp& curve) :
24,412✔
19
   m_curve(curve),
24,412✔
20
   m_coord_x(0),
24,412✔
21
   m_coord_y(curve.get_1_rep()),
24,412✔
22
   m_coord_z(0)
24,412✔
23
   {
24
   // Assumes Montgomery rep of zero is zero
25
   }
24,412✔
26

27
EC_Point::EC_Point(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
20,438✔
28
   m_curve(curve),
20,438✔
29
   m_coord_x(x),
20,438✔
30
   m_coord_y(y),
20,438✔
31
   m_coord_z(m_curve.get_1_rep())
20,438✔
32
   {
33
   if(x < 0 || x >= curve.get_p())
40,875✔
34
      throw Invalid_Argument("Invalid EC_Point affine x");
560✔
35
   if(y < 0 || y >= curve.get_p())
39,609✔
36
      throw Invalid_Argument("Invalid EC_Point affine y");
215✔
37

38
   secure_vector<word> monty_ws(m_curve.get_ws_size());
19,663✔
39
   m_curve.to_rep(m_coord_x, monty_ws);
19,663✔
40
   m_curve.to_rep(m_coord_y, monty_ws);
39,326✔
41
   }
22,757✔
42

43
void EC_Point::randomize_repr(RandomNumberGenerator& rng)
750✔
44
   {
45
   secure_vector<word> ws(m_curve.get_ws_size());
750✔
46
   randomize_repr(rng, ws);
750✔
47
   }
750✔
48

49
void EC_Point::randomize_repr(RandomNumberGenerator& rng, secure_vector<word>& ws)
6,414✔
50
   {
51
   const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p());
6,414✔
52

53
   /*
54
   * No reason to convert this to Montgomery representation first,
55
   * just pretend the random mask was chosen as Redc(mask) and the
56
   * random mask we generated above is in the Montgomery
57
   * representation.
58
   * //m_curve.to_rep(mask, ws);
59
   */
60
   const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws);
6,414✔
61
   const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws);
6,414✔
62

63
   m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws);
6,414✔
64
   m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws);
6,414✔
65
   m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws);
12,828✔
66
   }
19,242✔
67

68
namespace {
69

70
inline void resize_ws(std::vector<BigInt>& ws_bn, size_t cap_size)
9,751,794✔
71
   {
72
   BOTAN_ASSERT(ws_bn.size() >= EC_Point::WORKSPACE_SIZE,
9,751,794✔
73
                "Expected size for EC_Point workspace");
74

75
   for(auto& ws : ws_bn)
87,766,146✔
76
      if(ws.size() < cap_size)
78,014,352✔
77
         ws.get_word_vector().resize(cap_size);
1,489,170✔
78
   }
9,751,794✔
79

80
}
81

82
void EC_Point::add_affine(const word x_words[], size_t x_size,
2,281,112✔
83
                          const word y_words[], size_t y_size,
84
                          std::vector<BigInt>& ws_bn)
85
   {
86
   if((CT::all_zeros(x_words, x_size) & CT::all_zeros(y_words, y_size)).is_set())
17,064,343✔
87
      {
88
      return;
89
      }
90

91
   if(is_zero())
4,451,468✔
92
      {
93
      m_coord_x.set_words(x_words, x_size);
15,601✔
94
      m_coord_y.set_words(y_words, y_size);
15,601✔
95
      m_coord_z = m_curve.get_1_rep();
15,601✔
96
      return;
15,601✔
97
      }
98

99
   resize_ws(ws_bn, m_curve.get_ws_size());
2,210,157✔
100

101
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
2,210,157✔
102
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
2,210,157✔
103

104
   BigInt& T0 = ws_bn[2];
2,210,157✔
105
   BigInt& T1 = ws_bn[3];
2,210,157✔
106
   BigInt& T2 = ws_bn[4];
2,210,157✔
107
   BigInt& T3 = ws_bn[5];
2,210,157✔
108
   BigInt& T4 = ws_bn[6];
2,210,157✔
109

110
   /*
111
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
112
   simplified with Z2 = 1
113
   */
114

115
   const BigInt& p = m_curve.get_p();
2,210,157✔
116

117
   m_curve.sqr(T3, m_coord_z, ws); // z1^2
2,210,157✔
118
   m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2
2,210,157✔
119

120
   m_curve.mul(T2, m_coord_z, T3, ws); // z1^3
2,210,157✔
121
   m_curve.mul(T0, y_words, y_size, T2, ws); // y2*z1^3
2,210,157✔
122

123
   T4.mod_sub(m_coord_x, p, sub_ws); // x2*z1^2 - x1*z2^2
2,210,157✔
124

125
   T0.mod_sub(m_coord_y, p, sub_ws);
2,210,157✔
126

127
   if(T4.is_zero())
4,420,314✔
128
      {
129
      if(T0.is_zero())
322✔
130
         {
131
         mult2(ws_bn);
20✔
132
         return;
20✔
133
         }
134

135
      // setting to zero:
136
      m_coord_x.clear();
141✔
137
      m_coord_y = m_curve.get_1_rep();
141✔
138
      m_coord_z.clear();
141✔
139
      return;
141✔
140
      }
141

142
   m_curve.sqr(T2, T4, ws);
2,209,996✔
143

144
   m_curve.mul(T3, m_coord_x, T2, ws);
2,209,996✔
145

146
   m_curve.mul(T1, T2, T4, ws);
2,209,996✔
147

148
   m_curve.sqr(m_coord_x, T0, ws);
2,209,996✔
149
   m_coord_x.mod_sub(T1, p, sub_ws);
2,209,996✔
150

151
   m_coord_x.mod_sub(T3, p, sub_ws);
2,209,996✔
152
   m_coord_x.mod_sub(T3, p, sub_ws);
2,209,996✔
153

154
   T3.mod_sub(m_coord_x, p, sub_ws);
2,209,996✔
155

156
   m_curve.mul(T2, T0, T3, ws);
2,209,996✔
157
   m_curve.mul(T0, m_coord_y, T1, ws);
2,209,996✔
158
   T2.mod_sub(T0, p, sub_ws);
2,209,996✔
159
   m_coord_y.swap(T2);
2,209,996✔
160

161
   m_curve.mul(T0, m_coord_z, T4, ws);
2,209,996✔
162
   m_coord_z.swap(T0);
2,209,996✔
163
   }
164

165
void EC_Point::add(const word x_words[], size_t x_size,
1,473,357✔
166
                   const word y_words[], size_t y_size,
167
                   const word z_words[], size_t z_size,
168
                   std::vector<BigInt>& ws_bn)
169
   {
170
   if((CT::all_zeros(x_words, x_size) & CT::all_zeros(z_words, z_size)).is_set())
10,980,043✔
171
      return;
172

173
   if(is_zero())
2,869,877✔
174
      {
175
      m_coord_x.set_words(x_words, x_size);
5,822✔
176
      m_coord_y.set_words(y_words, y_size);
5,822✔
177
      m_coord_z.set_words(z_words, z_size);
5,822✔
178
      return;
5,822✔
179
      }
180

181
   resize_ws(ws_bn, m_curve.get_ws_size());
1,444,149✔
182

183
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
1,444,149✔
184
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
1,444,149✔
185

186
   BigInt& T0 = ws_bn[2];
1,444,149✔
187
   BigInt& T1 = ws_bn[3];
1,444,149✔
188
   BigInt& T2 = ws_bn[4];
1,444,149✔
189
   BigInt& T3 = ws_bn[5];
1,444,149✔
190
   BigInt& T4 = ws_bn[6];
1,444,149✔
191
   BigInt& T5 = ws_bn[7];
1,444,149✔
192

193
   /*
194
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
195
   */
196

197
   const BigInt& p = m_curve.get_p();
1,444,149✔
198

199
   m_curve.sqr(T0, z_words, z_size, ws); // z2^2
1,444,149✔
200
   m_curve.mul(T1, m_coord_x, T0, ws); // x1*z2^2
1,444,149✔
201
   m_curve.mul(T3, z_words, z_size, T0, ws); // z2^3
1,444,149✔
202
   m_curve.mul(T2, m_coord_y, T3, ws); // y1*z2^3
1,444,149✔
203

204
   m_curve.sqr(T3, m_coord_z, ws); // z1^2
1,444,149✔
205
   m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2
1,444,149✔
206

207
   m_curve.mul(T5, m_coord_z, T3, ws); // z1^3
1,444,149✔
208
   m_curve.mul(T0, y_words, y_size, T5, ws); // y2*z1^3
1,444,149✔
209

210
   T4.mod_sub(T1, p, sub_ws); // x2*z1^2 - x1*z2^2
1,444,149✔
211

212
   T0.mod_sub(T2, p, sub_ws);
1,444,149✔
213

214
   if(T4.is_zero())
2,888,298✔
215
      {
216
      if(T0.is_zero())
986✔
217
         {
218
         mult2(ws_bn);
153✔
219
         return;
153✔
220
         }
221

222
      // setting to zero:
223
      m_coord_x.clear();
340✔
224
      m_coord_y = m_curve.get_1_rep();
340✔
225
      m_coord_z.clear();
340✔
226
      return;
340✔
227
      }
228

229
   m_curve.sqr(T5, T4, ws);
1,443,656✔
230

231
   m_curve.mul(T3, T1, T5, ws);
1,443,656✔
232

233
   m_curve.mul(T1, T5, T4, ws);
1,443,656✔
234

235
   m_curve.sqr(m_coord_x, T0, ws);
1,443,656✔
236
   m_coord_x.mod_sub(T1, p, sub_ws);
1,443,656✔
237
   m_coord_x.mod_sub(T3, p, sub_ws);
1,443,656✔
238
   m_coord_x.mod_sub(T3, p, sub_ws);
1,443,656✔
239

240
   T3.mod_sub(m_coord_x, p, sub_ws);
1,443,656✔
241

242
   m_curve.mul(m_coord_y, T0, T3, ws);
1,443,656✔
243
   m_curve.mul(T3, T2, T1, ws);
1,443,656✔
244

245
   m_coord_y.mod_sub(T3, p, sub_ws);
1,443,656✔
246

247
   m_curve.mul(T3, z_words, z_size, m_coord_z, ws);
1,443,656✔
248
   m_curve.mul(m_coord_z, T3, T4, ws);
1,443,656✔
249
   }
250

251
void EC_Point::mult2i(size_t iterations, std::vector<BigInt>& ws_bn)
2,275,637✔
252
   {
253
   if(iterations == 0)
2,275,637✔
254
      return;
255

256
   if(m_coord_y.is_zero())
4,548,446✔
257
      {
258
      *this = EC_Point(m_curve); // setting myself to zero
×
259
      return;
×
260
      }
261

262
   /*
263
   TODO we can save 2 squarings per iteration by computing
264
   a*Z^4 using values cached from previous iteration
265
   */
266
   for(size_t i = 0; i != iterations; ++i)
7,450,003✔
267
      mult2(ws_bn);
5,174,366✔
268
   }
269

270
// *this *= 2
271
void EC_Point::mult2(std::vector<BigInt>& ws_bn)
6,103,659✔
272
   {
273
   if(is_zero())
12,174,127✔
274
      return;
275

276
   if(m_coord_y.is_zero())
9,922,197✔
277
      {
278
      *this = EC_Point(m_curve); // setting myself to zero
×
279
      return;
×
280
      }
281

282
   resize_ws(ws_bn, m_curve.get_ws_size());
6,097,488✔
283

284
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
6,097,488✔
285
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
6,097,488✔
286

287
   BigInt& T0 = ws_bn[2];
6,097,488✔
288
   BigInt& T1 = ws_bn[3];
6,097,488✔
289
   BigInt& T2 = ws_bn[4];
6,097,488✔
290
   BigInt& T3 = ws_bn[5];
6,097,488✔
291
   BigInt& T4 = ws_bn[6];
6,097,488✔
292

293
   /*
294
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc
295
   */
296
   const BigInt& p = m_curve.get_p();
6,097,488✔
297

298
   m_curve.sqr(T0, m_coord_y, ws);
6,097,488✔
299

300
   m_curve.mul(T1, m_coord_x, T0, ws);
6,097,488✔
301
   T1.mod_mul(4, p, sub_ws);
6,097,488✔
302

303
   if(m_curve.a_is_zero())
6,097,488✔
304
      {
305
      // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2
306
      m_curve.sqr(T4, m_coord_x, ws); // x^2
268,465✔
307
      T4.mod_mul(3, p, sub_ws); // 3*x^2
268,465✔
308
      }
309
   else if(m_curve.a_is_minus_3())
5,829,023✔
310
      {
311
      /*
312
      if a == -3 then
313
        3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2)
314
      */
315
      m_curve.sqr(T3, m_coord_z, ws); // z^2
4,619,269✔
316

317
      // (x-z^2)
318
      T2 = m_coord_x;
4,619,269✔
319
      T2.mod_sub(T3, p, sub_ws);
4,619,269✔
320

321
      // (x+z^2)
322
      T3.mod_add(m_coord_x, p, sub_ws);
4,619,269✔
323

324
      m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2)
4,619,269✔
325

326
      T4.mod_mul(3, p, sub_ws); // 3*(x-z^2)*(x+z^2)
4,619,269✔
327
      }
328
   else
329
      {
330
      m_curve.sqr(T3, m_coord_z, ws); // z^2
1,209,754✔
331
      m_curve.sqr(T4, T3, ws); // z^4
1,209,754✔
332
      m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4
1,209,754✔
333

334
      m_curve.sqr(T4, m_coord_x, ws); // x^2
1,209,754✔
335
      T4.mod_mul(3, p, sub_ws);
1,209,754✔
336
      T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4
1,209,754✔
337
      }
338

339
   m_curve.sqr(T2, T4, ws);
6,097,488✔
340
   T2.mod_sub(T1, p, sub_ws);
6,097,488✔
341
   T2.mod_sub(T1, p, sub_ws);
6,097,488✔
342

343
   m_curve.sqr(T3, T0, ws);
6,097,488✔
344
   T3.mod_mul(8, p, sub_ws);
6,097,488✔
345

346
   T1.mod_sub(T2, p, sub_ws);
6,097,488✔
347

348
   m_curve.mul(T0, T4, T1, ws);
6,097,488✔
349
   T0.mod_sub(T3, p, sub_ws);
6,097,488✔
350

351
   m_coord_x.swap(T2);
6,097,488✔
352

353
   m_curve.mul(T2, m_coord_y, m_coord_z, ws);
6,097,488✔
354
   T2.mod_mul(2, p, sub_ws);
6,097,488✔
355

356
   m_coord_y.swap(T0);
6,097,488✔
357
   m_coord_z.swap(T2);
6,103,659✔
358
   }
359

360
// arithmetic operators
361
EC_Point& EC_Point::operator+=(const EC_Point& rhs)
2,376✔
362
   {
363
   std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
2,376✔
364
   add(rhs, ws);
2,376✔
365
   return *this;
2,375✔
366
   }
2,376✔
367

368
EC_Point& EC_Point::operator-=(const EC_Point& rhs)
82✔
369
   {
370
   EC_Point minus_rhs = EC_Point(rhs).negate();
82✔
371

372
   if(is_zero())
82✔
373
      *this = minus_rhs;
×
374
   else
375
      *this += minus_rhs;
82✔
376

377
   return *this;
82✔
378
   }
82✔
379

380
EC_Point& EC_Point::operator*=(const BigInt& scalar)
67✔
381
   {
382
   *this = scalar * *this;
67✔
383
   return *this;
67✔
384
   }
385

386
EC_Point operator*(const BigInt& scalar, const EC_Point& point)
2,954✔
387
   {
388
   BOTAN_DEBUG_ASSERT(point.on_the_curve());
2,954✔
389

390
   const size_t scalar_bits = scalar.bits();
2,954✔
391

392
   std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
2,954✔
393

394
   EC_Point R[2] = { point.zero(), point };
8,862✔
395

396
   for(size_t i = scalar_bits; i > 0; i--)
502,781✔
397
      {
398
      const size_t b = scalar.get_bit(i - 1);
499,827✔
399
      R[b ^ 1].add(R[b], ws);
499,827✔
400
      R[b].mult2(ws);
499,827✔
401
      }
402

403
   if(scalar.is_negative())
2,954✔
404
      R[0].negate();
×
405

406
   BOTAN_DEBUG_ASSERT(R[0].on_the_curve());
2,954✔
407

408
   return R[0];
5,908✔
409
   }
11,816✔
410

411
//static
412
void EC_Point::force_all_affine(std::vector<EC_Point>& points,
10,779✔
413
                                secure_vector<word>& ws)
414
   {
415
   if(points.size() <= 1)
10,779✔
416
      {
417
      for(auto& point : points)
×
418
         point.force_affine();
×
419
      return;
×
420
      }
421

422
   for(auto& point : points)
1,067,377✔
423
      {
424
      if(point.is_zero())
1,964,207✔
425
         throw Invalid_State("Cannot convert zero ECC point to affine");
×
426
      }
427

428
   /*
429
   For >= 2 points use Montgomery's trick
430

431
   See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography"
432
   (Hankerson, Menezes, Vanstone)
433

434
   TODO is it really necessary to save all k points in c?
435
   */
436

437
   const CurveGFp& curve = points[0].m_curve;
10,779✔
438
   const BigInt& rep_1 = curve.get_1_rep();
10,779✔
439

440
   if(ws.size() < curve.get_ws_size())
10,779✔
441
      ws.resize(curve.get_ws_size());
×
442

443
   std::vector<BigInt> c(points.size());
10,779✔
444
   c[0] = points[0].m_coord_z;
10,779✔
445

446
   for(size_t i = 1; i != points.size(); ++i)
1,056,598✔
447
      {
448
      curve.mul(c[i], c[i-1], points[i].m_coord_z, ws);
2,091,638✔
449
      }
450

451
   BigInt s_inv = curve.invert_element(c[c.size()-1], ws);
10,779✔
452

453
   BigInt z_inv, z2_inv, z3_inv;
10,779✔
454

455
   for(size_t i = points.size() - 1; i != 0; i--)
1,056,598✔
456
      {
457
      EC_Point& point = points[i];
1,045,819✔
458

459
      curve.mul(z_inv, s_inv, c[i-1], ws);
1,045,819✔
460

461
      s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws);
1,045,819✔
462

463
      curve.sqr(z2_inv, z_inv, ws);
1,045,819✔
464
      curve.mul(z3_inv, z2_inv, z_inv, ws);
1,045,819✔
465
      point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws);
2,091,638✔
466
      point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws);
2,091,638✔
467
      point.m_coord_z = rep_1;
1,045,819✔
468
      }
469

470
   curve.sqr(z2_inv, s_inv, ws);
10,779✔
471
   curve.mul(z3_inv, z2_inv, s_inv, ws);
10,779✔
472
   points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws);
21,558✔
473
   points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws);
21,558✔
474
   points[0].m_coord_z = rep_1;
10,779✔
475
   }
43,116✔
476

477
void EC_Point::force_affine()
1,377✔
478
   {
479
   if(is_zero())
1,377✔
480
      throw Invalid_State("Cannot convert zero ECC point to affine");
×
481

482
   secure_vector<word> ws;
1,377✔
483

484
   const BigInt z_inv = m_curve.invert_element(m_coord_z, ws);
1,377✔
485
   const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws);
1,377✔
486
   const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws);
1,377✔
487
   m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws);
1,377✔
488
   m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws);
1,377✔
489
   m_coord_z = m_curve.get_1_rep();
1,377✔
490
   }
5,508✔
491

492
bool EC_Point::is_affine() const
40,775✔
493
   {
494
   return m_curve.is_one(m_coord_z);
40,775✔
495
   }
496

497
BigInt EC_Point::get_affine_x() const
27,344✔
498
   {
499
   if(is_zero())
30,567✔
500
      throw Invalid_State("Cannot convert zero point to affine");
27✔
501

502
   secure_vector<word> monty_ws;
27,317✔
503

504
   if(is_affine())
27,317✔
505
      return m_curve.from_rep_to_tmp(m_coord_x, monty_ws);
2,297✔
506

507
   BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
25,020✔
508
   z2 = m_curve.invert_element(z2, monty_ws);
25,020✔
509

510
   BigInt r;
25,020✔
511
   m_curve.mul(r, m_coord_x, z2, monty_ws);
25,020✔
512
   m_curve.from_rep(r, monty_ws);
25,020✔
513
   return r;
25,020✔
514
   }
78,871✔
515

516
BigInt EC_Point::get_affine_y() const
13,485✔
517
   {
518
   if(is_zero())
13,485✔
519
      throw Invalid_State("Cannot convert zero point to affine");
27✔
520

521
   secure_vector<word> monty_ws;
13,458✔
522

523
   if(is_affine())
13,458✔
524
      return m_curve.from_rep_to_tmp(m_coord_y, monty_ws);
2,290✔
525

526
   const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
11,168✔
527
   const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
11,168✔
528
   const BigInt z3_inv = m_curve.invert_element(z3, monty_ws);
11,168✔
529

530
   BigInt r;
11,168✔
531
   m_curve.mul(r, m_coord_y, z3_inv, monty_ws);
11,168✔
532
   m_curve.from_rep(r, monty_ws);
11,168✔
533
   return r;
11,168✔
534
   }
59,639✔
535

536
bool EC_Point::on_the_curve() const
29,354✔
537
   {
538
   /*
539
   Is the point still on the curve?? (If everything is correct, the
540
   point is always on its curve; then the function will return true.
541
   If somehow the state is corrupted, which suggests a fault attack
542
   (or internal computational error), then return false.
543
   */
544
   if(is_zero())
41,178✔
545
      return true;
546

547
   secure_vector<word> monty_ws;
29,292✔
548

549
   const BigInt y2 = m_curve.from_rep_to_tmp(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws);
29,292✔
550
   const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws);
29,292✔
551
   const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws);
29,292✔
552
   const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
29,292✔
553

554
   if(m_coord_z == z2) // Is z equal to 1 (in Montgomery form)?
29,292✔
555
      {
556
      if(y2 != m_curve.from_rep_to_tmp(x3 + ax + m_curve.get_b_rep(), monty_ws))
131,405✔
557
         return false;
558
      }
559

560
   const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
29,025✔
561
   const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws);
29,025✔
562
   const BigInt b_z6 = m_curve.mul_to_tmp(m_curve.get_b_rep(), m_curve.sqr_to_tmp(z3, monty_ws), monty_ws);
29,025✔
563

564
   if(y2 != m_curve.from_rep_to_tmp(x3 + ax_z4 + b_z6, monty_ws))
145,125✔
565
      return false;
50✔
566

567
   return true;
568
   }
233,864✔
569

570
// swaps the states of *this and other, does not throw!
571
void EC_Point::swap(EC_Point& other)
930,384✔
572
   {
573
   m_curve.swap(other.m_curve);
930,384✔
574
   m_coord_x.swap(other.m_coord_x);
930,384✔
575
   m_coord_y.swap(other.m_coord_y);
930,384✔
576
   m_coord_z.swap(other.m_coord_z);
930,384✔
577
   }
930,384✔
578

579
bool EC_Point::operator==(const EC_Point& other) const
5,333✔
580
   {
581
   if(m_curve != other.m_curve)
5,333✔
582
      return false;
583

584
   // If this is zero, only equal if other is also zero
585
   if(is_zero())
8,121✔
586
      return other.is_zero();
202✔
587

588
   return (get_affine_x() == other.get_affine_x() &&
20,552✔
589
           get_affine_y() == other.get_affine_y());
20,544✔
590
   }
591

592
// encoding and decoding
593
std::vector<uint8_t> EC_Point::encode(EC_Point_Format format) const
1,786✔
594
   {
595
   if(is_zero())
1,866✔
596
      return std::vector<uint8_t>(1); // single 0 byte
162✔
597

598
   const size_t p_bytes = m_curve.get_p().bytes();
1,624✔
599

600
   const BigInt x = get_affine_x();
1,624✔
601
   const BigInt y = get_affine_y();
1,624✔
602

603
   std::vector<uint8_t> result;
1,624✔
604

605
   if(format == EC_Point_Format::Uncompressed)
1,624✔
606
      {
607
      result.resize(1 + 2*p_bytes);
1,406✔
608
      result[0] = 0x04;
1,406✔
609
      BigInt::encode_1363(&result[1], p_bytes, x);
1,406✔
610
      BigInt::encode_1363(&result[1+p_bytes], p_bytes, y);
1,406✔
611
      }
612
   else if(format == EC_Point_Format::Compressed)
218✔
613
      {
614
      result.resize(1 + p_bytes);
126✔
615
      result[0] = 0x02 | static_cast<uint8_t>(y.get_bit(0));
252✔
616
      BigInt::encode_1363(&result[1], p_bytes, x);
126✔
617
      }
618
   else if(format == EC_Point_Format::Hybrid)
92✔
619
      {
620
      result.resize(1 + 2*p_bytes);
92✔
621
      result[0] = 0x06 | static_cast<uint8_t>(y.get_bit(0));
184✔
622
      BigInt::encode_1363(&result[1], p_bytes, x);
92✔
623
      BigInt::encode_1363(&result[1+p_bytes], p_bytes, y);
92✔
624
      }
625
   else
626
      throw Invalid_Argument("EC2OSP illegal point encoding");
×
627

628
   return result;
1,624✔
629
   }
5,034✔
630

631
namespace {
632

633
BigInt decompress_point(bool yMod2,
6,231✔
634
                        const BigInt& x,
635
                        const BigInt& curve_p,
636
                        const BigInt& curve_a,
637
                        const BigInt& curve_b)
638
   {
639
   BigInt xpow3 = x * x * x;
6,231✔
640

641
   BigInt g = curve_a * x;
6,231✔
642
   g += xpow3;
6,231✔
643
   g += curve_b;
6,231✔
644
   g = g % curve_p;
6,231✔
645

646
   BigInt z = sqrt_modulo_prime(g, curve_p);
6,231✔
647

648
   if(z < 0)
6,231✔
649
      throw Decoding_Error("Error during EC point decompression");
2,376✔
650

651
   if(z.get_bit(0) != yMod2)
7,710✔
652
      z = curve_p - z;
3,956✔
653

654
   return z;
3,855✔
655
   }
12,452✔
656

657
}
658

659
EC_Point OS2ECP(const uint8_t data[], size_t data_len,
9,701✔
660
                const CurveGFp& curve)
661
   {
662
   // Should we really be doing this?
663
   if(data_len <= 1)
9,701✔
664
      return EC_Point(curve); // return zero
173✔
665

666
   std::pair<BigInt, BigInt> xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b());
9,528✔
667

668
   EC_Point point(curve, xy.first, xy.second);
6,954✔
669

670
   if(!point.on_the_curve())
6,368✔
671
      throw Decoding_Error("OS2ECP: Decoded point was not on the curve");
200✔
672

673
   return point;
6,168✔
674
   }
7,154✔
675

676
std::pair<BigInt, BigInt> OS2ECP(const uint8_t data[], size_t data_len,
9,560✔
677
                                 const BigInt& curve_p,
678
                                 const BigInt& curve_a,
679
                                 const BigInt& curve_b)
680
   {
681
   if(data_len <= 1)
9,560✔
682
      throw Decoding_Error("OS2ECP invalid point");
×
683

684
   const uint8_t pc = data[0];
9,560✔
685

686
   BigInt x, y;
9,560✔
687

688
   if(pc == 2 || pc == 3)
9,560✔
689
      {
690
      //compressed form
691
      x = BigInt::decode(&data[1], data_len - 1);
5,748✔
692

693
      const bool y_mod_2 = ((pc & 0x01) == 1);
5,748✔
694
      y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b);
5,748✔
695
      }
696
   else if(pc == 4)
3,812✔
697
      {
698
      const size_t l = (data_len - 1) / 2;
3,308✔
699

700
      // uncompressed form
701
      x = BigInt::decode(&data[1], l);
3,308✔
702
      y = BigInt::decode(&data[l+1], l);
3,308✔
703
      }
704
   else if(pc == 6 || pc == 7)
504✔
705
      {
706
      const size_t l = (data_len - 1) / 2;
483✔
707

708
      // hybrid form
709
      x = BigInt::decode(&data[1], l);
483✔
710
      y = BigInt::decode(&data[l+1], l);
483✔
711

712
      const bool y_mod_2 = ((pc & 0x01) == 1);
483✔
713

714
      if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y)
3,702✔
715
         throw Decoding_Error("OS2ECP: Decoding error in hybrid format");
177✔
716
      }
717
   else
718
      throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc));
42✔
719

720
   return std::make_pair(x, y);
6,986✔
721
   }
16,538✔
722

723
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc