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

randombit / botan / 22219971043

20 Feb 2026 10:10AM UTC coverage: 90.331% (+0.001%) from 90.33%
22219971043

Pull #5356

github

web-flow
Merge fc5a2e175 into 2cf293ee6
Pull Request #5356: Refactor: Generalize the SEC.1 decoder

103030 of 114058 relevant lines covered (90.33%)

11449806.04 hits per line

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

91.46
/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/ec_sec1.h>
12
#include <botan/internal/fmt.h>
13
#include <botan/internal/pcurves.h>
14
#include <botan/internal/stl_util.h>
15
#include <algorithm>
16

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

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

26
namespace Botan {
27

28
EC_Group_Data::~EC_Group_Data() = default;
7,020✔
29

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

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

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

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

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

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

125
   return group;
1,171✔
126
}
×
127

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

157
   return true;
158
}
159

160
bool EC_Group_Data::params_match(const BigInt& p,
863✔
161
                                 const BigInt& a,
162
                                 const BigInt& b,
163
                                 std::span<const uint8_t> base_pt,
164
                                 const BigInt& order,
165
                                 const BigInt& cofactor) const {
166
   if(p != this->p()) {
863✔
167
      return false;
168
   }
169
   if(a != this->a()) {
77✔
170
      return false;
171
   }
172
   if(b != this->b()) {
72✔
173
      return false;
174
   }
175
   if(order != this->order()) {
130✔
176
      return false;
177
   }
178
   if(cofactor != this->cofactor()) {
63✔
179
      return false;
180
   }
181

182
   const size_t field_len = this->p_bytes();
63✔
183
   const auto base_pt_okay =
63✔
184
      sec1_decode(base_pt,
63✔
185
                  field_len,
186
                  overloaded{
187
                     [](const SEC1_Identity) -> bool { throw Decoding_Error("Identity is not a valid base point"); },
×
188
                     [&](const SEC1_Compressed compressed) {
×
189
                        return std::ranges::equal(compressed.x, m_g_x.serialize(field_len)) &&
×
190
                               compressed.y_is_even.as_bool() == m_g_y.is_even();
×
191
                     },
192
                     [&](const SEC1_Full full) {
62✔
193
                        return std::ranges::equal(full.x, m_g_x.serialize(field_len)) &&
181✔
194
                               std::ranges::equal(full.y, m_g_y.serialize(field_len));
295✔
195
                     },
196
                  });
197

198
   if(!base_pt_okay.has_value() /* SEC1 parsing failed */) {
63✔
199
      throw Decoding_Error("Invalid base point encoding in explicit group");
1✔
200
   }
201

202
   return *base_pt_okay;
62✔
203
}
204

205
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
×
206
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
×
207
}
208

209
void EC_Group_Data::set_oid(const OID& oid) {
×
210
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
×
211
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
×
212
   m_oid = oid;
×
213

214
   DER_Encoder der(m_der_named_curve);
×
215
   der.encode(m_oid);
×
216
}
×
217

218
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
30,744✔
219
   const size_t bit_length = 8 * bytes.size();
30,744✔
220

221
   if(bit_length < order_bits()) {
30,744✔
222
      // No shifting required, but might still need to reduce by modulus
223
      return this->scalar_from_bytes_mod_order(bytes);
5,266✔
224
   } else {
225
      const size_t shift = bit_length - order_bits();
25,478✔
226

227
      const size_t new_length = bytes.size() - (shift / 8);
25,478✔
228
      const size_t bit_shift = shift % 8;
25,478✔
229

230
      if(bit_shift == 0) {
25,478✔
231
         // Easy case just read different bytes
232
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
22,848✔
233
      } else {
234
         std::vector<uint8_t> sbytes(new_length);
2,630✔
235

236
         uint8_t carry = 0;
2,630✔
237
         for(size_t i = 0; i != new_length; ++i) {
71,773✔
238
            const uint8_t w = bytes[i];
69,143✔
239
            sbytes[i] = (w >> bit_shift) | carry;
69,143✔
240
            carry = w << (8 - bit_shift);
69,143✔
241
         }
242

243
         return this->scalar_from_bytes_mod_order(sbytes);
2,630✔
244
      }
2,630✔
245
   }
246
}
247

248
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
39,654✔
249
   if(bytes.size() > 2 * order_bytes()) {
39,654✔
250
      return {};
×
251
   }
252

253
   if(m_pcurve) {
39,654✔
254
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
36,837✔
255
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
36,837✔
256
      } else {
257
         return {};
×
258
      }
36,837✔
259
   } else {
260
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
261
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(BigInt(bytes)));
2,817✔
262
#else
263
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
264
#endif
265
   }
266
}
267

268
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
46,493✔
269
   if(m_pcurve) {
46,493✔
270
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
40,294✔
271
   } else {
272
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
273
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
12,398✔
274
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
18,597✔
275
#else
276
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
277
#endif
278
   }
279
}
280

281
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
141✔
282
   if(m_pcurve) {
141✔
283
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
129✔
284
   } else {
285
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
286
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
12✔
287
#else
288
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
289
#endif
290
   }
291
}
292

293
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
4,482✔
294
   if(bn <= 0 || bn >= m_order) {
4,482✔
295
      return {};
×
296
   }
297

298
   if(m_pcurve) {
4,482✔
299
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
8,142✔
300
   } else {
301
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
302
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
411✔
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::gk_x_mod_order(const EC_Scalar_Data& scalar,
6,222✔
310
                                                              RandomNumberGenerator& rng) const {
311
   if(m_pcurve) {
6,222✔
312
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
5,823✔
313
      auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
5,823✔
314
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
5,823✔
315
   } else {
5,823✔
316
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
317
      const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
399✔
318
      BOTAN_STATE_CHECK(m_base_mult != nullptr);
399✔
319
      std::vector<BigInt> ws;
399✔
320
      const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
399✔
321

322
      if(pt.is_zero()) {
798✔
323
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
324
      } else {
325
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
399✔
326
      }
327
#else
328
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
329
#endif
330
   }
399✔
331
}
332

333
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
76,097✔
334
   if(bytes.size() != m_order_bytes) {
76,097✔
335
      return nullptr;
5,896✔
336
   }
337

338
   if(m_pcurve) {
70,201✔
339
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
65,866✔
340
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
63,435✔
341
      } else {
342
         return nullptr;
2,431✔
343
      }
65,866✔
344
   } else {
345
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
346
      BigInt r(bytes);
4,335✔
347

348
      if(r.is_zero() || r >= m_order) {
8,670✔
349
         return nullptr;
466✔
350
      }
351

352
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
3,869✔
353
#else
354
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
355
#endif
356
   }
4,335✔
357
}
358

359
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
47,613✔
360
   try {
47,613✔
361
      if(m_pcurve) {
47,613✔
362
         if(auto pt = m_pcurve->deserialize_point(bytes)) {
44,850✔
363
            return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
38,515✔
364
         } else {
365
            return {};
6,335✔
366
         }
44,850✔
367
      } else {
368
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
369
         auto pt = Botan::OS2ECP(bytes, m_curve);
2,763✔
370
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
2,707✔
371
#else
372
         throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
373
#endif
374
      }
2,707✔
375
   } catch(...) {
56✔
376
      return {};
56✔
377
   }
56✔
378
}
379

380
namespace {
381

382
std::function<void(std::span<uint8_t>)> h2c_expand_message(std::string_view hash_fn,
61✔
383
                                                           std::span<const uint8_t> input,
384
                                                           std::span<const uint8_t> domain_sep) {
385
   /*
386
   * This could be extended to support expand_message_xof or a MHF like Argon2
387
   */
388

389
   if(hash_fn.starts_with("SHAKE")) {
61✔
390
      throw Not_Implemented("Hash to curve currently does not support expand_message_xof");
×
391
   }
392

393
   return [=](std::span<uint8_t> uniform_bytes) {
180✔
394
#if defined(BOTAN_HAS_XMD)
395
      expand_message_xmd(hash_fn, uniform_bytes, input, domain_sep);
58✔
396
#else
397
      BOTAN_UNUSED(hash_fn, uniform_bytes, input, domain_sep);
398
      throw Not_Implemented("Hash to curve is not implemented due to XMD being disabled");
399
#endif
400
   };
61✔
401
}
402

403
}  // namespace
404

405
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
26✔
406
                                                                           std::span<const uint8_t> input,
407
                                                                           std::span<const uint8_t> domain_sep) const {
408
   if(m_pcurve) {
26✔
409
      auto pt = m_pcurve->hash_to_curve_ro(h2c_expand_message(hash_fn, input, domain_sep));
26✔
410
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
26✔
411
   } else {
26✔
412
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
413
   }
414
}
415

416
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
35✔
417
                                                                           std::span<const uint8_t> input,
418
                                                                           std::span<const uint8_t> domain_sep) const {
419
   if(m_pcurve) {
35✔
420
      auto pt = m_pcurve->hash_to_curve_nu(h2c_expand_message(hash_fn, input, domain_sep));
38✔
421
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
32✔
422
   } else {
32✔
423
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
424
   }
425
}
426

427
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
15,714✔
428
                                                                RandomNumberGenerator& rng) const {
429
   if(m_pcurve) {
15,714✔
430
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
13,839✔
431
      auto pt = m_pcurve->point_to_affine(m_pcurve->mul_by_g(k.value(), rng));
13,839✔
432
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
13,839✔
433
   } else {
13,839✔
434
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
435
      const auto& group = scalar.group();
1,875✔
436
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
1,875✔
437

438
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
1,875✔
439
      std::vector<BigInt> ws;
1,875✔
440
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
1,875✔
441
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,875✔
442
#else
443
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
444
#endif
445
   }
1,875✔
446
}
447

448
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p,
3,482✔
449
                                                              const EC_Scalar_Data& x,
450
                                                              const EC_AffinePoint_Data& q,
451
                                                              const EC_Scalar_Data& y,
452
                                                              RandomNumberGenerator& rng) const {
453
   if(m_pcurve) {
3,482✔
454
      auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(),
6,404✔
455
                                    EC_Scalar_Data_PC::checked_ref(x).value(),
3,202✔
456
                                    EC_AffinePoint_Data_PC::checked_ref(q).value(),
3,202✔
457
                                    EC_Scalar_Data_PC::checked_ref(y).value(),
3,202✔
458
                                    rng);
3,202✔
459

460
      if(pt) {
3,202✔
461
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(*pt));
3,034✔
462
      } else {
463
         return nullptr;
168✔
464
      }
465
   } else {
3,202✔
466
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
467
      std::vector<BigInt> ws;
280✔
468
      const auto& group = p.group();
280✔
469

470
      // TODO this could be better!
471
      const EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws);
280✔
472
      const EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws);
280✔
473

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

476
      auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws);
280✔
477
      auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws);
280✔
478

479
      auto px_qy = px + qy;
280✔
480

481
      if(!px_qy.is_zero()) {
532✔
482
         px_qy.force_affine();
252✔
483
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
252✔
484
      } else {
485
         return nullptr;
28✔
486
      }
487
#else
488
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
489
#endif
490
   }
840✔
491
}
492

493
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p,
7,755✔
494
                                                               const EC_AffinePoint_Data& q) const {
495
   if(m_pcurve) {
7,755✔
496
      auto pt = m_pcurve->point_add(EC_AffinePoint_Data_PC::checked_ref(p).value(),
7,015✔
497
                                    EC_AffinePoint_Data_PC::checked_ref(q).value());
7,015✔
498

499
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
7,014✔
500
   } else {
7,014✔
501
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
502
      auto pt = p.to_legacy_point() + q.to_legacy_point();
740✔
503
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
740✔
504
#else
505
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
506
#endif
507
   }
740✔
508
}
509

510
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const {
9,512✔
511
   if(m_pcurve) {
9,512✔
512
      auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value());
8,454✔
513
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
8,454✔
514
   } else {
8,454✔
515
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
516
      auto pt = p.to_legacy_point();
1,058✔
517
      pt.negate();  // negates in place
1,058✔
518
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,058✔
519
#else
520
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
521
#endif
522
   }
1,058✔
523
}
524

525
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
15,098✔
526
   if(m_pcurve) {
15,098✔
527
      return std::make_unique<EC_Mul2Table_Data_PC>(h);
14,798✔
528
   } else {
529
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
530
      const EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
600✔
531
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
300✔
532
#else
533
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
534
#endif
535
   }
300✔
536
}
537

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