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

randombit / botan / 11972552403

22 Nov 2024 12:26PM UTC coverage: 91.244% (+0.004%) from 91.24%
11972552403

push

github

web-flow
Merge pull request #4436 from randombit/jack/cleanup-curvegfp

Cleanups relating to CurveGFp

93250 of 102198 relevant lines covered (91.24%)

11237819.31 hits per line

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

92.47
/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,2024 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/reducer.h>
14
#include <botan/rng.h>
15
#include <botan/internal/ct_utils.h>
16
#include <botan/internal/ec_inner_data.h>
17
#include <botan/internal/monty.h>
18
#include <botan/internal/mp_core.h>
19
#include <botan/internal/stl_util.h>
20

21
namespace Botan {
22

23
// The main reason CurveGFp has not been entirely removed already is
24
// because a few (deprecated) public APIs of EC_Point rely on them,
25
// thus until Botan4 we must continue to access the EC data via a type
26
// named CurveGFp
27

28
CurveGFp::CurveGFp(const EC_Group_Data* group) : m_group(group) {
1,169✔
29
   BOTAN_ASSERT_NONNULL(m_group);
1,169✔
30
}
1,169✔
31

32
const BigInt& CurveGFp::get_a() const {
7,411✔
33
   return this->group().a();
7,411✔
34
}
35

36
const BigInt& CurveGFp::get_b() const {
7,411✔
37
   return this->group().b();
7,411✔
38
}
39

40
const BigInt& CurveGFp::get_p() const {
7,496✔
41
   return this->group().p();
7,496✔
42
}
43

44
size_t CurveGFp::get_p_words() const {
1,511,829✔
45
   return this->group().p_words();
1,511,829✔
46
}
47

48
namespace {
49

50
void to_rep(const EC_Group_Data& group, BigInt& x, secure_vector<word>& ws) {
93,122✔
51
   group.monty().mul_by(x, group.monty().R2(), ws);
93,122✔
52
}
93,122✔
53

54
void from_rep(const EC_Group_Data& group, BigInt& z, secure_vector<word>& ws) {
18,285✔
55
   group.monty().redc_in_place(z, ws);
18,285✔
56
}
18,285✔
57

58
BigInt from_rep_to_tmp(const EC_Group_Data& group, const BigInt& x, secure_vector<word>& ws) {
138,457✔
59
   return group.monty().redc(x, ws);
27,068✔
60
}
61

62
void fe_mul(const EC_Group_Data& group, BigInt& z, const BigInt& x, const BigInt& y, secure_vector<word>& ws) {
31,447,967✔
63
   group.monty().mul(z, x, y, ws);
1,470,721✔
64
}
1,913,387✔
65

66
void fe_mul(
7,268,968✔
67
   const EC_Group_Data& group, BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector<word>& ws) {
68
   group.monty().mul(z, y, std::span{x_w, x_size}, ws);
14,537,936✔
69
}
70

71
BigInt fe_mul(const EC_Group_Data& group, const BigInt& x, const BigInt& y, secure_vector<word>& ws) {
1,068,639✔
72
   return group.monty().mul(x, y, ws);
16,767✔
73
}
74

75
void fe_sqr(const EC_Group_Data& group, BigInt& z, const BigInt& x, secure_vector<word>& ws) {
24,043,075✔
76
   group.monty().sqr(z, x, ws);
5,343✔
77
}
208,281✔
78

79
void fe_sqr(const EC_Group_Data& group, BigInt& z, const word x_w[], size_t x_size, secure_vector<word>& ws) {
1,283,820✔
80
   group.monty().sqr(z, std::span{x_w, x_size}, ws);
2,567,640✔
81
}
82

83
BigInt fe_sqr(const EC_Group_Data& group, const BigInt& x, secure_vector<word>& ws) {
196,896✔
84
   return group.monty().sqr(x, ws);
196,896✔
85
}
86

87
BigInt invert_element(const EC_Group_Data& group, const BigInt& x, secure_vector<word>& ws) {
30,071✔
88
   return group.monty().inv_mod_p(x, ws);
1,303✔
89
}
90

91
size_t monty_ws_size(const EC_Group_Data& group) {
6,132,833✔
92
   return 2 * group.p_words();
1,303✔
93
}
94

95
}  // namespace
96

97
EC_Point::EC_Point(const CurveGFp& curve) : m_curve(curve), m_x(0), m_y(curve.group().monty().R1()), m_z(0) {}
23,293✔
98

99
EC_Point EC_Point::zero() const {
18,396✔
100
   return EC_Point(m_curve);
18,396✔
101
}
102

103
EC_Point::EC_Point(const CurveGFp& curve, BigInt x, BigInt y) :
43,886✔
104
      m_curve(curve), m_x(std::move(x)), m_y(std::move(y)), m_z(m_curve.group().monty().R1()) {
43,886✔
105
   const auto& group = m_curve.group();
43,886✔
106

107
   if(m_x < 0 || m_x >= group.p()) {
43,886✔
108
      throw Invalid_Argument("Invalid EC_Point affine x");
×
109
   }
110
   if(m_y < 0 || m_y >= group.p()) {
43,886✔
111
      throw Invalid_Argument("Invalid EC_Point affine y");
×
112
   }
113

114
   secure_vector<word> monty_ws(monty_ws_size(group));
43,886✔
115

116
   to_rep(group, m_x, monty_ws);
43,886✔
117
   to_rep(group, m_y, monty_ws);
87,772✔
118
}
43,886✔
119

120
void EC_Point::randomize_repr(RandomNumberGenerator& rng) {
74,824✔
121
   const auto& group = m_curve.group();
74,824✔
122
   secure_vector<word> ws(monty_ws_size(group));
74,824✔
123
   randomize_repr(rng, ws);
74,824✔
124
}
74,824✔
125

126
void EC_Point::randomize_repr(RandomNumberGenerator& rng, secure_vector<word>& ws) {
84,429✔
127
   const auto& group = m_curve.group();
84,429✔
128

129
   const BigInt mask = BigInt::random_integer(rng, 2, group.p());
84,429✔
130

131
   /*
132
   * No reason to convert this to Montgomery representation first,
133
   * just pretend the random mask was chosen as Redc(mask) and the
134
   * random mask we generated above is in the Montgomery
135
   * representation.
136
   */
137

138
   const BigInt mask2 = fe_sqr(group, mask, ws);
84,429✔
139
   const BigInt mask3 = fe_mul(group, mask2, mask, ws);
84,429✔
140

141
   m_x = fe_mul(group, m_x, mask2, ws);
84,429✔
142
   m_y = fe_mul(group, m_y, mask3, ws);
84,429✔
143
   m_z = fe_mul(group, m_z, mask, ws);
168,858✔
144
}
253,287✔
145

146
namespace {
147

148
inline void resize_ws(std::vector<BigInt>& ws_bn, size_t cap_size) {
6,012,820✔
149
   BOTAN_ASSERT(ws_bn.size() >= EC_Point::WORKSPACE_SIZE, "Expected size for EC_Point workspace");
6,012,820✔
150

151
   for(auto& ws : ws_bn) {
54,115,380✔
152
      if(ws.size() < cap_size) {
48,102,560✔
153
         ws.get_word_vector().resize(cap_size);
1,231,381✔
154
      }
155
   }
156
}
6,012,820✔
157

158
}  // namespace
159

160
void EC_Point::add_affine(
1,147,322✔
161
   const word x_words[], size_t x_size, const word y_words[], size_t y_size, std::vector<BigInt>& ws_bn) {
162
   if((CT::all_zeros(x_words, x_size) & CT::all_zeros(y_words, y_size)).as_bool()) {
3,441,966✔
163
      return;
164
   }
165

166
   const auto& group = m_curve.group();
1,077,278✔
167

168
   if(is_zero()) {
2,154,544✔
169
      m_x.set_words(x_words, x_size);
10,296✔
170
      m_y.set_words(y_words, y_size);
10,296✔
171
      m_z = group.monty().R1();
10,296✔
172
      return;
10,296✔
173
   }
174

175
   resize_ws(ws_bn, monty_ws_size(group));
1,066,982✔
176

177
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
1,066,982✔
178
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
1,066,982✔
179

180
   BigInt& T0 = ws_bn[2];
1,066,982✔
181
   BigInt& T1 = ws_bn[3];
1,066,982✔
182
   BigInt& T2 = ws_bn[4];
1,066,982✔
183
   BigInt& T3 = ws_bn[5];
1,066,982✔
184
   BigInt& T4 = ws_bn[6];
1,066,982✔
185

186
   /*
187
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
188
   simplified with Z2 = 1
189
   */
190

191
   const BigInt& p = group.p();
1,066,982✔
192

193
   fe_sqr(group, T3, m_z, ws);                  // z1^2
1,066,982✔
194
   fe_mul(group, T4, x_words, x_size, T3, ws);  // x2*z1^2
1,066,982✔
195

196
   fe_mul(group, T2, m_z, T3, ws);              // z1^3
1,066,982✔
197
   fe_mul(group, T0, y_words, y_size, T2, ws);  // y2*z1^3
1,066,982✔
198

199
   T4.mod_sub(m_x, p, sub_ws);  // x2*z1^2 - x1*z2^2
1,066,982✔
200

201
   T0.mod_sub(m_y, p, sub_ws);
1,066,982✔
202

203
   if(T4.is_zero()) {
2,133,964✔
204
      if(T0.is_zero()) {
34✔
205
         mult2(ws_bn);
2✔
206
         return;
2✔
207
      }
208

209
      // setting to zero:
210
      m_x.clear();
15✔
211
      m_y = group.monty().R1();
15✔
212
      m_z.clear();
15✔
213
      return;
15✔
214
   }
215

216
   fe_sqr(group, T2, T4, ws);
1,066,965✔
217

218
   fe_mul(group, T3, m_x, T2, ws);
1,066,965✔
219

220
   fe_mul(group, T1, T2, T4, ws);
1,066,965✔
221

222
   fe_sqr(group, m_x, T0, ws);
1,066,965✔
223
   m_x.mod_sub(T1, p, sub_ws);
1,066,965✔
224

225
   m_x.mod_sub(T3, p, sub_ws);
1,066,965✔
226
   m_x.mod_sub(T3, p, sub_ws);
1,066,965✔
227

228
   T3.mod_sub(m_x, p, sub_ws);
1,066,965✔
229

230
   fe_mul(group, T2, T0, T3, ws);
1,066,965✔
231
   fe_mul(group, T0, m_y, T1, ws);
1,066,965✔
232
   T2.mod_sub(T0, p, sub_ws);
1,066,965✔
233
   m_y.swap(T2);
1,066,965✔
234

235
   fe_mul(group, T0, m_z, T4, ws);
1,066,965✔
236
   m_z.swap(T0);
1,066,965✔
237
}
238

239
void EC_Point::add(const word x_words[],
1,316,742✔
240
                   size_t x_size,
241
                   const word y_words[],
242
                   size_t y_size,
243
                   const word z_words[],
244
                   size_t z_size,
245
                   std::vector<BigInt>& ws_bn) {
246
   if((CT::all_zeros(x_words, x_size) & CT::all_zeros(z_words, z_size)).as_bool()) {
3,950,226✔
247
      return;
248
   }
249

250
   const auto& group = m_curve.group();
1,291,922✔
251

252
   if(is_zero()) {
2,579,318✔
253
      m_x.set_words(x_words, x_size);
8,102✔
254
      m_y.set_words(y_words, y_size);
8,102✔
255
      m_z.set_words(z_words, z_size);
8,102✔
256
      return;
8,102✔
257
   }
258

259
   resize_ws(ws_bn, monty_ws_size(group));
1,283,820✔
260

261
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
1,283,820✔
262
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
1,283,820✔
263

264
   BigInt& T0 = ws_bn[2];
1,283,820✔
265
   BigInt& T1 = ws_bn[3];
1,283,820✔
266
   BigInt& T2 = ws_bn[4];
1,283,820✔
267
   BigInt& T3 = ws_bn[5];
1,283,820✔
268
   BigInt& T4 = ws_bn[6];
1,283,820✔
269
   BigInt& T5 = ws_bn[7];
1,283,820✔
270

271
   /*
272
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
273
   */
274

275
   const BigInt& p = group.p();
1,283,820✔
276

277
   fe_sqr(group, T0, z_words, z_size, ws);      // z2^2
1,283,820✔
278
   fe_mul(group, T1, m_x, T0, ws);              // x1*z2^2
1,283,820✔
279
   fe_mul(group, T3, z_words, z_size, T0, ws);  // z2^3
1,283,820✔
280
   fe_mul(group, T2, m_y, T3, ws);              // y1*z2^3
1,283,820✔
281

282
   fe_sqr(group, T3, m_z, ws);                  // z1^2
1,283,820✔
283
   fe_mul(group, T4, x_words, x_size, T3, ws);  // x2*z1^2
1,283,820✔
284

285
   fe_mul(group, T5, m_z, T3, ws);              // z1^3
1,283,820✔
286
   fe_mul(group, T0, y_words, y_size, T5, ws);  // y2*z1^3
1,283,820✔
287

288
   T4.mod_sub(T1, p, sub_ws);  // x2*z1^2 - x1*z2^2
1,283,820✔
289

290
   T0.mod_sub(T2, p, sub_ws);
1,283,820✔
291

292
   if(T4.is_zero()) {
2,567,640✔
293
      if(T0.is_zero()) {
552✔
294
         mult2(ws_bn);
32✔
295
         return;
32✔
296
      }
297

298
      // setting to zero:
299
      m_x.clear();
244✔
300
      m_y = group.monty().R1();
244✔
301
      m_z.clear();
244✔
302
      return;
244✔
303
   }
304

305
   fe_sqr(group, T5, T4, ws);
1,283,544✔
306

307
   fe_mul(group, T3, T1, T5, ws);
1,283,544✔
308

309
   fe_mul(group, T1, T5, T4, ws);
1,283,544✔
310

311
   fe_sqr(group, m_x, T0, ws);
1,283,544✔
312
   m_x.mod_sub(T1, p, sub_ws);
1,283,544✔
313
   m_x.mod_sub(T3, p, sub_ws);
1,283,544✔
314
   m_x.mod_sub(T3, p, sub_ws);
1,283,544✔
315

316
   T3.mod_sub(m_x, p, sub_ws);
1,283,544✔
317

318
   fe_mul(group, m_y, T0, T3, ws);
1,283,544✔
319
   fe_mul(group, T3, T2, T1, ws);
1,283,544✔
320

321
   m_y.mod_sub(T3, p, sub_ws);
1,283,544✔
322

323
   fe_mul(group, T3, z_words, z_size, m_z, ws);
1,283,544✔
324
   fe_mul(group, m_z, T3, T4, ws);
1,283,544✔
325
}
326

327
void EC_Point::mult2i(size_t iterations, std::vector<BigInt>& ws_bn) {
1,001,825✔
328
   if(iterations == 0) {
1,001,825✔
329
      return;
330
   }
331

332
   if(m_y.is_zero()) {
2,003,533✔
333
      *this = EC_Point(m_curve);  // setting myself to zero
×
334
      return;
×
335
   }
336

337
   /*
338
   TODO we can save 2 squarings per iteration by computing
339
   a*Z^4 using values cached from previous iteration
340
   */
341
   for(size_t i = 0; i != iterations; ++i) {
3,777,893✔
342
      mult2(ws_bn);
2,776,068✔
343
   }
344
}
345

346
// *this *= 2
347
void EC_Point::mult2(std::vector<BigInt>& ws_bn) {
3,662,700✔
348
   if(is_zero()) {
7,313,595✔
349
      return;
350
   }
351

352
   const auto& group = m_curve.group();
3,662,018✔
353

354
   if(m_y.is_zero()) {
6,322,328✔
355
      *this = EC_Point(m_curve);  // setting myself to zero
×
356
      return;
×
357
   }
358

359
   resize_ws(ws_bn, monty_ws_size(group));
3,662,018✔
360

361
   secure_vector<word>& ws = ws_bn[0].get_word_vector();
3,662,018✔
362
   secure_vector<word>& sub_ws = ws_bn[1].get_word_vector();
3,662,018✔
363

364
   BigInt& T0 = ws_bn[2];
3,662,018✔
365
   BigInt& T1 = ws_bn[3];
3,662,018✔
366
   BigInt& T2 = ws_bn[4];
3,662,018✔
367
   BigInt& T3 = ws_bn[5];
3,662,018✔
368
   BigInt& T4 = ws_bn[6];
3,662,018✔
369

370
   /*
371
   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc
372
   */
373
   const BigInt& p = group.p();
3,662,018✔
374

375
   fe_sqr(group, T0, m_y, ws);
3,662,018✔
376

377
   fe_mul(group, T1, m_x, T0, ws);
3,662,018✔
378
   T1.mod_mul(4, p, sub_ws);
3,662,018✔
379

380
   if(group.a_is_zero()) {
3,662,018✔
381
      // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2
382
      fe_sqr(group, T4, m_x, ws);  // x^2
500,935✔
383
      T4.mod_mul(3, p, sub_ws);    // 3*x^2
500,935✔
384
   } else if(group.a_is_minus_3()) {
3,161,083✔
385
      /*
386
      if a == -3 then
387
        3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2)
388
      */
389
      fe_sqr(group, T3, m_z, ws);  // z^2
2,093,632✔
390

391
      // (x-z^2)
392
      T2 = m_x;
2,093,632✔
393
      T2.mod_sub(T3, p, sub_ws);
2,093,632✔
394

395
      // (x+z^2)
396
      T3.mod_add(m_x, p, sub_ws);
2,093,632✔
397

398
      fe_mul(group, T4, T2, T3, ws);  // (x-z^2)*(x+z^2)
2,093,632✔
399

400
      T4.mod_mul(3, p, sub_ws);  // 3*(x-z^2)*(x+z^2)
2,093,632✔
401
   } else {
402
      fe_sqr(group, T3, m_z, ws);                  // z^2
1,067,451✔
403
      fe_sqr(group, T4, T3, ws);                   // z^4
1,067,451✔
404
      fe_mul(group, T3, group.monty_a(), T4, ws);  // a*z^4
1,067,451✔
405

406
      fe_sqr(group, T4, m_x, ws);  // x^2
1,067,451✔
407
      T4.mod_mul(3, p, sub_ws);
1,067,451✔
408
      T4.mod_add(T3, p, sub_ws);  // 3*x^2 + a*z^4
1,067,451✔
409
   }
410

411
   fe_sqr(group, T2, T4, ws);
3,662,018✔
412
   T2.mod_sub(T1, p, sub_ws);
3,662,018✔
413
   T2.mod_sub(T1, p, sub_ws);
3,662,018✔
414

415
   fe_sqr(group, T3, T0, ws);
3,662,018✔
416
   T3.mod_mul(8, p, sub_ws);
3,662,018✔
417

418
   T1.mod_sub(T2, p, sub_ws);
3,662,018✔
419

420
   fe_mul(group, T0, T4, T1, ws);
3,662,018✔
421
   T0.mod_sub(T3, p, sub_ws);
3,662,018✔
422

423
   m_x.swap(T2);
3,662,018✔
424

425
   fe_mul(group, T2, m_y, m_z, ws);
3,662,018✔
426
   T2.mod_mul(2, p, sub_ws);
3,662,018✔
427

428
   m_y.swap(T0);
3,662,018✔
429
   m_z.swap(T2);
3,662,018✔
430
}
431

432
// arithmetic operators
433
EC_Point& EC_Point::operator+=(const EC_Point& rhs) {
2,526✔
434
   std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
2,526✔
435
   add(rhs, ws);
2,526✔
436
   return *this;
2,525✔
437
}
2,526✔
438

439
EC_Point& EC_Point::operator-=(const EC_Point& rhs) {
85✔
440
   EC_Point minus_rhs = EC_Point(rhs).negate();
85✔
441

442
   if(is_zero()) {
85✔
443
      *this = minus_rhs;
×
444
   } else {
445
      *this += minus_rhs;
85✔
446
   }
447

448
   return *this;
85✔
449
}
85✔
450

451
EC_Point& EC_Point::operator*=(const BigInt& scalar) {
67✔
452
   *this = scalar * *this;
67✔
453
   return *this;
67✔
454
}
455

456
EC_Point EC_Point::mul(const BigInt& scalar) const {
3,426✔
457
   const size_t scalar_bits = scalar.bits();
3,426✔
458

459
   std::vector<BigInt> ws(EC_Point::WORKSPACE_SIZE);
3,426✔
460

461
   EC_Point R[2] = {this->zero(), *this};
10,278✔
462

463
   for(size_t i = scalar_bits; i > 0; i--) {
774,982✔
464
      const size_t b = scalar.get_bit(i - 1);
771,556✔
465
      R[b ^ 1].add(R[b], ws);
771,556✔
466
      R[b].mult2(ws);
771,556✔
467
   }
468

469
   if(scalar.is_negative()) {
3,426✔
470
      R[0].negate();
×
471
   }
472

473
   BOTAN_DEBUG_ASSERT(R[0].on_the_curve());
3,426✔
474

475
   return R[0];
6,852✔
476
}
13,704✔
477

478
//static
479
void EC_Point::force_all_affine(std::span<EC_Point> points, secure_vector<word>& ws) {
1,303✔
480
   if(points.size() <= 1) {
1,303✔
481
      for(auto& point : points) {
×
482
         point.force_affine();
×
483
      }
484
      return;
×
485
   }
486

487
   for(auto& point : points) {
204,241✔
488
      if(point.is_zero()) {
389,859✔
489
         throw Invalid_State("Cannot convert zero ECC point to affine");
×
490
      }
491
   }
492

493
   /*
494
   For >= 2 points use Montgomery's trick
495

496
   See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography"
497
   (Hankerson, Menezes, Vanstone)
498

499
   TODO is it really necessary to save all k points in c?
500
   */
501

502
   const auto& group = points[0].m_curve.group();
1,303✔
503
   const BigInt& rep_1 = group.monty().R1();
1,303✔
504

505
   if(ws.size() < monty_ws_size(group)) {
1,303✔
506
      ws.resize(monty_ws_size(group));
×
507
   }
508

509
   std::vector<BigInt> c(points.size());
1,303✔
510
   c[0] = points[0].m_z;
1,303✔
511

512
   for(size_t i = 1; i != points.size(); ++i) {
202,938✔
513
      fe_mul(group, c[i], c[i - 1], points[i].m_z, ws);
403,270✔
514
   }
515

516
   BigInt s_inv = invert_element(group, c[c.size() - 1], ws);
1,303✔
517

518
   BigInt z_inv, z2_inv, z3_inv;
1,303✔
519

520
   for(size_t i = points.size() - 1; i != 0; i--) {
202,938✔
521
      EC_Point& point = points[i];
201,635✔
522

523
      fe_mul(group, z_inv, s_inv, c[i - 1], ws);
201,635✔
524

525
      s_inv = fe_mul(group, s_inv, point.m_z, ws);
201,635✔
526

527
      fe_sqr(group, z2_inv, z_inv, ws);
201,635✔
528
      fe_mul(group, z3_inv, z2_inv, z_inv, ws);
201,635✔
529
      point.m_x = fe_mul(group, point.m_x, z2_inv, ws);
201,635✔
530
      point.m_y = fe_mul(group, point.m_y, z3_inv, ws);
201,635✔
531
      point.m_z = rep_1;
201,635✔
532
   }
533

534
   fe_sqr(group, z2_inv, s_inv, ws);
1,303✔
535
   fe_mul(group, z3_inv, z2_inv, s_inv, ws);
1,303✔
536
   points[0].m_x = fe_mul(group, points[0].m_x, z2_inv, ws);
1,303✔
537
   points[0].m_y = fe_mul(group, points[0].m_y, z3_inv, ws);
1,303✔
538
   points[0].m_z = rep_1;
1,303✔
539
}
5,212✔
540

541
void EC_Point::force_affine() {
10,483✔
542
   if(is_zero()) {
10,672✔
543
      throw Invalid_State("Cannot convert zero ECC point to affine");
×
544
   }
545

546
   secure_vector<word> ws;
10,483✔
547

548
   const auto& group = m_curve.group();
10,483✔
549

550
   const BigInt z_inv = invert_element(group, m_z, ws);
10,483✔
551
   const BigInt z2_inv = fe_sqr(group, z_inv, ws);
10,483✔
552
   const BigInt z3_inv = fe_mul(group, z_inv, z2_inv, ws);
10,483✔
553
   m_x = fe_mul(group, m_x, z2_inv, ws);
10,483✔
554
   m_y = fe_mul(group, m_y, z3_inv, ws);
10,483✔
555
   m_z = group.monty().R1();
10,483✔
556
}
41,932✔
557

558
bool EC_Point::is_affine() const {
112,907✔
559
   const auto& group = m_curve.group();
112,907✔
560
   return m_z == group.monty().R1();
112,907✔
561
}
562

563
secure_vector<uint8_t> EC_Point::x_bytes() const {
×
564
   const auto& group = m_curve.group();
×
565
   const size_t p_bytes = group.p_bytes();
×
566
   secure_vector<uint8_t> b(p_bytes);
×
567
   BigInt::encode_1363(b.data(), b.size(), this->get_affine_x());
×
568
   return b;
×
569
}
×
570

571
secure_vector<uint8_t> EC_Point::y_bytes() const {
×
572
   const auto& group = m_curve.group();
×
573
   const size_t p_bytes = group.p_bytes();
×
574
   secure_vector<uint8_t> b(p_bytes);
×
575
   BigInt::encode_1363(b.data(), b.size(), this->get_affine_y());
×
576
   return b;
×
577
}
×
578

579
secure_vector<uint8_t> EC_Point::xy_bytes() const {
16,107✔
580
   const auto& group = m_curve.group();
16,107✔
581
   const size_t p_bytes = group.p_bytes();
16,107✔
582
   secure_vector<uint8_t> b(2 * p_bytes);
16,107✔
583
   BigInt::encode_1363(&b[0], p_bytes, this->get_affine_x());
16,107✔
584
   BigInt::encode_1363(&b[p_bytes], p_bytes, this->get_affine_y());
16,107✔
585
   return b;
16,107✔
586
}
×
587

588
BigInt EC_Point::get_affine_x() const {
57,293✔
589
   if(is_zero()) {
57,990✔
590
      throw Invalid_State("Cannot convert zero point to affine");
28✔
591
   }
592

593
   secure_vector<word> monty_ws;
57,265✔
594

595
   const auto& group = m_curve.group();
57,265✔
596

597
   if(is_affine()) {
57,265✔
598
      return from_rep_to_tmp(group, m_x, monty_ws);
57,265✔
599
   }
600

601
   BigInt z2 = fe_sqr(group, m_z, monty_ws);
9,953✔
602
   z2 = invert_element(group, z2, monty_ws);
9,953✔
603

604
   BigInt r;
9,953✔
605
   fe_mul(group, r, m_x, z2, monty_ws);
9,953✔
606
   from_rep(group, r, monty_ws);
9,953✔
607
   return r;
9,953✔
608
}
77,171✔
609

610
BigInt EC_Point::get_affine_y() const {
55,670✔
611
   if(is_zero()) {
55,670✔
612
      throw Invalid_State("Cannot convert zero point to affine");
28✔
613
   }
614

615
   const auto& group = m_curve.group();
55,642✔
616
   secure_vector<word> monty_ws;
55,642✔
617

618
   if(is_affine()) {
55,642✔
619
      return from_rep_to_tmp(group, m_y, monty_ws);
55,642✔
620
   }
621

622
   const BigInt z2 = fe_sqr(group, m_z, monty_ws);
8,332✔
623
   const BigInt z3 = fe_mul(group, m_z, z2, monty_ws);
8,332✔
624
   const BigInt z3_inv = invert_element(group, z3, monty_ws);
8,332✔
625

626
   BigInt r;
8,332✔
627
   fe_mul(group, r, m_y, z3_inv, monty_ws);
8,332✔
628
   from_rep(group, r, monty_ws);
8,332✔
629
   return r;
8,332✔
630
}
88,970✔
631

632
bool EC_Point::on_the_curve() const {
16,823✔
633
   /*
634
   Is the point still on the curve?? (If everything is correct, the
635
   point is always on its curve; then the function will return true.
636
   If somehow the state is corrupted, which suggests a fault attack
637
   (or internal computational error), then return false.
638
   */
639
   if(is_zero()) {
22,084✔
640
      return true;
641
   }
642

643
   const auto& group = m_curve.group();
16,767✔
644
   secure_vector<word> monty_ws;
16,767✔
645

646
   const BigInt y2 = from_rep_to_tmp(group, fe_sqr(group, m_y, monty_ws), monty_ws);
16,767✔
647
   const BigInt x3 = fe_mul(group, m_x, fe_sqr(group, m_x, monty_ws), monty_ws);
16,767✔
648
   const BigInt ax = fe_mul(group, m_x, group.monty_a(), monty_ws);
16,767✔
649
   const BigInt z2 = fe_sqr(group, m_z, monty_ws);
16,767✔
650

651
   const BigInt& monty_b = group.monty_b();
16,767✔
652

653
   // Is z equal to 1 (in Montgomery form)?
654
   if(m_z == z2) {
16,767✔
655
      if(y2 != from_rep_to_tmp(group, x3 + ax + monty_b, monty_ws)) {
51,845✔
656
         return false;
657
      }
658
   }
659

660
   const BigInt z3 = fe_mul(group, m_z, z2, monty_ws);
16,699✔
661
   const BigInt ax_z4 = fe_mul(group, ax, fe_sqr(group, z2, monty_ws), monty_ws);
16,699✔
662
   const BigInt b_z6 = fe_mul(group, monty_b, fe_sqr(group, z3, monty_ws), monty_ws);
16,699✔
663

664
   if(y2 != from_rep_to_tmp(group, x3 + ax_z4 + b_z6, monty_ws)) {
83,495✔
665
      return false;
666
   }
667

668
   return true;
669
}
133,932✔
670

671
bool EC_Point::_is_x_eq_to_v_mod_order(const BigInt& v) const {
5,356✔
672
   if(this->is_zero()) {
10,698✔
673
      return false;
674
   }
675

676
   const auto& group = m_curve.group();
5,343✔
677

678
   /*
679
   * The trick used below doesn't work for curves with cofactors
680
   */
681
   if(group.has_cofactor()) {
5,343✔
682
      return group.mod_order(this->get_affine_x()) == v;
×
683
   }
684

685
   /*
686
   * Note we're working with the projective coordinate directly here!
687
   * Nominally we're comparing v with the affine x coordinate.
688
   *
689
   * return group.mod_order(this->get_affine_x()) == v;
690
   *
691
   * However by instead projecting r to an identical z as the x
692
   * coordinate, we can compare without having to perform an
693
   * expensive inversion in the field.
694
   *
695
   * That is, given (x*z2) and r, instead of checking if
696
   *    (x*z2)*z2^-1 == r,
697
   * we check if
698
   *    (x*z2) == (r*z2)
699
   */
700
   secure_vector<word> ws;
5,343✔
701
   BigInt vr = v;
5,343✔
702
   to_rep(group, vr, ws);
5,343✔
703
   BigInt z2, v_z2;
5,343✔
704
   fe_sqr(group, z2, this->get_z(), ws);
5,343✔
705
   fe_mul(group, v_z2, vr, z2, ws);
5,343✔
706

707
   /*
708
   * Since (typically) the group order is slightly less than the size
709
   * of the field elements, its possible the signer had to reduce the
710
   * r component. If they did not reduce r, then this value is correct.
711
   *
712
   * Due to the Hasse bound, this case occurs almost always; the
713
   * probability that a reduction was actually required is
714
   * approximately 1 in 2^(n/2) where n is the bit length of the curve.
715
   */
716
   if(this->get_x() == v_z2) {
5,343✔
717
      return true;
718
   }
719

720
   if(group.order_is_less_than_p()) {
3,320✔
721
      vr = v + group.order();
2,196✔
722
      if(vr < group.p()) {
2,196✔
723
         to_rep(group, vr, ws);
7✔
724
         fe_mul(group, v_z2, vr, z2, ws);
7✔
725

726
         if(this->get_x() == v_z2) {
7✔
727
            return true;
728
         }
729
      }
730
   }
731

732
   // Reject:
733
   return false;
734
}
21,372✔
735

736
// swaps the states of *this and other
737
void EC_Point::swap(EC_Point& other) noexcept {
277,867✔
738
   m_curve.swap(other.m_curve);
277,867✔
739
   m_x.swap(other.m_x);
277,867✔
740
   m_y.swap(other.m_y);
277,867✔
741
   m_z.swap(other.m_z);
277,867✔
742
}
277,867✔
743

744
bool EC_Point::operator==(const EC_Point& other) const {
7,505✔
745
   if(m_curve != other.m_curve) {
7,505✔
746
      return false;
747
   }
748

749
   // If this is zero, only equal if other is also zero
750
   if(is_zero()) {
10,334✔
751
      return other.is_zero();
168✔
752
   }
753

754
   return (get_affine_x() == other.get_affine_x() && get_affine_y() == other.get_affine_y());
36,683✔
755
}
756

757
// encoding and decoding
758
std::vector<uint8_t> EC_Point::encode(EC_Point_Format format) const {
24,842✔
759
   if(is_zero()) {
25,730✔
760
      return std::vector<uint8_t>(1);  // single 0 byte
168✔
761
   }
762

763
   const size_t p_bytes = m_curve.group().p_bytes();
24,674✔
764

765
   const BigInt x = get_affine_x();
24,674✔
766
   const BigInt y = get_affine_y();
24,674✔
767

768
   const size_t parts = (format == EC_Point_Format::Compressed) ? 1 : 2;
24,674✔
769

770
   std::vector<uint8_t> result(1 + parts * p_bytes);
24,674✔
771
   BufferStuffer stuffer(result);
24,674✔
772

773
   if(format == EC_Point_Format::Uncompressed) {
24,674✔
774
      stuffer.append(0x04);
22,802✔
775
      x.serialize_to(stuffer.next(p_bytes));
22,802✔
776
      y.serialize_to(stuffer.next(p_bytes));
22,802✔
777
   } else if(format == EC_Point_Format::Compressed) {
1,872✔
778
      stuffer.append(0x02 | static_cast<uint8_t>(y.get_bit(0)));
3,558✔
779
      x.serialize_to(stuffer.next(p_bytes));
1,779✔
780
   } else if(format == EC_Point_Format::Hybrid) {
93✔
781
      stuffer.append(0x06 | static_cast<uint8_t>(y.get_bit(0)));
186✔
782
      x.serialize_to(stuffer.next(p_bytes));
93✔
783
      y.serialize_to(stuffer.next(p_bytes));
93✔
784
   } else {
785
      throw Invalid_Argument("EC2OSP illegal point encoding");
×
786
   }
787

788
   return result;
24,674✔
789
}
74,022✔
790

791
namespace {
792

793
BigInt decompress_point(bool y_mod_2, const BigInt& x, const BigInt& p, const BigInt& a, const BigInt& b) {
968✔
794
   const BigInt g = ((x * x + a) * x + b) % p;
3,872✔
795

796
   BigInt z = sqrt_modulo_prime(g, p);
968✔
797

798
   if(z < 0) {
968✔
799
      throw Decoding_Error("Error during EC point decompression");
×
800
   }
801

802
   if(z.get_bit(0) != y_mod_2) {
1,936✔
803
      z = p - z;
1,060✔
804
   }
805

806
   return z;
968✔
807
}
968✔
808

809
}  // namespace
810

811
EC_Point OS2ECP(std::span<const uint8_t> data, const CurveGFp& curve) {
7,539✔
812
   return OS2ECP(data.data(), data.size(), curve);
7,539✔
813
}
814

815
EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp& curve) {
7,539✔
816
   if(data_len == 1 && data[0] == 0) {
7,539✔
817
      // SEC1 standard representation of the point at infinity
818
      return EC_Point(curve);
128✔
819
   }
820

821
   const auto [g_x, g_y] = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b());
7,411✔
822

823
   EC_Point point(curve, g_x, g_y);
14,532✔
824

825
   if(!point.on_the_curve()) {
7,266✔
826
      throw Decoding_Error("OS2ECP: Decoded point was not on the curve");
68✔
827
   }
828

829
   return point;
7,198✔
830
}
7,334✔
831

832
std::pair<BigInt, BigInt> OS2ECP(const uint8_t pt[], size_t pt_len, const BigInt& p, const BigInt& a, const BigInt& b) {
7,467✔
833
   if(pt_len <= 1) {
7,467✔
834
      throw Decoding_Error("OS2ECP invalid point encoding");
×
835
   }
836

837
   const uint8_t pc = pt[0];
7,467✔
838
   const size_t p_bytes = p.bytes();
7,467✔
839

840
   BigInt x, y;
7,467✔
841

842
   if(pc == 2 || pc == 3) {
7,467✔
843
      if(pt_len != 1 + p_bytes) {
999✔
844
         throw Decoding_Error("OS2ECP invalid point encoding");
127✔
845
      }
846
      x = BigInt::decode(&pt[1], pt_len - 1);
872✔
847

848
      const bool y_mod_2 = ((pc & 0x01) == 1);
872✔
849
      y = decompress_point(y_mod_2, x, p, a, b);
872✔
850
   } else if(pc == 4) {
6,468✔
851
      if(pt_len != 1 + 2 * p_bytes) {
6,354✔
852
         throw Decoding_Error("OS2ECP invalid point encoding");
1✔
853
      }
854

855
      x = BigInt::decode(&pt[1], p_bytes);
6,353✔
856
      y = BigInt::decode(&pt[p_bytes + 1], p_bytes);
6,353✔
857
   } else if(pc == 6 || pc == 7) {
114✔
858
      if(pt_len != 1 + 2 * p_bytes) {
111✔
859
         throw Decoding_Error("OS2ECP invalid point encoding");
15✔
860
      }
861

862
      x = BigInt::decode(&pt[1], p_bytes);
96✔
863
      y = BigInt::decode(&pt[p_bytes + 1], p_bytes);
96✔
864

865
      const bool y_mod_2 = ((pc & 0x01) == 1);
96✔
866

867
      if(decompress_point(y_mod_2, x, p, a, b) != y) {
434✔
868
         throw Decoding_Error("OS2ECP: Decoding error in hybrid format");
×
869
      }
870
   } else {
871
      throw Decoding_Error("OS2ECP: Unknown format type " + std::to_string(static_cast<int>(pc)));
9✔
872
   }
873

874
   if(x >= p || y >= p) {
14,642✔
875
      throw Decoding_Error("OS2ECP invalid point encoding");
×
876
   }
877

878
   return std::make_pair(x, y);
7,321✔
879
}
14,788✔
880

881
}  // namespace Botan
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

© 2025 Coveralls, Inc