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

randombit / botan / 13128051110

03 Feb 2025 11:15PM UTC coverage: 91.228% (-0.003%) from 91.231%
13128051110

push

github

web-flow
Merge pull request #4630 from randombit/jack/just-for-you-rene

Add EC_Group::engine

94182 of 103238 relevant lines covered (91.23%)

11326744.07 hits per line

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

94.81
/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
namespace Botan {
20

21
EC_Group_Data::~EC_Group_Data() = default;
13,939✔
22

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

59
      if(const auto id = PCurve::PrimeOrderCurveId::from_oid(m_oid)) {
1,152✔
60
         m_pcurve = PCurve::PrimeOrderCurve::from_id(*id);
913✔
61
         if(m_pcurve) {
913✔
62
            m_engine = EC_Group_Engine::Optimized;
913✔
63
         }
64
         // still possibly null, if the curve is supported in general but not
65
         // available in the build
66
      }
67
   }
1,152✔
68

69
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
70
   secure_vector<word> ws;
1,162✔
71
   m_a_r = m_monty.mul(a, m_monty.R2(), ws);
2,324✔
72
   m_b_r = m_monty.mul(b, m_monty.R2(), ws);
2,324✔
73
   if(!m_pcurve) {
1,162✔
74
      m_engine = EC_Group_Engine::Legacy;
249✔
75
   }
76
#else
77
   if(!m_pcurve) {
78
      if(m_oid.empty()) {
79
         throw Not_Implemented("EC_Group this group is not supported in this build configuration");
80
      } else {
81
         throw Not_Implemented(
82
            fmt("EC_Group the group {} is not supported in this build configuration", oid.to_string()));
83
      }
84
   }
85
#endif
86
}
1,162✔
87

88
std::shared_ptr<EC_Group_Data> EC_Group_Data::create(const BigInt& p,
1,162✔
89
                                                     const BigInt& a,
90
                                                     const BigInt& b,
91
                                                     const BigInt& g_x,
92
                                                     const BigInt& g_y,
93
                                                     const BigInt& order,
94
                                                     const BigInt& cofactor,
95
                                                     const OID& oid,
96
                                                     EC_Group_Source source) {
97
   auto group = std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
1,162✔
98

99
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
100
   group->m_curve = CurveGFp(group.get());
1,162✔
101
   group->m_base_point = EC_Point(group->m_curve, g_x, g_y);
2,324✔
102
   if(!group->m_pcurve) {
1,162✔
103
      group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order);
249✔
104
   }
105
#endif
106

107
   return group;
1,162✔
108
}
×
109

110
bool EC_Group_Data::params_match(const BigInt& p,
854✔
111
                                 const BigInt& a,
112
                                 const BigInt& b,
113
                                 const BigInt& g_x,
114
                                 const BigInt& g_y,
115
                                 const BigInt& order,
116
                                 const BigInt& cofactor) const {
117
   return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
946✔
118
           this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
937✔
119
}
120

121
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
19✔
122
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
19✔
123
}
124

125
void EC_Group_Data::set_oid(const OID& oid) {
5✔
126
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
5✔
127
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
5✔
128
   m_oid = oid;
5✔
129

130
   DER_Encoder der(m_der_named_curve);
5✔
131
   der.encode(m_oid);
5✔
132
}
5✔
133

134
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
26,057✔
135
   const size_t bit_length = 8 * bytes.size();
26,057✔
136

137
   if(bit_length < order_bits()) {
26,057✔
138
      // No shifting required, but might still need to reduce by modulus
139
      return this->scalar_from_bytes_mod_order(bytes);
5,258✔
140
   } else {
141
      const size_t shift = bit_length - order_bits();
20,799✔
142

143
      const size_t new_length = bytes.size() - (shift / 8);
20,799✔
144
      const size_t bit_shift = shift % 8;
20,799✔
145

146
      if(bit_shift == 0) {
20,799✔
147
         // Easy case just read different bytes
148
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
18,165✔
149
      } else {
150
         std::vector<uint8_t> sbytes(new_length);
2,634✔
151

152
         uint8_t carry = 0;
2,634✔
153
         for(size_t i = 0; i != new_length; ++i) {
72,006✔
154
            const uint8_t w = bytes[i];
69,372✔
155
            sbytes[i] = (w >> bit_shift) | carry;
69,372✔
156
            carry = w << (8 - bit_shift);
69,372✔
157
         }
158

159
         return this->scalar_from_bytes_mod_order(sbytes);
2,634✔
160
      }
2,634✔
161
   }
162
}
163

164
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
34,770✔
165
   if(bytes.size() > 2 * order_bytes()) {
34,770✔
166
      return {};
×
167
   }
168

169
   if(m_pcurve) {
34,770✔
170
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
23,532✔
171
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
23,532✔
172
      } else {
173
         return {};
×
174
      }
23,532✔
175
   } else {
176
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
177
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(BigInt(bytes)));
22,476✔
178
#else
179
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
180
#endif
181
   }
182
}
183

184
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
44,245✔
185
   if(m_pcurve) {
44,245✔
186
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
19,439✔
187
   } else {
188
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
189
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
49,612✔
190
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
99,224✔
191
#else
192
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
193
#endif
194
   }
195
}
196

197
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_zero() const {
×
198
   if(m_pcurve) {
×
199
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_zero());
×
200
   } else {
201
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
202
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
203
#else
204
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
205
#endif
206
   }
207
}
208

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

221
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
4,481✔
222
   if(bn <= 0 || bn >= m_order) {
4,481✔
223
      return {};
×
224
   }
225

226
   if(m_pcurve) {
4,481✔
227
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
6,746✔
228
   } else {
229
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
230
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
1,108✔
231
#else
232
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
233
#endif
234
   }
235
}
236

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

250
      if(pt.is_zero()) {
3,242✔
251
         return scalar_zero();
×
252
      } else {
253
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
3,242✔
254
      }
255
#else
256
      BOTAN_UNUSED(ws);
257
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
258
#endif
259
   }
1,621✔
260
}
261

262
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
68,620✔
263
   if(bytes.size() != m_order_bytes) {
68,620✔
264
      return nullptr;
5,822✔
265
   }
266

267
   if(m_pcurve) {
62,798✔
268
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
46,900✔
269
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
44,715✔
270
      } else {
271
         return nullptr;
2,185✔
272
      }
46,900✔
273
   } else {
274
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
275
      BigInt r(bytes);
15,898✔
276

277
      if(r.is_zero() || r >= m_order) {
31,796✔
278
         return nullptr;
716✔
279
      }
280

281
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
15,182✔
282
#else
283
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
284
#endif
285
   }
15,898✔
286
}
287

288
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
44,417✔
289
   try {
44,417✔
290
      if(m_pcurve) {
44,417✔
291
         if(auto pt = m_pcurve->deserialize_point(bytes)) {
33,027✔
292
            return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
26,910✔
293
         } else {
294
            return nullptr;
6,117✔
295
         }
33,027✔
296
      } else {
297
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
298
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), bytes);
11,652✔
299
#else
300
         throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
301
#endif
302
      }
303
   } catch(...) {
262✔
304
      return nullptr;
262✔
305
   }
262✔
306
}
307

308
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
24✔
309
                                                                           std::span<const uint8_t> input,
310
                                                                           std::span<const uint8_t> domain_sep) const {
311
   if(m_pcurve) {
24✔
312
      auto pt = m_pcurve->hash_to_curve_ro(hash_fn, input, domain_sep);
24✔
313
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
24✔
314
   } else {
24✔
315
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
316
   }
317
}
318

319
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
33✔
320
                                                                           std::span<const uint8_t> input,
321
                                                                           std::span<const uint8_t> domain_sep) const {
322
   if(m_pcurve) {
33✔
323
      auto pt = m_pcurve->hash_to_curve_nu(hash_fn, input, domain_sep);
33✔
324
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
30✔
325
   } else {
30✔
326
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
327
   }
328
}
329

330
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
15,363✔
331
                                                                RandomNumberGenerator& rng,
332
                                                                std::vector<BigInt>& ws) const {
333
   if(m_pcurve) {
15,363✔
334
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
7,970✔
335
      auto pt = m_pcurve->mul_by_g(k.value(), rng).to_affine();
15,940✔
336
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
7,970✔
337
   } else {
7,970✔
338
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
339
      const auto& group = scalar.group();
7,393✔
340
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
7,393✔
341

342
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
7,393✔
343
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
7,393✔
344
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
7,393✔
345
#else
346
      BOTAN_UNUSED(ws);
347
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
348
#endif
349
   }
7,393✔
350
}
351

352
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p,
3,472✔
353
                                                              const EC_Scalar_Data& x,
354
                                                              const EC_AffinePoint_Data& q,
355
                                                              const EC_Scalar_Data& y,
356
                                                              RandomNumberGenerator& rng) const {
357
   if(m_pcurve) {
3,472✔
358
      auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(),
5,208✔
359
                                    EC_Scalar_Data_PC::checked_ref(x).value(),
2,604✔
360
                                    EC_AffinePoint_Data_PC::checked_ref(q).value(),
2,604✔
361
                                    EC_Scalar_Data_PC::checked_ref(y).value(),
2,604✔
362
                                    rng);
2,604✔
363

364
      if(pt) {
2,604✔
365
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt->to_affine());
2,520✔
366
      } else {
367
         return nullptr;
84✔
368
      }
369
   } else {
2,604✔
370
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
371
      std::vector<BigInt> ws;
868✔
372
      const auto& group = p.group();
868✔
373

374
      // TODO this could be better!
375
      EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws);
868✔
376
      EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws);
868✔
377

378
      const auto order = group->order() * group->cofactor();  // See #3800
868✔
379

380
      auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws);
868✔
381
      auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws);
868✔
382

383
      auto px_qy = px + qy;
868✔
384

385
      if(!px_qy.is_zero()) {
1,624✔
386
         px_qy.force_affine();
756✔
387
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
756✔
388
      } else {
389
         return nullptr;
112✔
390
      }
391
#else
392
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
393
#endif
394
   }
3,472✔
395
}
396

397
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p,
7,753✔
398
                                                               const EC_AffinePoint_Data& q) const {
399
   if(m_pcurve) {
7,753✔
400
      auto pt = m_pcurve->point_add_mixed(
5,045✔
401
         PCurve::PrimeOrderCurve::ProjectivePoint::from_affine(EC_AffinePoint_Data_PC::checked_ref(p).value()),
5,046✔
402
         EC_AffinePoint_Data_PC::checked_ref(q).value());
10,090✔
403

404
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
5,044✔
405
   } else {
5,044✔
406
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
407
      auto pt = p.to_legacy_point() + q.to_legacy_point();
2,708✔
408
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
2,708✔
409
#else
410
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
411
#endif
412
   }
2,708✔
413
}
414

415
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const {
9,512✔
416
   if(m_pcurve) {
9,512✔
417
      auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value());
6,312✔
418
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
6,312✔
419
   } else {
6,312✔
420
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
421
      auto pt = p.to_legacy_point();
3,200✔
422
      pt.negate();  // negates in place
3,200✔
423
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
3,200✔
424
#else
425
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
426
#endif
427
   }
3,200✔
428
}
429

430
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
13,257✔
431
   if(m_pcurve) {
13,257✔
432
      return std::make_unique<EC_Mul2Table_Data_PC>(h);
11,176✔
433
   } else {
434
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
435
      EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
4,162✔
436
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
2,081✔
437
#else
438
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
439
#endif
440
   }
2,081✔
441
}
442

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