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

randombit / botan / 21521969667

30 Jan 2026 10:56AM UTC coverage: 90.064% (-0.01%) from 90.076%
21521969667

push

github

web-flow
Merge pull request #5268 from randombit/jack/ecc-params-setup

Avoid validation of known EC groups when decoding an explicit curve block

102164 of 113435 relevant lines covered (90.06%)

11348221.73 hits per line

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

90.77
/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/ec_inner_pc.h>
11
#include <botan/internal/fmt.h>
12
#include <botan/internal/pcurves.h>
13
#include <algorithm>
14

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

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

24
namespace Botan {
25

26
EC_Group_Data::~EC_Group_Data() = default;
6,901✔
27

28
// Note this constructor *does not* initialize m_curve, m_base_point or m_base_mult
29
EC_Group_Data::EC_Group_Data(const BigInt& p,
1,151✔
30
                             const BigInt& a,
31
                             const BigInt& b,
32
                             const BigInt& g_x,
33
                             const BigInt& g_y,
34
                             const BigInt& order,
35
                             const BigInt& cofactor,
36
                             const OID& oid,
37
                             EC_Group_Source source) :
1,151✔
38
      m_p(p),
1,151✔
39
      m_a(a),
1,151✔
40
      m_b(b),
1,151✔
41
      m_g_x(g_x),
1,151✔
42
      m_g_y(g_y),
1,151✔
43
      m_order(order),
1,151✔
44
      m_cofactor(cofactor),
1,151✔
45
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
46
      m_mod_field(Barrett_Reduction::for_public_modulus(p)),
1,151✔
47
      m_mod_order(Barrett_Reduction::for_public_modulus(order)),
1,151✔
48
      m_monty(m_p, m_mod_field),
1,151✔
49
#endif
50
      m_oid(oid),
1,151✔
51
      m_p_words(p.sig_words()),
1,151✔
52
      m_p_bits(p.bits()),
1,151✔
53
      m_order_bits(order.bits()),
1,151✔
54
      m_order_bytes((m_order_bits + 7) / 8),
1,151✔
55
      m_a_is_minus_3(a == p - 3),
1,151✔
56
      m_a_is_zero(a.is_zero()),
1,151✔
57
      m_has_cofactor(m_cofactor != 1),
1,151✔
58
      m_order_is_less_than_p(m_order < p),
1,151✔
59
      m_source(source) {
3,453✔
60
   // TODO(Botan4) we can assume/assert the OID is set
61
   if(!m_oid.empty()) {
1,151✔
62
      DER_Encoder der(m_der_named_curve);
1,146✔
63
      der.encode(m_oid);
1,146✔
64

65
      const std::string name = m_oid.human_name_or_empty();
1,146✔
66
      if(!name.empty()) {
1,146✔
67
         // returns nullptr if unknown or not supported
68
         m_pcurve = PCurve::PrimeOrderCurve::for_named_curve(name);
1,141✔
69
      }
70
      if(m_pcurve) {
1,146✔
71
         m_engine = EC_Group_Engine::Optimized;
904✔
72
      }
73
   }
1,146✔
74

75
   // Try a generic pcurves instance
76
   if(!m_pcurve && !m_has_cofactor) {
1,151✔
77
      m_pcurve = PCurve::PrimeOrderCurve::from_params(p, a, b, g_x, g_y, order);
246✔
78
      if(m_pcurve) {
246✔
79
         m_engine = EC_Group_Engine::Generic;
147✔
80
      }
81
      // possibly still null here, if parameters unsuitable or if the
82
      // pcurves_generic module wasn't included in the build
83
   }
84

85
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
86
   secure_vector<word> ws;
1,151✔
87
   m_a_r = m_monty.mul(a, m_monty.R2(), ws);
2,302✔
88
   m_b_r = m_monty.mul(b, m_monty.R2(), ws);
2,302✔
89
   if(!m_pcurve) {
1,151✔
90
      m_engine = EC_Group_Engine::Legacy;
100✔
91
   }
92
#else
93
   if(!m_pcurve) {
94
      if(m_oid.empty()) {
95
         throw Not_Implemented("EC_Group this group is not supported in this build configuration");
96
      } else {
97
         throw Not_Implemented(
98
            fmt("EC_Group the group {} is not supported in this build configuration", oid.to_string()));
99
      }
100
   }
101
#endif
102
}
1,151✔
103

104
std::shared_ptr<EC_Group_Data> EC_Group_Data::create(const BigInt& p,
1,151✔
105
                                                     const BigInt& a,
106
                                                     const BigInt& b,
107
                                                     const BigInt& g_x,
108
                                                     const BigInt& g_y,
109
                                                     const BigInt& order,
110
                                                     const BigInt& cofactor,
111
                                                     const OID& oid,
112
                                                     EC_Group_Source source) {
113
   auto group = std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
1,151✔
114

115
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
116
   group->m_curve = CurveGFp(group.get());
1,151✔
117
   group->m_base_point = EC_Point(group->m_curve, g_x, g_y);
2,302✔
118
   if(!group->m_pcurve) {
1,151✔
119
      group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order);
100✔
120
   }
121
#endif
122

123
   return group;
1,151✔
124
}
×
125

126
bool EC_Group_Data::params_match(const BigInt& p,
195✔
127
                                 const BigInt& a,
128
                                 const BigInt& b,
129
                                 const BigInt& g_x,
130
                                 const BigInt& g_y,
131
                                 const BigInt& order,
132
                                 const BigInt& cofactor) const {
133
   if(p != this->p()) {
195✔
134
      return false;
135
   }
136
   if(a != this->a()) {
38✔
137
      return false;
138
   }
139
   if(b != this->b()) {
35✔
140
      return false;
141
   }
142
   if(order != this->order()) {
35✔
143
      return false;
144
   }
145
   if(cofactor != this->cofactor()) {
35✔
146
      return false;
147
   }
148
   if(g_x != this->g_x()) {
35✔
149
      return false;
150
   }
151
   if(g_y != this->g_y()) {
34✔
152
      return false;
153
   }
154

155
   return true;
156
}
157

158
bool EC_Group_Data::params_match(const BigInt& p,
826✔
159
                                 const BigInt& a,
160
                                 const BigInt& b,
161
                                 std::span<const uint8_t> base_pt,
162
                                 const BigInt& order,
163
                                 const BigInt& cofactor) const {
164
   if(p != this->p()) {
826✔
165
      return false;
166
   }
167
   if(a != this->a()) {
79✔
168
      return false;
169
   }
170
   if(b != this->b()) {
74✔
171
      return false;
172
   }
173
   if(order != this->order()) {
67✔
174
      return false;
175
   }
176
   if(cofactor != this->cofactor()) {
64✔
177
      return false;
178
   }
179

180
   const size_t field_len = this->p_bytes();
64✔
181

182
   if(base_pt.size() == 1 + field_len && (base_pt[0] == 0x02 || base_pt[0] == 0x03)) {
64✔
183
      // compressed
184

185
      const auto g_x = m_g_x.serialize(field_len);
×
186
      const auto g_y = m_g_y.is_odd();
×
187

188
      const auto sec1_x = base_pt.subspan(1, field_len);
×
189
      const bool sec1_y = (base_pt[0] == 0x03);
×
190

191
      if(!std::ranges::equal(sec1_x, g_x)) {
×
192
         return false;
193
      }
194

195
      if(sec1_y != g_y) {
×
196
         return false;
197
      }
198

199
      return true;
×
200
   } else if(base_pt.size() == 1 + 2 * field_len && base_pt[0] == 0x04) {
64✔
201
      const auto g_x = m_g_x.serialize(field_len);
63✔
202
      const auto g_y = m_g_y.serialize(field_len);
63✔
203

204
      const auto sec1_x = base_pt.subspan(1, field_len);
63✔
205
      const auto sec1_y = base_pt.subspan(1 + field_len, field_len);
63✔
206

207
      if(!std::ranges::equal(sec1_x, g_x)) {
126✔
208
         return false;
209
      }
210

211
      if(!std::ranges::equal(sec1_y, g_y)) {
177✔
212
         return false;
213
      }
214

215
      return true;
57✔
216
   } else {
126✔
217
      throw Decoding_Error("Invalid base point encoding in explicit group");
1✔
218
   }
219
}
220

221
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
×
222
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
×
223
}
224

225
void EC_Group_Data::set_oid(const OID& oid) {
×
226
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
×
227
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
×
228
   m_oid = oid;
×
229

230
   DER_Encoder der(m_der_named_curve);
×
231
   der.encode(m_oid);
×
232
}
×
233

234
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
30,610✔
235
   const size_t bit_length = 8 * bytes.size();
30,610✔
236

237
   if(bit_length < order_bits()) {
30,610✔
238
      // No shifting required, but might still need to reduce by modulus
239
      return this->scalar_from_bytes_mod_order(bytes);
5,261✔
240
   } else {
241
      const size_t shift = bit_length - order_bits();
25,349✔
242

243
      const size_t new_length = bytes.size() - (shift / 8);
25,349✔
244
      const size_t bit_shift = shift % 8;
25,349✔
245

246
      if(bit_shift == 0) {
25,349✔
247
         // Easy case just read different bytes
248
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
22,709✔
249
      } else {
250
         std::vector<uint8_t> sbytes(new_length);
2,640✔
251

252
         uint8_t carry = 0;
2,640✔
253
         for(size_t i = 0; i != new_length; ++i) {
72,036✔
254
            const uint8_t w = bytes[i];
69,396✔
255
            sbytes[i] = (w >> bit_shift) | carry;
69,396✔
256
            carry = w << (8 - bit_shift);
69,396✔
257
         }
258

259
         return this->scalar_from_bytes_mod_order(sbytes);
2,640✔
260
      }
2,640✔
261
   }
262
}
263

264
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
39,396✔
265
   if(bytes.size() > 2 * order_bytes()) {
39,396✔
266
      return {};
×
267
   }
268

269
   if(m_pcurve) {
39,396✔
270
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
36,576✔
271
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
36,576✔
272
      } else {
273
         return {};
×
274
      }
36,576✔
275
   } else {
276
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
277
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(BigInt(bytes)));
2,820✔
278
#else
279
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
280
#endif
281
   }
282
}
283

284
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
46,145✔
285
   if(m_pcurve) {
46,145✔
286
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
39,946✔
287
   } else {
288
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
289
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
12,398✔
290
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
18,597✔
291
#else
292
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
293
#endif
294
   }
295
}
296

297
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
129✔
298
   if(m_pcurve) {
129✔
299
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
117✔
300
   } else {
301
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
302
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
12✔
303
#else
304
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
305
#endif
306
   }
307
}
308

309
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
4,450✔
310
   if(bn <= 0 || bn >= m_order) {
4,450✔
311
      return {};
×
312
   }
313

314
   if(m_pcurve) {
4,450✔
315
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
8,078✔
316
   } else {
317
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
318
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
411✔
319
#else
320
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
321
#endif
322
   }
323
}
324

325
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar,
6,152✔
326
                                                              RandomNumberGenerator& rng) const {
327
   if(m_pcurve) {
6,152✔
328
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
5,753✔
329
      auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
5,753✔
330
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
5,753✔
331
   } else {
5,753✔
332
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
333
      const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
399✔
334
      BOTAN_STATE_CHECK(m_base_mult != nullptr);
399✔
335
      std::vector<BigInt> ws;
399✔
336
      const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
399✔
337

338
      if(pt.is_zero()) {
798✔
339
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
340
      } else {
341
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
399✔
342
      }
343
#else
344
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
345
#endif
346
   }
399✔
347
}
348

349
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
75,728✔
350
   if(bytes.size() != m_order_bytes) {
75,728✔
351
      return nullptr;
5,896✔
352
   }
353

354
   if(m_pcurve) {
69,832✔
355
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
65,532✔
356
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
63,099✔
357
      } else {
358
         return nullptr;
2,433✔
359
      }
65,532✔
360
   } else {
361
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
362
      BigInt r(bytes);
4,300✔
363

364
      if(r.is_zero() || r >= m_order) {
8,600✔
365
         return nullptr;
428✔
366
      }
367

368
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
3,872✔
369
#else
370
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
371
#endif
372
   }
4,300✔
373
}
374

375
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
47,712✔
376
   // The deprecated "hybrid" point format
377
   // TODO(Botan4) remove this
378
   if(bytes.size() >= 1 + 2 * 4 && (bytes[0] == 0x06 || bytes[0] == 0x07)) {
47,712✔
379
      const bool hdr_y_is_even = bytes[0] == 0x06;
207✔
380
      const bool y_is_even = (bytes.back() & 0x01) == 0;
207✔
381

382
      if(hdr_y_is_even == y_is_even) {
207✔
383
         std::vector<uint8_t> sec1(bytes.begin(), bytes.end());
147✔
384
         sec1[0] = 0x04;
147✔
385
         return this->point_deserialize(sec1);
147✔
386
      }
147✔
387
   }
388

389
   try {
47,565✔
390
      if(m_pcurve) {
47,565✔
391
         if(auto pt = m_pcurve->deserialize_point(bytes)) {
44,803✔
392
            return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
38,484✔
393
         } else {
394
            return {};
6,319✔
395
         }
44,803✔
396
      } else {
397
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
398
         auto pt = Botan::OS2ECP(bytes, m_curve);
2,762✔
399
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
2,706✔
400
#else
401
         throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
402
#endif
403
      }
2,706✔
404
   } catch(...) {
56✔
405
      return {};
56✔
406
   }
56✔
407
}
408

409
namespace {
410

411
std::function<void(std::span<uint8_t>)> h2c_expand_message(std::string_view hash_fn,
43✔
412
                                                           std::span<const uint8_t> input,
413
                                                           std::span<const uint8_t> domain_sep) {
414
   /*
415
   * This could be extended to support expand_message_xof or a MHF like Argon2
416
   */
417

418
   if(hash_fn.starts_with("SHAKE")) {
43✔
419
      throw Not_Implemented("Hash to curve currently does not support expand_message_xof");
×
420
   }
421

422
   return [=](std::span<uint8_t> uniform_bytes) {
129✔
423
#if defined(BOTAN_HAS_XMD)
424
      expand_message_xmd(hash_fn, uniform_bytes, input, domain_sep);
43✔
425
#else
426
      BOTAN_UNUSED(hash_fn, uniform_bytes, input, domain_sep);
427
      throw Not_Implemented("Hash to curve is not implemented due to XMD being disabled");
428
#endif
429
   };
43✔
430
}
431

432
}  // namespace
433

434
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
20✔
435
                                                                           std::span<const uint8_t> input,
436
                                                                           std::span<const uint8_t> domain_sep) const {
437
   if(m_pcurve) {
20✔
438
      auto pt = m_pcurve->hash_to_curve_ro(h2c_expand_message(hash_fn, input, domain_sep));
20✔
439
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
20✔
440
   } else {
20✔
441
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
442
   }
443
}
444

445
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
23✔
446
                                                                           std::span<const uint8_t> input,
447
                                                                           std::span<const uint8_t> domain_sep) const {
448
   if(m_pcurve) {
23✔
449
      auto pt = m_pcurve->hash_to_curve_nu(h2c_expand_message(hash_fn, input, domain_sep));
23✔
450
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
23✔
451
   } else {
23✔
452
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
453
   }
454
}
455

456
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
15,612✔
457
                                                                RandomNumberGenerator& rng) const {
458
   if(m_pcurve) {
15,612✔
459
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
13,737✔
460
      auto pt = m_pcurve->point_to_affine(m_pcurve->mul_by_g(k.value(), rng));
13,737✔
461
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
13,737✔
462
   } else {
13,737✔
463
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
464
      const auto& group = scalar.group();
1,875✔
465
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
1,875✔
466

467
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
1,875✔
468
      std::vector<BigInt> ws;
1,875✔
469
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
1,875✔
470
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,875✔
471
#else
472
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
473
#endif
474
   }
1,875✔
475
}
476

477
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p,
3,472✔
478
                                                              const EC_Scalar_Data& x,
479
                                                              const EC_AffinePoint_Data& q,
480
                                                              const EC_Scalar_Data& y,
481
                                                              RandomNumberGenerator& rng) const {
482
   if(m_pcurve) {
3,472✔
483
      auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(),
6,384✔
484
                                    EC_Scalar_Data_PC::checked_ref(x).value(),
3,192✔
485
                                    EC_AffinePoint_Data_PC::checked_ref(q).value(),
3,192✔
486
                                    EC_Scalar_Data_PC::checked_ref(y).value(),
3,192✔
487
                                    rng);
3,192✔
488

489
      if(pt) {
3,192✔
490
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(*pt));
3,024✔
491
      } else {
492
         return nullptr;
168✔
493
      }
494
   } else {
3,192✔
495
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
496
      std::vector<BigInt> ws;
280✔
497
      const auto& group = p.group();
280✔
498

499
      // TODO this could be better!
500
      const EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws);
280✔
501
      const EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws);
280✔
502

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

505
      auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws);
280✔
506
      auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws);
280✔
507

508
      auto px_qy = px + qy;
280✔
509

510
      if(!px_qy.is_zero()) {
532✔
511
         px_qy.force_affine();
252✔
512
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
252✔
513
      } else {
514
         return nullptr;
28✔
515
      }
516
#else
517
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
518
#endif
519
   }
840✔
520
}
521

522
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p,
7,745✔
523
                                                               const EC_AffinePoint_Data& q) const {
524
   if(m_pcurve) {
7,745✔
525
      auto pt = m_pcurve->point_add(EC_AffinePoint_Data_PC::checked_ref(p).value(),
7,005✔
526
                                    EC_AffinePoint_Data_PC::checked_ref(q).value());
7,005✔
527

528
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
7,004✔
529
   } else {
7,004✔
530
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
531
      auto pt = p.to_legacy_point() + q.to_legacy_point();
740✔
532
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
740✔
533
#else
534
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
535
#endif
536
   }
740✔
537
}
538

539
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const {
9,512✔
540
   if(m_pcurve) {
9,512✔
541
      auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value());
8,454✔
542
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
8,454✔
543
   } else {
8,454✔
544
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
545
      auto pt = p.to_legacy_point();
1,058✔
546
      pt.negate();  // negates in place
1,058✔
547
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,058✔
548
#else
549
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
550
#endif
551
   }
1,058✔
552
}
553

554
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
14,983✔
555
   if(m_pcurve) {
14,983✔
556
      return std::make_unique<EC_Mul2Table_Data_PC>(h);
14,683✔
557
   } else {
558
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
559
      const EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
600✔
560
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
300✔
561
#else
562
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
563
#endif
564
   }
300✔
565
}
566

567
}  // 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

© 2026 Coveralls, Inc