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

randombit / botan / 13471882073

22 Feb 2025 10:03AM UTC coverage: 91.691% (+0.03%) from 91.665%
13471882073

push

github

web-flow
Merge pull request #4554 from randombit/jack/pcurves-generic

Add generic pcurves for application specific curves

95806 of 104488 relevant lines covered (91.69%)

11387702.61 hits per line

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

92.54
/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

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

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

23
namespace Botan {
24

25
EC_Group_Data::~EC_Group_Data() = default;
5,772✔
26

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

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

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

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

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

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

122
   return group;
1,155✔
123
}
×
124

125
bool EC_Group_Data::params_match(const BigInt& p,
777✔
126
                                 const BigInt& a,
127
                                 const BigInt& b,
128
                                 const BigInt& g_x,
129
                                 const BigInt& g_y,
130
                                 const BigInt& order,
131
                                 const BigInt& cofactor) const {
132
   return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
878✔
133
           this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
869✔
134
}
135

136
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
×
137
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
×
138
}
139

140
void EC_Group_Data::set_oid(const OID& oid) {
×
141
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
×
142
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
×
143
   m_oid = oid;
×
144

145
   DER_Encoder der(m_der_named_curve);
×
146
   der.encode(m_oid);
×
147
}
×
148

149
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
26,074✔
150
   const size_t bit_length = 8 * bytes.size();
26,074✔
151

152
   if(bit_length < order_bits()) {
26,074✔
153
      // No shifting required, but might still need to reduce by modulus
154
      return this->scalar_from_bytes_mod_order(bytes);
5,248✔
155
   } else {
156
      const size_t shift = bit_length - order_bits();
20,826✔
157

158
      const size_t new_length = bytes.size() - (shift / 8);
20,826✔
159
      const size_t bit_shift = shift % 8;
20,826✔
160

161
      if(bit_shift == 0) {
20,826✔
162
         // Easy case just read different bytes
163
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
18,167✔
164
      } else {
165
         std::vector<uint8_t> sbytes(new_length);
2,659✔
166

167
         uint8_t carry = 0;
2,659✔
168
         for(size_t i = 0; i != new_length; ++i) {
72,637✔
169
            const uint8_t w = bytes[i];
69,978✔
170
            sbytes[i] = (w >> bit_shift) | carry;
69,978✔
171
            carry = w << (8 - bit_shift);
69,978✔
172
         }
173

174
         return this->scalar_from_bytes_mod_order(sbytes);
2,659✔
175
      }
2,659✔
176
   }
177
}
178

179
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
34,790✔
180
   if(bytes.size() > 2 * order_bytes()) {
34,790✔
181
      return {};
×
182
   }
183

184
   if(m_pcurve) {
34,790✔
185
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
31,970✔
186
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
31,970✔
187
      } else {
188
         return {};
×
189
      }
31,970✔
190
   } else {
191
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
192
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(BigInt(bytes)));
2,820✔
193
#else
194
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
195
#endif
196
   }
197
}
198

199
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
44,362✔
200
   if(m_pcurve) {
44,362✔
201
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
76,342✔
202
   } else {
203
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
204
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
12,382✔
205
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
18,573✔
206
#else
207
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
208
#endif
209
   }
210
}
211

212
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
101✔
213
   if(m_pcurve) {
101✔
214
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
93✔
215
   } else {
216
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
217
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
8✔
218
#else
219
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
220
#endif
221
   }
222
}
223

224
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
4,484✔
225
   if(bn <= 0 || bn >= m_order) {
4,484✔
226
      return {};
×
227
   }
228

229
   if(m_pcurve) {
4,484✔
230
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
8,146✔
231
   } else {
232
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
233
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
411✔
234
#else
235
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
236
#endif
237
   }
238
}
239

240
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar,
3,312✔
241
                                                              RandomNumberGenerator& rng,
242
                                                              std::vector<BigInt>& ws) const {
243
   if(m_pcurve) {
3,312✔
244
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
2,913✔
245
      auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
2,913✔
246
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
2,913✔
247
   } else {
2,913✔
248
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
249
      const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
399✔
250
      BOTAN_STATE_CHECK(m_base_mult != nullptr);
399✔
251
      const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
399✔
252

253
      if(pt.is_zero()) {
798✔
254
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
255
      } else {
256
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
399✔
257
      }
258
#else
259
      BOTAN_UNUSED(ws);
260
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
261
#endif
262
   }
399✔
263
}
264

265
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
69,377✔
266
   if(bytes.size() != m_order_bytes) {
69,377✔
267
      return nullptr;
5,816✔
268
   }
269

270
   if(m_pcurve) {
63,561✔
271
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
59,233✔
272
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
56,817✔
273
      } else {
274
         return nullptr;
2,416✔
275
      }
59,233✔
276
   } else {
277
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
278
      BigInt r(bytes);
4,328✔
279

280
      if(r.is_zero() || r >= m_order) {
8,656✔
281
         return nullptr;
456✔
282
      }
283

284
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
3,872✔
285
#else
286
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
287
#endif
288
   }
4,328✔
289
}
290

291
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
44,555✔
292
   // The deprecated "hybrid" point format
293
   // TODO(Botan4) remove this
294
   if(bytes.size() >= 1 + 2 * 4 && (bytes[0] == 0x06 || bytes[0] == 0x07)) {
44,555✔
295
      bool hdr_y_is_even = bytes[0] == 0x06;
207✔
296
      bool y_is_even = (bytes.back() & 0x01) == 0;
207✔
297

298
      if(hdr_y_is_even == y_is_even) {
207✔
299
         std::vector<uint8_t> sec1(bytes.begin(), bytes.end());
147✔
300
         sec1[0] = 0x04;
147✔
301
         return this->point_deserialize(sec1);
147✔
302
      }
147✔
303
   }
304

305
   try {
44,408✔
306
      if(m_pcurve) {
44,408✔
307
         if(auto pt = m_pcurve->deserialize_point(bytes)) {
41,654✔
308
            return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
35,335✔
309
         } else {
310
            return {};
6,319✔
311
         }
41,654✔
312
      } else {
313
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
314
         auto pt = Botan::OS2ECP(bytes, m_curve);
2,754✔
315
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
2,698✔
316
#else
317
         throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
318
#endif
319
      }
2,698✔
320
   } catch(...) {
56✔
321
      return {};
56✔
322
   }
56✔
323
}
324

325
namespace {
326

327
std::function<void(std::span<uint8_t>)> h2c_expand_message(std::string_view hash_fn,
57✔
328
                                                           std::span<const uint8_t> input,
329
                                                           std::span<const uint8_t> domain_sep) {
330
   /*
331
   * This could be extended to support expand_message_xof or a MHF like Argon2
332
   */
333

334
   if(hash_fn.starts_with("SHAKE")) {
57✔
335
      throw Not_Implemented("Hash to curve currently does not support expand_message_xof");
×
336
   }
337

338
   return [=](std::span<uint8_t> uniform_bytes) {
168✔
339
#if defined(BOTAN_HAS_XMD)
340
      expand_message_xmd(hash_fn, uniform_bytes, input, domain_sep);
54✔
341
#else
342
      BOTAN_UNUSED(hash_fn, uniform_bytes, input, domain_sep);
343
      throw Not_Implemented("Hash to curve is not implemented due to XMD being disabled");
344
#endif
345
   };
57✔
346
}
347

348
}  // namespace
349

350
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
24✔
351
                                                                           std::span<const uint8_t> input,
352
                                                                           std::span<const uint8_t> domain_sep) const {
353
   if(m_pcurve) {
24✔
354
      auto pt = m_pcurve->hash_to_curve_ro(h2c_expand_message(hash_fn, input, domain_sep));
24✔
355
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
24✔
356
   } else {
24✔
357
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
358
   }
359
}
360

361
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
33✔
362
                                                                           std::span<const uint8_t> input,
363
                                                                           std::span<const uint8_t> domain_sep) const {
364
   if(m_pcurve) {
33✔
365
      auto pt = m_pcurve->hash_to_curve_nu(h2c_expand_message(hash_fn, input, domain_sep));
36✔
366
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
30✔
367
   } else {
30✔
368
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
369
   }
370
}
371

372
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
15,369✔
373
                                                                RandomNumberGenerator& rng,
374
                                                                std::vector<BigInt>& ws) const {
375
   if(m_pcurve) {
15,369✔
376
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
13,498✔
377
      auto pt = m_pcurve->point_to_affine(m_pcurve->mul_by_g(k.value(), rng));
13,498✔
378
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
13,498✔
379
   } else {
13,498✔
380
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
381
      const auto& group = scalar.group();
1,871✔
382
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
1,871✔
383

384
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
1,871✔
385
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
1,871✔
386
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,871✔
387
#else
388
      BOTAN_UNUSED(ws);
389
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
390
#endif
391
   }
1,871✔
392
}
393

394
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p,
3,472✔
395
                                                              const EC_Scalar_Data& x,
396
                                                              const EC_AffinePoint_Data& q,
397
                                                              const EC_Scalar_Data& y,
398
                                                              RandomNumberGenerator& rng) const {
399
   if(m_pcurve) {
3,472✔
400
      auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(),
6,384✔
401
                                    EC_Scalar_Data_PC::checked_ref(x).value(),
3,192✔
402
                                    EC_AffinePoint_Data_PC::checked_ref(q).value(),
3,192✔
403
                                    EC_Scalar_Data_PC::checked_ref(y).value(),
3,192✔
404
                                    rng);
3,192✔
405

406
      if(pt) {
3,192✔
407
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(*pt));
3,024✔
408
      } else {
409
         return nullptr;
168✔
410
      }
411
   } else {
3,192✔
412
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
413
      std::vector<BigInt> ws;
280✔
414
      const auto& group = p.group();
280✔
415

416
      // TODO this could be better!
417
      EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws);
280✔
418
      EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws);
280✔
419

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

422
      auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws);
280✔
423
      auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws);
280✔
424

425
      auto px_qy = px + qy;
280✔
426

427
      if(!px_qy.is_zero()) {
532✔
428
         px_qy.force_affine();
252✔
429
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
252✔
430
      } else {
431
         return nullptr;
28✔
432
      }
433
#else
434
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
435
#endif
436
   }
840✔
437
}
438

439
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p,
7,753✔
440
                                                               const EC_AffinePoint_Data& q) const {
441
   if(m_pcurve) {
7,753✔
442
      auto pt = m_pcurve->point_add(EC_AffinePoint_Data_PC::checked_ref(p).value(),
7,013✔
443
                                    EC_AffinePoint_Data_PC::checked_ref(q).value());
7,013✔
444

445
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
7,012✔
446
   } else {
7,012✔
447
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
448
      auto pt = p.to_legacy_point() + q.to_legacy_point();
740✔
449
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
740✔
450
#else
451
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
452
#endif
453
   }
740✔
454
}
455

456
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const {
9,512✔
457
   if(m_pcurve) {
9,512✔
458
      auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value());
8,454✔
459
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
8,454✔
460
   } else {
8,454✔
461
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
462
      auto pt = p.to_legacy_point();
1,058✔
463
      pt.negate();  // negates in place
1,058✔
464
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,058✔
465
#else
466
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
467
#endif
468
   }
1,058✔
469
}
470

471
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
13,256✔
472
   if(m_pcurve) {
13,256✔
473
      return std::make_unique<EC_Mul2Table_Data_PC>(h);
12,956✔
474
   } else {
475
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
476
      EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
600✔
477
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
300✔
478
#else
479
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
480
#endif
481
   }
300✔
482
}
483

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