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

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

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

96.23
/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) : m_curve(curve), m_coord_x(0), m_coord_y(curve.get_1_rep()), m_coord_z(0) {
24,432✔
19
   // Assumes Montgomery rep of zero is zero
20
}
24,432✔
21

22
EC_Point::EC_Point(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
20,545✔
23
      m_curve(curve), m_coord_x(x), m_coord_y(y), m_coord_z(m_curve.get_1_rep()) {
20,545✔
24
   if(x < 0 || x >= curve.get_p())
41,090✔
25
      throw Invalid_Argument("Invalid EC_Point affine x");
558✔
26
   if(y < 0 || y >= curve.get_p())
39,828✔
27
      throw Invalid_Argument("Invalid EC_Point affine y");
214✔
28

29
   secure_vector<word> monty_ws(m_curve.get_ws_size());
19,773✔
30
   m_curve.to_rep(m_coord_x, monty_ws);
19,773✔
31
   m_curve.to_rep(m_coord_y, monty_ws);
19,773✔
32
}
22,855✔
33

34
void EC_Point::randomize_repr(RandomNumberGenerator& rng) {
749✔
35
   secure_vector<word> ws(m_curve.get_ws_size());
749✔
36
   randomize_repr(rng, ws);
749✔
37
}
749✔
38

39
void EC_Point::randomize_repr(RandomNumberGenerator& rng, secure_vector<word>& ws) {
6,411✔
40
   const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p());
6,411✔
41

42
   /*
43
   * No reason to convert this to Montgomery representation first,
44
   * just pretend the random mask was chosen as Redc(mask) and the
45
   * random mask we generated above is in the Montgomery
46
   * representation.
47
   * //m_curve.to_rep(mask, ws);
48
   */
49
   const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws);
6,411✔
50
   const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws);
6,411✔
51

52
   m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws);
6,411✔
53
   m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws);
6,411✔
54
   m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws);
12,822✔
55
}
19,233✔
56

57
namespace {
58

59
inline void resize_ws(std::vector<BigInt>& ws_bn, size_t cap_size) {
9,765,878✔
60
   BOTAN_ASSERT(ws_bn.size() >= EC_Point::WORKSPACE_SIZE, "Expected size for EC_Point workspace");
9,765,878✔
61

62
   for(auto& ws : ws_bn)
87,892,902✔
63
      if(ws.size() < cap_size)
78,127,024✔
64
         ws.get_word_vector().resize(cap_size);
1,488,967✔
65
}
9,765,878✔
66

67
}
68

69
void EC_Point::add_affine(
2,284,868✔
70
   const word x_words[], size_t x_size, const word y_words[], size_t y_size, std::vector<BigInt>& ws_bn) {
71
   if((CT::all_zeros(x_words, x_size) & CT::all_zeros(y_words, y_size)).is_set()) {
17,087,931✔
72
      return;
73
   }
74

75
   if(is_zero()) {
4,459,182✔
76
      m_coord_x.set_words(x_words, x_size);
15,623✔
77
      m_coord_y.set_words(y_words, y_size);
15,623✔
78
      m_coord_z = m_curve.get_1_rep();
15,623✔
79
      return;
15,623✔
80
   }
81

82
   resize_ws(ws_bn, m_curve.get_ws_size());
2,213,991✔
83

84
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
2,213,991✔
85
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
2,213,991✔
86

87
   BigInt& T0 = ws_bn[2];
2,213,991✔
88
   BigInt& T1 = ws_bn[3];
2,213,991✔
89
   BigInt& T2 = ws_bn[4];
2,213,991✔
90
   BigInt& T3 = ws_bn[5];
2,213,991✔
91
   BigInt& T4 = ws_bn[6];
2,213,991✔
92

93
   /*
94
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
95
   simplified with Z2 = 1
96
   */
97

98
   const BigInt& p = m_curve.get_p();
2,213,991✔
99

100
   m_curve.sqr(T3, m_coord_z, ws);            // z1^2
2,213,991✔
101
   m_curve.mul(T4, x_words, x_size, T3, ws);  // x2*z1^2
2,213,991✔
102

103
   m_curve.mul(T2, m_coord_z, T3, ws);        // z1^3
2,213,991✔
104
   m_curve.mul(T0, y_words, y_size, T2, ws);  // y2*z1^3
2,213,991✔
105

106
   T4.mod_sub(m_coord_x, p, sub_ws);  // x2*z1^2 - x1*z2^2
2,213,991✔
107

108
   T0.mod_sub(m_coord_y, p, sub_ws);
2,213,991✔
109

110
   if(T4.is_zero()) {
4,427,982✔
111
      if(T0.is_zero()) {
316✔
112
         mult2(ws_bn);
19✔
113
         return;
19✔
114
      }
115

116
      // setting to zero:
117
      m_coord_x.clear();
139✔
118
      m_coord_y = m_curve.get_1_rep();
139✔
119
      m_coord_z.clear();
139✔
120
      return;
139✔
121
   }
122

123
   m_curve.sqr(T2, T4, ws);
2,213,833✔
124

125
   m_curve.mul(T3, m_coord_x, T2, ws);
2,213,833✔
126

127
   m_curve.mul(T1, T2, T4, ws);
2,213,833✔
128

129
   m_curve.sqr(m_coord_x, T0, ws);
2,213,833✔
130
   m_coord_x.mod_sub(T1, p, sub_ws);
2,213,833✔
131

132
   m_coord_x.mod_sub(T3, p, sub_ws);
2,213,833✔
133
   m_coord_x.mod_sub(T3, p, sub_ws);
2,213,833✔
134

135
   T3.mod_sub(m_coord_x, p, sub_ws);
2,213,833✔
136

137
   m_curve.mul(T2, T0, T3, ws);
2,213,833✔
138
   m_curve.mul(T0, m_coord_y, T1, ws);
2,213,833✔
139
   T2.mod_sub(T0, p, sub_ws);
2,213,833✔
140
   m_coord_y.swap(T2);
2,213,833✔
141

142
   m_curve.mul(T0, m_coord_z, T4, ws);
2,213,833✔
143
   m_coord_z.swap(T0);
2,213,833✔
144
}
145

146
void EC_Point::add(const word x_words[],
1,476,041✔
147
                   size_t x_size,
148
                   const word y_words[],
149
                   size_t y_size,
150
                   const word z_words[],
151
                   size_t z_size,
152
                   std::vector<BigInt>& ws_bn) {
153
   if((CT::all_zeros(x_words, x_size) & CT::all_zeros(z_words, z_size)).is_set())
10,998,942✔
154
      return;
155

156
   if(is_zero()) {
2,874,823✔
157
      m_coord_x.set_words(x_words, x_size);
5,817✔
158
      m_coord_y.set_words(y_words, y_size);
5,817✔
159
      m_coord_z.set_words(z_words, z_size);
5,817✔
160
      return;
5,817✔
161
   }
162

163
   resize_ws(ws_bn, m_curve.get_ws_size());
1,446,688✔
164

165
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
1,446,688✔
166
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
1,446,688✔
167

168
   BigInt& T0 = ws_bn[2];
1,446,688✔
169
   BigInt& T1 = ws_bn[3];
1,446,688✔
170
   BigInt& T2 = ws_bn[4];
1,446,688✔
171
   BigInt& T3 = ws_bn[5];
1,446,688✔
172
   BigInt& T4 = ws_bn[6];
1,446,688✔
173
   BigInt& T5 = ws_bn[7];
1,446,688✔
174

175
   /*
176
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
177
   */
178

179
   const BigInt& p = m_curve.get_p();
1,446,688✔
180

181
   m_curve.sqr(T0, z_words, z_size, ws);      // z2^2
1,446,688✔
182
   m_curve.mul(T1, m_coord_x, T0, ws);        // x1*z2^2
1,446,688✔
183
   m_curve.mul(T3, z_words, z_size, T0, ws);  // z2^3
1,446,688✔
184
   m_curve.mul(T2, m_coord_y, T3, ws);        // y1*z2^3
1,446,688✔
185

186
   m_curve.sqr(T3, m_coord_z, ws);            // z1^2
1,446,688✔
187
   m_curve.mul(T4, x_words, x_size, T3, ws);  // x2*z1^2
1,446,688✔
188

189
   m_curve.mul(T5, m_coord_z, T3, ws);        // z1^3
1,446,688✔
190
   m_curve.mul(T0, y_words, y_size, T5, ws);  // y2*z1^3
1,446,688✔
191

192
   T4.mod_sub(T1, p, sub_ws);  // x2*z1^2 - x1*z2^2
1,446,688✔
193

194
   T0.mod_sub(T2, p, sub_ws);
1,446,688✔
195

196
   if(T4.is_zero()) {
2,893,376✔
197
      if(T0.is_zero()) {
974✔
198
         mult2(ws_bn);
151✔
199
         return;
151✔
200
      }
201

202
      // setting to zero:
203
      m_coord_x.clear();
336✔
204
      m_coord_y = m_curve.get_1_rep();
336✔
205
      m_coord_z.clear();
336✔
206
      return;
336✔
207
   }
208

209
   m_curve.sqr(T5, T4, ws);
1,446,201✔
210

211
   m_curve.mul(T3, T1, T5, ws);
1,446,201✔
212

213
   m_curve.mul(T1, T5, T4, ws);
1,446,201✔
214

215
   m_curve.sqr(m_coord_x, T0, ws);
1,446,201✔
216
   m_coord_x.mod_sub(T1, p, sub_ws);
1,446,201✔
217
   m_coord_x.mod_sub(T3, p, sub_ws);
1,446,201✔
218
   m_coord_x.mod_sub(T3, p, sub_ws);
1,446,201✔
219

220
   T3.mod_sub(m_coord_x, p, sub_ws);
1,446,201✔
221

222
   m_curve.mul(m_coord_y, T0, T3, ws);
1,446,201✔
223
   m_curve.mul(T3, T2, T1, ws);
1,446,201✔
224

225
   m_coord_y.mod_sub(T3, p, sub_ws);
1,446,201✔
226

227
   m_curve.mul(T3, z_words, z_size, m_coord_z, ws);
1,446,201✔
228
   m_curve.mul(m_coord_z, T3, T4, ws);
1,446,201✔
229
}
230

231
void EC_Point::mult2i(size_t iterations, std::vector<BigInt>& ws_bn) {
2,279,011✔
232
   if(iterations == 0)
2,279,011✔
233
      return;
234

235
   if(m_coord_y.is_zero()) {
4,555,196✔
236
      *this = EC_Point(m_curve);  // setting myself to zero
×
237
      return;
×
238
   }
239

240
   /*
241
   TODO we can save 2 squarings per iteration by computing
242
   a*Z^4 using values cached from previous iteration
243
   */
244
   for(size_t i = 0; i != iterations; ++i)
7,458,723✔
245
      mult2(ws_bn);
5,179,712✔
246
}
247

248
// *this *= 2
249
void EC_Point::mult2(std::vector<BigInt>& ws_bn) {
6,111,354✔
250
   if(is_zero())
12,189,464✔
251
      return;
252

253
   if(m_coord_y.is_zero()) {
9,934,242✔
254
      *this = EC_Point(m_curve);  // setting myself to zero
×
255
      return;
×
256
   }
257

258
   resize_ws(ws_bn, m_curve.get_ws_size());
6,105,199✔
259

260
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
6,105,199✔
261
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
6,105,199✔
262

263
   BigInt& T0 = ws_bn[2];
6,105,199✔
264
   BigInt& T1 = ws_bn[3];
6,105,199✔
265
   BigInt& T2 = ws_bn[4];
6,105,199✔
266
   BigInt& T3 = ws_bn[5];
6,105,199✔
267
   BigInt& T4 = ws_bn[6];
6,105,199✔
268

269
   /*
270
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc
271
   */
272
   const BigInt& p = m_curve.get_p();
6,105,199✔
273

274
   m_curve.sqr(T0, m_coord_y, ws);
6,105,199✔
275

276
   m_curve.mul(T1, m_coord_x, T0, ws);
6,105,199✔
277
   T1.mod_mul(4, p, sub_ws);
6,105,199✔
278

279
   if(m_curve.a_is_zero()) {
6,105,199✔
280
      // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2
281
      m_curve.sqr(T4, m_coord_x, ws);  // x^2
268,490✔
282
      T4.mod_mul(3, p, sub_ws);        // 3*x^2
268,490✔
283
   } else if(m_curve.a_is_minus_3()) {
5,836,709✔
284
      /*
285
      if a == -3 then
286
        3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2)
287
      */
288
      m_curve.sqr(T3, m_coord_z, ws);  // z^2
4,627,918✔
289

290
      // (x-z^2)
291
      T2 = m_coord_x;
4,627,918✔
292
      T2.mod_sub(T3, p, sub_ws);
4,627,918✔
293

294
      // (x+z^2)
295
      T3.mod_add(m_coord_x, p, sub_ws);
4,627,918✔
296

297
      m_curve.mul(T4, T2, T3, ws);  // (x-z^2)*(x+z^2)
4,627,918✔
298

299
      T4.mod_mul(3, p, sub_ws);  // 3*(x-z^2)*(x+z^2)
4,627,918✔
300
   } else {
301
      m_curve.sqr(T3, m_coord_z, ws);                // z^2
1,208,791✔
302
      m_curve.sqr(T4, T3, ws);                       // z^4
1,208,791✔
303
      m_curve.mul(T3, m_curve.get_a_rep(), T4, ws);  // a*z^4
1,208,791✔
304

305
      m_curve.sqr(T4, m_coord_x, ws);  // x^2
1,208,791✔
306
      T4.mod_mul(3, p, sub_ws);
1,208,791✔
307
      T4.mod_add(T3, p, sub_ws);  // 3*x^2 + a*z^4
1,208,791✔
308
   }
309

310
   m_curve.sqr(T2, T4, ws);
6,105,199✔
311
   T2.mod_sub(T1, p, sub_ws);
6,105,199✔
312
   T2.mod_sub(T1, p, sub_ws);
6,105,199✔
313

314
   m_curve.sqr(T3, T0, ws);
6,105,199✔
315
   T3.mod_mul(8, p, sub_ws);
6,105,199✔
316

317
   T1.mod_sub(T2, p, sub_ws);
6,105,199✔
318

319
   m_curve.mul(T0, T4, T1, ws);
6,105,199✔
320
   T0.mod_sub(T3, p, sub_ws);
6,105,199✔
321

322
   m_coord_x.swap(T2);
6,105,199✔
323

324
   m_curve.mul(T2, m_coord_y, m_coord_z, ws);
6,105,199✔
325
   T2.mod_mul(2, p, sub_ws);
6,105,199✔
326

327
   m_coord_y.swap(T0);
6,105,199✔
328
   m_coord_z.swap(T2);
6,111,354✔
329
}
330

331
// arithmetic operators
332
EC_Point& EC_Point::operator+=(const EC_Point& rhs) {
2,376✔
333
   std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
2,376✔
334
   add(rhs, ws);
2,376✔
335
   return *this;
2,375✔
336
}
2,376✔
337

338
EC_Point& EC_Point::operator-=(const EC_Point& rhs) {
82✔
339
   EC_Point minus_rhs = EC_Point(rhs).negate();
82✔
340

341
   if(is_zero())
82✔
342
      *this = minus_rhs;
×
343
   else
344
      *this += minus_rhs;
82✔
345

346
   return *this;
82✔
347
}
82✔
348

349
EC_Point& EC_Point::operator*=(const BigInt& scalar) {
67✔
350
   *this = scalar * *this;
67✔
351
   return *this;
67✔
352
}
353

354
EC_Point operator*(const BigInt& scalar, const EC_Point& point) {
2,956✔
355
   BOTAN_DEBUG_ASSERT(point.on_the_curve());
2,956✔
356

357
   const size_t scalar_bits = scalar.bits();
2,956✔
358

359
   std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
2,956✔
360

361
   EC_Point R[2] = {point.zero(), point};
8,868✔
362

363
   for(size_t i = scalar_bits; i > 0; i--) {
503,055✔
364
      const size_t b = scalar.get_bit(i - 1);
500,099✔
365
      R[b ^ 1].add(R[b], ws);
500,099✔
366
      R[b].mult2(ws);
500,099✔
367
   }
368

369
   if(scalar.is_negative())
2,956✔
370
      R[0].negate();
×
371

372
   BOTAN_DEBUG_ASSERT(R[0].on_the_curve());
2,956✔
373

374
   return R[0];
5,912✔
375
}
11,824✔
376

377
//static
378
void EC_Point::force_all_affine(std::vector<EC_Point>& points, secure_vector<word>& ws) {
10,824✔
379
   if(points.size() <= 1) {
10,824✔
380
      for(auto& point : points)
×
381
         point.force_affine();
×
382
      return;
×
383
   }
384

385
   for(auto& point : points) {
1,072,545✔
386
      if(point.is_zero())
1,973,838✔
387
         throw Invalid_State("Cannot convert zero ECC point to affine");
×
388
   }
389

390
   /*
391
   For >= 2 points use Montgomery's trick
392

393
   See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography"
394
   (Hankerson, Menezes, Vanstone)
395

396
   TODO is it really necessary to save all k points in c?
397
   */
398

399
   const CurveGFp& curve = points[0].m_curve;
10,824✔
400
   const BigInt& rep_1 = curve.get_1_rep();
10,824✔
401

402
   if(ws.size() < curve.get_ws_size())
10,824✔
403
      ws.resize(curve.get_ws_size());
×
404

405
   std::vector<BigInt> c(points.size());
10,824✔
406
   c[0] = points[0].m_coord_z;
10,824✔
407

408
   for(size_t i = 1; i != points.size(); ++i) {
1,061,721✔
409
      curve.mul(c[i], c[i - 1], points[i].m_coord_z, ws);
2,101,794✔
410
   }
411

412
   BigInt s_inv = curve.invert_element(c[c.size() - 1], ws);
10,824✔
413

414
   BigInt z_inv, z2_inv, z3_inv;
10,824✔
415

416
   for(size_t i = points.size() - 1; i != 0; i--) {
1,061,721✔
417
      EC_Point& point = points[i];
1,050,897✔
418

419
      curve.mul(z_inv, s_inv, c[i - 1], ws);
1,050,897✔
420

421
      s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws);
1,050,897✔
422

423
      curve.sqr(z2_inv, z_inv, ws);
1,050,897✔
424
      curve.mul(z3_inv, z2_inv, z_inv, ws);
1,050,897✔
425
      point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws);
2,101,794✔
426
      point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws);
2,101,794✔
427
      point.m_coord_z = rep_1;
1,050,897✔
428
   }
429

430
   curve.sqr(z2_inv, s_inv, ws);
10,824✔
431
   curve.mul(z3_inv, z2_inv, s_inv, ws);
10,824✔
432
   points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws);
21,648✔
433
   points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws);
21,648✔
434
   points[0].m_coord_z = rep_1;
10,824✔
435
}
43,296✔
436

437
void EC_Point::force_affine() {
1,377✔
438
   if(is_zero())
1,377✔
439
      throw Invalid_State("Cannot convert zero ECC point to affine");
×
440

441
   secure_vector<word> ws;
1,377✔
442

443
   const BigInt z_inv = m_curve.invert_element(m_coord_z, ws);
1,377✔
444
   const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws);
1,377✔
445
   const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws);
1,377✔
446
   m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws);
1,377✔
447
   m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws);
1,377✔
448
   m_coord_z = m_curve.get_1_rep();
1,377✔
449
}
5,508✔
450

451
bool EC_Point::is_affine() const { return m_curve.is_one(m_coord_z); }
40,935✔
452

453
BigInt EC_Point::get_affine_x() const {
27,436✔
454
   if(is_zero())
30,659✔
455
      throw Invalid_State("Cannot convert zero point to affine");
27✔
456

457
   secure_vector<word> monty_ws;
27,409✔
458

459
   if(is_affine())
27,409✔
460
      return m_curve.from_rep_to_tmp(m_coord_x, monty_ws);
2,365✔
461

462
   BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
25,044✔
463
   z2 = m_curve.invert_element(z2, monty_ws);
25,044✔
464

465
   BigInt r;
25,044✔
466
   m_curve.mul(r, m_coord_x, z2, monty_ws);
25,044✔
467
   m_curve.from_rep(r, monty_ws);
25,044✔
468
   return r;
25,044✔
469
}
79,022✔
470

471
BigInt EC_Point::get_affine_y() const {
13,553✔
472
   if(is_zero())
13,553✔
473
      throw Invalid_State("Cannot convert zero point to affine");
27✔
474

475
   secure_vector<word> monty_ws;
13,526✔
476

477
   if(is_affine())
13,526✔
478
      return m_curve.from_rep_to_tmp(m_coord_y, monty_ws);
2,358✔
479

480
   const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
11,168✔
481
   const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
11,168✔
482
   const BigInt z3_inv = m_curve.invert_element(z3, monty_ws);
11,168✔
483

484
   BigInt r;
11,168✔
485
   m_curve.mul(r, m_coord_y, z3_inv, monty_ws);
11,168✔
486
   m_curve.from_rep(r, monty_ws);
11,168✔
487
   return r;
11,168✔
488
}
59,718✔
489

490
bool EC_Point::on_the_curve() const {
29,549✔
491
   /*
492
   Is the point still on the curve?? (If everything is correct, the
493
   point is always on its curve; then the function will return true.
494
   If somehow the state is corrupted, which suggests a fault attack
495
   (or internal computational error), then return false.
496
   */
497
   if(is_zero())
41,480✔
498
      return true;
499

500
   secure_vector<word> monty_ws;
29,487✔
501

502
   const BigInt y2 = m_curve.from_rep_to_tmp(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws);
29,487✔
503
   const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws);
29,487✔
504
   const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws);
29,487✔
505
   const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws);
29,487✔
506

507
   if(m_coord_z == z2)  // Is z equal to 1 (in Montgomery form)?
29,487✔
508
   {
509
      if(y2 != m_curve.from_rep_to_tmp(x3 + ax + m_curve.get_b_rep(), monty_ws))
132,380✔
510
         return false;
511
   }
512

513
   const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws);
29,220✔
514
   const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws);
29,220✔
515
   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,220✔
516

517
   if(y2 != m_curve.from_rep_to_tmp(x3 + ax_z4 + b_z6, monty_ws))
146,100✔
518
      return false;
49✔
519

520
   return true;
521
}
235,424✔
522

523
// swaps the states of *this and other, does not throw!
524
void EC_Point::swap(EC_Point& other) {
934,709✔
525
   m_curve.swap(other.m_curve);
934,709✔
526
   m_coord_x.swap(other.m_coord_x);
934,709✔
527
   m_coord_y.swap(other.m_coord_y);
934,709✔
528
   m_coord_z.swap(other.m_coord_z);
934,709✔
529
}
934,709✔
530

531
bool EC_Point::operator==(const EC_Point& other) const {
5,333✔
532
   if(m_curve != other.m_curve)
5,333✔
533
      return false;
534

535
   // If this is zero, only equal if other is also zero
536
   if(is_zero())
8,121✔
537
      return other.is_zero();
202✔
538

539
   return (get_affine_x() == other.get_affine_x() && get_affine_y() == other.get_affine_y());
25,687✔
540
}
541

542
// encoding and decoding
543
std::vector<uint8_t> EC_Point::encode(EC_Point_Format format) const {
1,856✔
544
   if(is_zero())
1,936✔
545
      return std::vector<uint8_t>(1);  // single 0 byte
162✔
546

547
   const size_t p_bytes = m_curve.get_p().bytes();
1,694✔
548

549
   const BigInt x = get_affine_x();
1,694✔
550
   const BigInt y = get_affine_y();
1,694✔
551

552
   std::vector<uint8_t> result;
1,694✔
553

554
   if(format == EC_Point_Format::Uncompressed) {
1,694✔
555
      result.resize(1 + 2 * p_bytes);
1,476✔
556
      result[0] = 0x04;
1,476✔
557
      BigInt::encode_1363(&result[1], p_bytes, x);
1,476✔
558
      BigInt::encode_1363(&result[1 + p_bytes], p_bytes, y);
1,476✔
559
   } else if(format == EC_Point_Format::Compressed) {
218✔
560
      result.resize(1 + p_bytes);
126✔
561
      result[0] = 0x02 | static_cast<uint8_t>(y.get_bit(0));
252✔
562
      BigInt::encode_1363(&result[1], p_bytes, x);
126✔
563
   } else if(format == EC_Point_Format::Hybrid) {
92✔
564
      result.resize(1 + 2 * p_bytes);
92✔
565
      result[0] = 0x06 | static_cast<uint8_t>(y.get_bit(0));
184✔
566
      BigInt::encode_1363(&result[1], p_bytes, x);
92✔
567
      BigInt::encode_1363(&result[1 + p_bytes], p_bytes, y);
92✔
568
   } else
569
      throw Invalid_Argument("EC2OSP illegal point encoding");
×
570

571
   return result;
1,694✔
572
}
5,244✔
573

574
namespace {
575

576
BigInt decompress_point(
6,231✔
577
   bool yMod2, const BigInt& x, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) {
578
   BigInt xpow3 = x * x * x;
6,231✔
579

580
   BigInt g = curve_a * x;
6,231✔
581
   g += xpow3;
6,231✔
582
   g += curve_b;
6,231✔
583
   g = g % curve_p;
6,231✔
584

585
   BigInt z = sqrt_modulo_prime(g, curve_p);
6,231✔
586

587
   if(z < 0)
6,231✔
588
      throw Decoding_Error("Error during EC point decompression");
2,376✔
589

590
   if(z.get_bit(0) != yMod2)
7,710✔
591
      z = curve_p - z;
3,956✔
592

593
   return z;
3,855✔
594
}
12,452✔
595

596
}
597

598
EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp& curve) {
9,813✔
599
   // Should we really be doing this?
600
   if(data_len <= 1)
9,813✔
601
      return EC_Point(curve);  // return zero
173✔
602

603
   std::pair<BigInt, BigInt> xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b());
9,640✔
604

605
   EC_Point point(curve, xy.first, xy.second);
7,066✔
606

607
   if(!point.on_the_curve())
6,480✔
608
      throw Decoding_Error("OS2ECP: Decoded point was not on the curve");
200✔
609

610
   return point;
6,280✔
611
}
7,266✔
612

613
std::pair<BigInt, BigInt> OS2ECP(
9,672✔
614
   const uint8_t data[], size_t data_len, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) {
615
   if(data_len <= 1)
9,672✔
616
      throw Decoding_Error("OS2ECP invalid point");
×
617

618
   const uint8_t pc = data[0];
9,672✔
619

620
   BigInt x, y;
9,672✔
621

622
   if(pc == 2 || pc == 3) {
9,672✔
623
      //compressed form
624
      x = BigInt::decode(&data[1], data_len - 1);
5,748✔
625

626
      const bool y_mod_2 = ((pc & 0x01) == 1);
5,748✔
627
      y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b);
5,748✔
628
   } else if(pc == 4) {
3,924✔
629
      const size_t l = (data_len - 1) / 2;
3,420✔
630

631
      // uncompressed form
632
      x = BigInt::decode(&data[1], l);
3,420✔
633
      y = BigInt::decode(&data[l + 1], l);
3,420✔
634
   } else if(pc == 6 || pc == 7) {
504✔
635
      const size_t l = (data_len - 1) / 2;
483✔
636

637
      // hybrid form
638
      x = BigInt::decode(&data[1], l);
483✔
639
      y = BigInt::decode(&data[l + 1], l);
483✔
640

641
      const bool y_mod_2 = ((pc & 0x01) == 1);
483✔
642

643
      if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y)
3,702✔
644
         throw Decoding_Error("OS2ECP: Decoding error in hybrid format");
177✔
645
   } else
646
      throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc));
42✔
647

648
   return std::make_pair(x, y);
7,098✔
649
}
16,762✔
650

651
}
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