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

randombit / botan / 29471089948

15 Jul 2026 11:28PM UTC coverage: 89.402% (-2.3%) from 91.656%
29471089948

push

github

web-flow
Merge pull request #5724 from randombit/jack/filter-fixes

Fix various bugs in the Pipe/Filter library

113560 of 127022 relevant lines covered (89.4%)

10935343.63 hits per line

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

89.86
/src/lib/pubkey/ec_group/ec_inner_data.cpp
1
/*
2
* (C) 2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/internal/ec_inner_data.h>
8

9
#include <botan/der_enc.h>
10
#include <botan/internal/barrett.h>
11
#include <botan/internal/ec_inner_pc.h>
12
#include <botan/internal/fmt.h>
13
#include <botan/internal/pcurves.h>
14
#include <algorithm>
15

16
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
17
   #include <botan/internal/ec_inner_bn.h>
18
   #include <botan/internal/point_mul.h>
19
#endif
20

21
#if defined(BOTAN_HAS_XMD)
22
   #include <botan/internal/xmd.h>
23
#endif
24

25
namespace Botan {
26

27
EC_Group_Data::~EC_Group_Data() = default;
4,097✔
28

29
// Note this constructor *does not* initialize m_curve, m_base_point or m_base_mult
30
EC_Group_Data::EC_Group_Data(const BigInt& p,
684✔
31
                             const BigInt& a,
32
                             const BigInt& b,
33
                             const BigInt& g_x,
34
                             const BigInt& g_y,
35
                             const BigInt& order,
36
                             const BigInt& cofactor,
37
                             const OID& oid,
38
                             EC_Group_Source source) :
684✔
39
      m_p(p),
684✔
40
      m_a(a),
684✔
41
      m_b(b),
684✔
42
      m_g_x(g_x),
684✔
43
      m_g_y(g_y),
684✔
44
      m_order(order),
684✔
45
      m_cofactor(cofactor),
684✔
46
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
47
      m_mod_field(Barrett_Reduction::for_public_modulus(p)),
684✔
48
      m_mod_order(Barrett_Reduction::for_public_modulus(order)),
684✔
49
      m_monty(m_p, m_mod_field),
684✔
50
#endif
51
      m_oid(oid),
684✔
52
      m_p_words(p.sig_words()),
684✔
53
      m_p_bits(p.bits()),
684✔
54
      m_order_bits(order.bits()),
684✔
55
      m_order_bytes((m_order_bits + 7) / 8),
684✔
56
      m_a_is_minus_3(a == p - 3),
684✔
57
      m_a_is_zero(a.is_zero()),
684✔
58
      m_has_cofactor(m_cofactor != 1),
684✔
59
      m_order_is_less_than_p(m_order < p),
684✔
60
      m_source(source) {
2,052✔
61
   // Verify the generator (x, y) satisfies y^2 = x^3 + a*x + b (mod p)
62
   auto mod_p = Barrett_Reduction::for_public_modulus(p);
684✔
63
   const BigInt y2 = mod_p.square(g_y);
684✔
64
   const BigInt x3_ax_b = mod_p.reduce(mod_p.cube(g_x) + mod_p.multiply(a, g_x) + b);
684✔
65
   if(y2 != x3_ax_b) {
684✔
66
      throw Invalid_Argument("EC_Group generator is not on the curve");
×
67
   }
68

69
   // TODO(Botan4) we can assume/assert the OID is set
70
   if(!m_oid.empty()) {
684✔
71
      DER_Encoder der(m_der_named_curve);
677✔
72
      der.encode(m_oid);
677✔
73

74
      if(const auto name = m_oid.registered_name()) {
677✔
75
         // returns nullptr if unknown or not supported
76
         m_pcurve = PCurve::PrimeOrderCurve::for_named_curve(*name);
672✔
77
      }
×
78
      if(m_pcurve) {
677✔
79
         m_engine = EC_Group_Engine::Optimized;
587✔
80
      }
81
   }
677✔
82

83
   // Try a generic pcurves instance
84
   if(!m_pcurve && !m_has_cofactor) {
684✔
85
      m_pcurve = PCurve::PrimeOrderCurve::from_params(p, a, b, g_x, g_y, order);
96✔
86
      if(m_pcurve) {
96✔
87
         m_engine = EC_Group_Engine::Generic;
86✔
88
      }
89
      // possibly still null here, if parameters unsuitable or if the
90
      // pcurves_generic module wasn't included in the build
91
   }
92

93
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
94
   secure_vector<word> ws;
684✔
95
   m_a_r = m_monty.mul(a, m_monty.R2(), ws);
1,368✔
96
   m_b_r = m_monty.mul(b, m_monty.R2(), ws);
1,368✔
97
   if(!m_pcurve) {
684✔
98
      m_engine = EC_Group_Engine::Legacy;
11✔
99
   }
100
#else
101
   if(!m_pcurve) {
102
      if(m_oid.empty()) {
103
         throw Not_Implemented("EC_Group this group is not supported in this build configuration");
104
      } else {
105
         throw Not_Implemented(
106
            fmt("EC_Group the group {} is not supported in this build configuration", oid.to_string()));
107
      }
108
   }
109
#endif
110
}
1,368✔
111

112
std::shared_ptr<EC_Group_Data> EC_Group_Data::create(const BigInt& p,
684✔
113
                                                     const BigInt& a,
114
                                                     const BigInt& b,
115
                                                     const BigInt& g_x,
116
                                                     const BigInt& g_y,
117
                                                     const BigInt& order,
118
                                                     const BigInt& cofactor,
119
                                                     const OID& oid,
120
                                                     EC_Group_Source source) {
121
   auto group = std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
684✔
122

123
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
124
   group->m_curve = CurveGFp(group.get());
684✔
125
   group->m_base_point = EC_Point(group->m_curve, g_x, g_y);
1,368✔
126
   if(!group->m_pcurve) {
684✔
127
      group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order);
11✔
128
   }
129
#endif
130

131
   return group;
684✔
132
}
×
133

134
bool EC_Group_Data::params_match(const BigInt& p,
78✔
135
                                 const BigInt& a,
136
                                 const BigInt& b,
137
                                 const BigInt& g_x,
138
                                 const BigInt& g_y,
139
                                 const BigInt& order,
140
                                 const BigInt& cofactor) const {
141
   if(p != this->p()) {
78✔
142
      return false;
143
   }
144
   if(a != this->a()) {
34✔
145
      return false;
146
   }
147
   if(b != this->b()) {
34✔
148
      return false;
149
   }
150
   if(order != this->order()) {
34✔
151
      return false;
152
   }
153
   if(cofactor != this->cofactor()) {
34✔
154
      return false;
155
   }
156
   if(g_x != this->g_x()) {
34✔
157
      return false;
158
   }
159
   if(g_y != this->g_y()) {
34✔
160
      return false;
161
   }
162

163
   return true;
164
}
165

166
bool EC_Group_Data::params_match(const BigInt& p,
823✔
167
                                 const BigInt& a,
168
                                 const BigInt& b,
169
                                 std::span<const uint8_t> base_pt,
170
                                 const BigInt& order,
171
                                 const BigInt& cofactor) const {
172
   if(p != this->p()) {
823✔
173
      return false;
174
   }
175
   if(a != this->a()) {
76✔
176
      return false;
177
   }
178
   if(b != this->b()) {
71✔
179
      return false;
180
   }
181
   if(order != this->order()) {
64✔
182
      return false;
183
   }
184
   if(cofactor != this->cofactor()) {
63✔
185
      return false;
186
   }
187

188
   const size_t field_len = this->p_bytes();
63✔
189

190
   if(base_pt.size() == 1 + field_len && (base_pt[0] == 0x02 || base_pt[0] == 0x03)) {
63✔
191
      // compressed
192

193
      const auto g_x = m_g_x.serialize(field_len);
×
194
      const auto g_y = m_g_y.is_odd();
×
195

196
      const auto sec1_x = base_pt.subspan(1, field_len);
×
197
      const bool sec1_y = (base_pt[0] == 0x03);
×
198

199
      if(!std::ranges::equal(sec1_x, g_x)) {
×
200
         return false;
201
      }
202

203
      if(sec1_y != g_y) {
×
204
         return false;
205
      }
206

207
      return true;
×
208
   } else if(base_pt.size() == 1 + 2 * field_len && base_pt[0] == 0x04) {
63✔
209
      const auto g_x = m_g_x.serialize(field_len);
62✔
210
      const auto g_y = m_g_y.serialize(field_len);
62✔
211

212
      const auto sec1_x = base_pt.subspan(1, field_len);
62✔
213
      const auto sec1_y = base_pt.subspan(1 + field_len, field_len);
62✔
214

215
      if(!std::ranges::equal(sec1_x, g_x)) {
124✔
216
         return false;
217
      }
218

219
      if(!std::ranges::equal(sec1_y, g_y)) {
174✔
220
         return false;
221
      }
222

223
      return true;
56✔
224
   } else {
124✔
225
      throw Decoding_Error("Invalid base point encoding in explicit group");
1✔
226
   }
227
}
228

229
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
×
230
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
×
231
}
232

233
void EC_Group_Data::set_oid(const OID& oid) {
×
234
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
×
235
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
×
236
   m_oid = oid;
×
237

238
   DER_Encoder der(m_der_named_curve);
×
239
   der.encode(m_oid);
×
240
}
×
241

242
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
39,920✔
243
   const size_t bit_length = 8 * bytes.size();
39,920✔
244

245
   if(bit_length < order_bits()) {
39,920✔
246
      // No shifting required, but might still need to reduce by modulus
247
      return this->scalar_from_bytes_mod_order(bytes);
8,027✔
248
   } else {
249
      const size_t shift = bit_length - order_bits();
31,893✔
250

251
      const size_t new_length = bytes.size() - (shift / 8);
31,893✔
252
      const size_t bit_shift = shift % 8;
31,893✔
253

254
      if(bit_shift == 0) {
31,893✔
255
         // Easy case just read different bytes
256
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
28,927✔
257
      } else {
258
         std::vector<uint8_t> sbytes(new_length);
2,966✔
259

260
         uint8_t carry = 0;
2,966✔
261
         for(size_t i = 0; i != new_length; ++i) {
83,782✔
262
            const uint8_t w = bytes[i];
80,816✔
263
            sbytes[i] = (w >> bit_shift) | carry;
80,816✔
264
            carry = w << (8 - bit_shift);
80,816✔
265
         }
266

267
         return this->scalar_from_bytes_mod_order(sbytes);
2,966✔
268
      }
2,966✔
269
   }
270
}
271

272
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
50,857✔
273
   if(bytes.size() > 2 * order_bytes()) {
50,857✔
274
      return {};
×
275
   }
276

277
   if(m_pcurve) {
50,857✔
278
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
47,761✔
279
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
47,761✔
280
      } else {
281
         return {};
×
282
      }
47,761✔
283
   } else {
284
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
285
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(BigInt(bytes)));
3,096✔
286
#else
287
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
288
#endif
289
   }
290
}
291

292
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
46,590✔
293
   if(m_pcurve) {
46,590✔
294
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
40,387✔
295
   } else {
296
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
297
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
12,406✔
298
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
18,609✔
299
#else
300
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
301
#endif
302
   }
303
}
304

305
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
297✔
306
   if(m_pcurve) {
297✔
307
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
281✔
308
   } else {
309
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
310
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
16✔
311
#else
312
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
313
#endif
314
   }
315
}
316

317
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
4,563✔
318
   if(bn <= 0 || bn >= m_order) {
4,563✔
319
      return {};
×
320
   }
321

322
   if(m_pcurve) {
4,563✔
323
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
8,288✔
324
   } else {
325
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
326
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
419✔
327
#else
328
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
329
#endif
330
   }
331
}
332

333
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar,
6,276✔
334
                                                              RandomNumberGenerator& rng) const {
335
   if(m_pcurve) {
6,276✔
336
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
5,877✔
337
      auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
5,877✔
338
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
5,877✔
339
   } else {
5,877✔
340
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
341
      const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
399✔
342
      BOTAN_STATE_CHECK(m_base_mult != nullptr);
399✔
343
      std::vector<BigInt> ws;
399✔
344
      const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
399✔
345

346
      if(pt.is_zero()) {
798✔
347
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
348
      } else {
349
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
399✔
350
      }
351
#else
352
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
353
#endif
354
   }
399✔
355
}
356

357
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
96,737✔
358
   if(bytes.size() != m_order_bytes) {
96,737✔
359
      return nullptr;
7,730✔
360
   }
361

362
   if(m_pcurve) {
89,007✔
363
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
84,181✔
364
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
81,686✔
365
      } else {
366
         return nullptr;
2,495✔
367
      }
84,181✔
368
   } else {
369
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
370
      BigInt r(bytes);
4,826✔
371

372
      if(r.is_zero() || r >= m_order) {
9,652✔
373
         return nullptr;
457✔
374
      }
375

376
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
4,369✔
377
#else
378
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
379
#endif
380
   }
4,826✔
381
}
382

383
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize_uncompressed(
46,777✔
384
   std::span<const uint8_t> bytes) const {
385
   if(bytes.size() != 1 + 2 * p_bytes() || bytes[0] != 0x04) {
46,777✔
386
      return {};
8,862✔
387
   }
388

389
   if(m_pcurve) {
37,915✔
390
      if(auto pt = m_pcurve->deserialize_point_uncompressed(bytes)) {
35,636✔
391
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
35,449✔
392
      } else {
393
         return {};
187✔
394
      }
35,636✔
395
   } else {
396
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
397
      try {
2,279✔
398
         auto pt = Botan::OS2ECP(bytes, m_curve);
2,279✔
399
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
2,271✔
400
      } catch(...) {
2,279✔
401
         return {};
8✔
402
      }
8✔
403
#else
404
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
405
#endif
406
   }
407
}
408

409
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize_compressed(std::span<const uint8_t> bytes) const {
25,832✔
410
   if(bytes.size() != 1 + p_bytes() || (bytes[0] != 0x02 && bytes[0] != 0x03)) {
25,832✔
411
      return {};
13,758✔
412
   }
413

414
   if(m_pcurve) {
12,074✔
415
      if(auto pt = m_pcurve->deserialize_point_compressed(bytes)) {
10,474✔
416
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
10,462✔
417
      } else {
418
         return {};
12✔
419
      }
10,474✔
420
   } else {
421
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
422
      try {
1,600✔
423
         auto pt = Botan::OS2ECP(bytes, m_curve);
1,600✔
424
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,600✔
425
      } catch(...) {
1,600✔
426
         return {};
×
427
      }
×
428
#else
429
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
430
#endif
431
   }
432
}
433

434
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_identity() const {
366✔
435
   if(m_pcurve) {
366✔
436
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_identity());
314✔
437
   } else {
438
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
439
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), EC_Point(m_curve));
52✔
440
#else
441
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
442
#endif
443
   }
444
}
445

446
namespace {
447

448
std::function<void(std::span<uint8_t>)> h2c_expand_message(std::string_view hash_fn,
77✔
449
                                                           std::span<const uint8_t> input,
450
                                                           std::span<const uint8_t> domain_sep) {
451
   /*
452
   * This could be extended to support expand_message_xof or a MHF like Argon2
453
   */
454

455
   if(hash_fn.starts_with("SHAKE")) {
77✔
456
      throw Not_Implemented("Hash to curve currently does not support expand_message_xof");
×
457
   }
458

459
   return [=](std::span<uint8_t> uniform_bytes) {
228✔
460
#if defined(BOTAN_HAS_XMD)
461
      expand_message_xmd(hash_fn, uniform_bytes, input, domain_sep);
74✔
462
#else
463
      BOTAN_UNUSED(hash_fn, uniform_bytes, input, domain_sep);
464
      throw Not_Implemented("Hash to curve is not implemented due to XMD being disabled");
465
#endif
466
   };
77✔
467
}
468

469
}  // namespace
470

471
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
34✔
472
                                                                           std::span<const uint8_t> input,
473
                                                                           std::span<const uint8_t> domain_sep) const {
474
   if(m_pcurve) {
34✔
475
      auto pt = m_pcurve->hash_to_curve_ro(h2c_expand_message(hash_fn, input, domain_sep));
34✔
476
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
34✔
477
   } else {
34✔
478
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
479
   }
480
}
481

482
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
43✔
483
                                                                           std::span<const uint8_t> input,
484
                                                                           std::span<const uint8_t> domain_sep) const {
485
   if(m_pcurve) {
43✔
486
      auto pt = m_pcurve->hash_to_curve_nu(h2c_expand_message(hash_fn, input, domain_sep));
46✔
487
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
40✔
488
   } else {
40✔
489
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
490
   }
491
}
492

493
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
17,566✔
494
                                                                RandomNumberGenerator& rng) const {
495
   if(m_pcurve) {
17,566✔
496
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
15,713✔
497
      auto pt = m_pcurve->point_to_affine(m_pcurve->mul_by_g(k.value(), rng));
15,713✔
498
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
15,713✔
499
   } else {
15,713✔
500
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
501
      const auto& group = scalar.group();
1,853✔
502
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
1,853✔
503

504
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
1,853✔
505
      std::vector<BigInt> ws;
1,853✔
506
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
1,853✔
507
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,853✔
508
#else
509
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
510
#endif
511
   }
1,853✔
512
}
513

514
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p,
3,488✔
515
                                                              const EC_Scalar_Data& x,
516
                                                              const EC_AffinePoint_Data& q,
517
                                                              const EC_Scalar_Data& y,
518
                                                              RandomNumberGenerator& rng) const {
519
   if(m_pcurve) {
3,488✔
520
      auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(),
6,416✔
521
                                    EC_Scalar_Data_PC::checked_ref(x).value(),
3,208✔
522
                                    EC_AffinePoint_Data_PC::checked_ref(q).value(),
3,208✔
523
                                    EC_Scalar_Data_PC::checked_ref(y).value(),
3,208✔
524
                                    rng);
3,208✔
525

526
      if(pt) {
3,208✔
527
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(*pt));
3,040✔
528
      } else {
529
         return nullptr;
168✔
530
      }
531
   } else {
3,208✔
532
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
533
      std::vector<BigInt> ws;
280✔
534
      const auto& group = p.group();
280✔
535

536
      // TODO this could be better!
537
      const EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws);
280✔
538
      const EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws);
280✔
539

540
      const auto order = group->order() * group->cofactor();  // See #3800
280✔
541

542
      auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws);
280✔
543
      auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws);
280✔
544

545
      auto px_qy = px + qy;
280✔
546

547
      if(!px_qy.is_zero()) {
532✔
548
         px_qy.force_affine();
252✔
549
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
252✔
550
      } else {
551
         return nullptr;
28✔
552
      }
553
#else
554
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
555
#endif
556
   }
840✔
557
}
558

559
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p,
10,209✔
560
                                                               const EC_AffinePoint_Data& q) const {
561
   if(m_pcurve) {
10,209✔
562
      auto pt = m_pcurve->point_add(EC_AffinePoint_Data_PC::checked_ref(p).value(),
9,469✔
563
                                    EC_AffinePoint_Data_PC::checked_ref(q).value());
9,469✔
564

565
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
9,468✔
566
   } else {
9,468✔
567
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
568
      auto pt = p.to_legacy_point() + q.to_legacy_point();
740✔
569
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
740✔
570
#else
571
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
572
#endif
573
   }
740✔
574
}
575

576
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const {
9,629✔
577
   if(m_pcurve) {
9,629✔
578
      auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value());
8,567✔
579
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
8,567✔
580
   } else {
8,567✔
581
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
582
      auto pt = p.to_legacy_point();
1,062✔
583
      pt.negate();  // negates in place
1,062✔
584
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,062✔
585
#else
586
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
587
#endif
588
   }
1,062✔
589
}
590

591
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
14,508✔
592
   if(m_pcurve) {
14,508✔
593
      return std::make_unique<EC_Mul2Table_Data_PC>(h);
14,204✔
594
   } else {
595
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
596
      const EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
608✔
597
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
304✔
598
#else
599
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
600
#endif
601
   }
304✔
602
}
603

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

© 2026 Coveralls, Inc