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

randombit / botan / 12781227458

14 Jan 2025 11:56PM UTC coverage: 91.197% (-0.004%) from 91.201%
12781227458

push

github

web-flow
Merge pull request #4552 from randombit/jack/ec-disabled

In EC_Group throw immediately if encountering an unsupported group

93405 of 102421 relevant lines covered (91.2%)

11440676.72 hits per line

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

94.74
/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/pcurves.h>
12

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

18
namespace Botan {
19

20
EC_Group_Data::~EC_Group_Data() = default;
13,938✔
21

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

57
      if(const auto id = PCurve::PrimeOrderCurveId::from_oid(m_oid)) {
1,150✔
58
         m_pcurve = PCurve::PrimeOrderCurve::from_id(*id);
910✔
59
         // still possibly null, if the curve is supported in general but not
60
         // available in the build
61
      }
62
   }
1,150✔
63

64
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
65
   secure_vector<word> ws;
1,162✔
66
   m_a_r = m_monty.mul(a, m_monty.R2(), ws);
2,324✔
67
   m_b_r = m_monty.mul(b, m_monty.R2(), ws);
2,324✔
68
#else
69
   if(!m_pcurve) {
70
      throw Not_Implemented("EC_Group this group is not supported unless legacy_ec_point is included in the build");
71
   }
72
#endif
73
}
1,162✔
74

75
std::shared_ptr<EC_Group_Data> EC_Group_Data::create(const BigInt& p,
1,162✔
76
                                                     const BigInt& a,
77
                                                     const BigInt& b,
78
                                                     const BigInt& g_x,
79
                                                     const BigInt& g_y,
80
                                                     const BigInt& order,
81
                                                     const BigInt& cofactor,
82
                                                     const OID& oid,
83
                                                     EC_Group_Source source) {
84
   auto group = std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
1,162✔
85

86
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
87
   group->m_curve = CurveGFp(group.get());
1,162✔
88
   group->m_base_point = EC_Point(group->m_curve, g_x, g_y);
3,486✔
89
   if(!group->m_pcurve) {
1,162✔
90
      group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order);
252✔
91
   }
92
#endif
93

94
   return group;
1,162✔
95
}
×
96

97
bool EC_Group_Data::params_match(const BigInt& p,
933✔
98
                                 const BigInt& a,
99
                                 const BigInt& b,
100
                                 const BigInt& g_x,
101
                                 const BigInt& g_y,
102
                                 const BigInt& order,
103
                                 const BigInt& cofactor) const {
104
   return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
1,030✔
105
           this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
1,021✔
106
}
107

108
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
20✔
109
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
20✔
110
}
111

112
void EC_Group_Data::set_oid(const OID& oid) {
6✔
113
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
6✔
114
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
6✔
115
   m_oid = oid;
6✔
116

117
   DER_Encoder der(m_der_named_curve);
6✔
118
   der.encode(m_oid);
6✔
119
}
6✔
120

121
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
26,027✔
122
   const size_t bit_length = 8 * bytes.size();
26,027✔
123

124
   if(bit_length < order_bits()) {
26,027✔
125
      // No shifting required, but might still need to reduce by modulus
126
      return this->scalar_from_bytes_mod_order(bytes);
5,254✔
127
   } else {
128
      const size_t shift = bit_length - order_bits();
20,773✔
129

130
      const size_t new_length = bytes.size() - (shift / 8);
20,773✔
131
      const size_t bit_shift = shift % 8;
20,773✔
132

133
      if(bit_shift == 0) {
20,773✔
134
         // Easy case just read different bytes
135
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
18,146✔
136
      } else {
137
         std::vector<uint8_t> sbytes(new_length);
2,627✔
138

139
         uint8_t carry = 0;
2,627✔
140
         for(size_t i = 0; i != new_length; ++i) {
71,784✔
141
            const uint8_t w = bytes[i];
69,157✔
142
            sbytes[i] = (w >> bit_shift) | carry;
69,157✔
143
            carry = w << (8 - bit_shift);
69,157✔
144
         }
145

146
         return this->scalar_from_bytes_mod_order(sbytes);
2,627✔
147
      }
2,627✔
148
   }
149
}
150

151
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
34,460✔
152
   if(bytes.size() > 2 * order_bytes()) {
34,460✔
153
      return {};
×
154
   }
155

156
   if(m_pcurve) {
34,460✔
157
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
23,399✔
158
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
23,399✔
159
      } else {
160
         return {};
×
161
      }
23,399✔
162
   } else {
163
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
164
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(BigInt(bytes)));
33,183✔
165
#else
166
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
167
#endif
168
   }
169
}
170

171
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
44,214✔
172
   if(m_pcurve) {
44,214✔
173
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
19,424✔
174
   } else {
175
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
176
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
49,580✔
177
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
99,160✔
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_zero() const {
×
185
   if(m_pcurve) {
×
186
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_zero());
×
187
   } else {
188
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
189
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
190
#else
191
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
192
#endif
193
   }
194
}
195

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

208
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
6,374✔
209
   if(bn <= 0 || bn >= m_order) {
6,374✔
210
      return {};
×
211
   }
212

213
   if(m_pcurve) {
6,374✔
214
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
10,126✔
215
   } else {
216
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
217
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
1,311✔
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::gk_x_mod_order(const EC_Scalar_Data& scalar,
3,305✔
225
                                                              RandomNumberGenerator& rng,
226
                                                              std::vector<BigInt>& ws) const {
227
   if(m_pcurve) {
3,305✔
228
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
1,684✔
229
      auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
1,684✔
230
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
1,684✔
231
   } else {
1,684✔
232
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
233
      const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
1,621✔
234
      BOTAN_STATE_CHECK(m_base_mult != nullptr);
1,621✔
235
      const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
1,621✔
236

237
      if(pt.is_zero()) {
3,242✔
238
         return scalar_zero();
×
239
      } else {
240
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(pt.get_affine_x()));
4,863✔
241
      }
242
#else
243
      BOTAN_UNUSED(ws);
244
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
245
#endif
246
   }
1,621✔
247
}
248

249
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
69,171✔
250
   if(bytes.size() != m_order_bytes) {
69,171✔
251
      return nullptr;
5,858✔
252
   }
253

254
   if(m_pcurve) {
63,313✔
255
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
47,477✔
256
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
45,243✔
257
      } else {
258
         return nullptr;
2,234✔
259
      }
47,477✔
260
   } else {
261
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
262
      BigInt r(bytes);
15,836✔
263

264
      if(r.is_zero() || r >= m_order) {
31,672✔
265
         return nullptr;
695✔
266
      }
267

268
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
15,141✔
269
#else
270
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
271
#endif
272
   }
15,836✔
273
}
274

275
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
41,834✔
276
   try {
41,834✔
277
      if(m_pcurve) {
41,834✔
278
         if(auto pt = m_pcurve->deserialize_point(bytes)) {
31,844✔
279
            return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
25,727✔
280
         } else {
281
            return nullptr;
6,117✔
282
         }
31,844✔
283
      } else {
284
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
285
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), bytes);
10,243✔
286
#else
287
         throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
288
#endif
289
      }
290
   } catch(...) {
253✔
291
      return nullptr;
253✔
292
   }
253✔
293
}
294

295
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
25✔
296
                                                                           std::span<const uint8_t> input,
297
                                                                           std::span<const uint8_t> domain_sep) const {
298
   if(m_pcurve) {
25✔
299
      auto pt = m_pcurve->hash_to_curve_ro(hash_fn, input, domain_sep);
25✔
300
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
25✔
301
   } else {
25✔
302
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
303
   }
304
}
305

306
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
34✔
307
                                                                           std::span<const uint8_t> input,
308
                                                                           std::span<const uint8_t> domain_sep) const {
309
   if(m_pcurve) {
34✔
310
      auto pt = m_pcurve->hash_to_curve_nu(hash_fn, input, domain_sep);
34✔
311
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
31✔
312
   } else {
31✔
313
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
314
   }
315
}
316

317
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
15,866✔
318
                                                                RandomNumberGenerator& rng,
319
                                                                std::vector<BigInt>& ws) const {
320
   if(m_pcurve) {
15,866✔
321
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
8,485✔
322
      auto pt = m_pcurve->mul_by_g(k.value(), rng).to_affine();
16,970✔
323
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
8,485✔
324
   } else {
8,485✔
325
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
326
      const auto& group = scalar.group();
7,381✔
327
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
7,381✔
328

329
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
7,381✔
330
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
7,381✔
331
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
7,381✔
332
#else
333
      BOTAN_UNUSED(ws);
334
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
335
#endif
336
   }
7,381✔
337
}
338

339
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p,
3,472✔
340
                                                              const EC_Scalar_Data& x,
341
                                                              const EC_AffinePoint_Data& q,
342
                                                              const EC_Scalar_Data& y,
343
                                                              RandomNumberGenerator& rng) const {
344
   if(m_pcurve) {
3,472✔
345
      auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(),
5,208✔
346
                                    EC_Scalar_Data_PC::checked_ref(x).value(),
2,604✔
347
                                    EC_AffinePoint_Data_PC::checked_ref(q).value(),
2,604✔
348
                                    EC_Scalar_Data_PC::checked_ref(y).value(),
2,604✔
349
                                    rng);
2,604✔
350

351
      if(pt) {
2,604✔
352
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt->to_affine());
2,520✔
353
      } else {
354
         return nullptr;
84✔
355
      }
356
   } else {
2,604✔
357
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
358
      std::vector<BigInt> ws;
868✔
359
      const auto& group = p.group();
868✔
360

361
      // TODO this could be better!
362
      EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws);
868✔
363
      EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws);
868✔
364

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

367
      auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws);
868✔
368
      auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws);
868✔
369

370
      auto px_qy = px + qy;
868✔
371

372
      if(!px_qy.is_zero()) {
1,624✔
373
         px_qy.force_affine();
756✔
374
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
756✔
375
      } else {
376
         return nullptr;
112✔
377
      }
378
#else
379
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
380
#endif
381
   }
3,472✔
382
}
383

384
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p,
7,753✔
385
                                                               const EC_AffinePoint_Data& q) const {
386
   if(m_pcurve) {
7,753✔
387
      auto pt = m_pcurve->point_add_mixed(
5,045✔
388
         PCurve::PrimeOrderCurve::ProjectivePoint::from_affine(EC_AffinePoint_Data_PC::checked_ref(p).value()),
5,045✔
389
         EC_AffinePoint_Data_PC::checked_ref(q).value());
10,090✔
390

391
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
5,045✔
392
   } else {
5,045✔
393
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
394
      auto pt = p.to_legacy_point() + q.to_legacy_point();
2,708✔
395
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
2,708✔
396
#else
397
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
398
#endif
399
   }
2,708✔
400
}
401

402
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const {
6,712✔
403
   if(m_pcurve) {
6,712✔
404
      auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value());
5,112✔
405
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
5,112✔
406
   } else {
5,112✔
407
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
408
      auto pt = p.to_legacy_point();
1,600✔
409
      pt.negate();  // negates in place
1,600✔
410
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
1,600✔
411
#else
412
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
413
#endif
414
   }
1,600✔
415
}
416

417
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
13,244✔
418
   if(m_pcurve) {
13,244✔
419
      EC_AffinePoint_Data_PC g(shared_from_this(), m_pcurve->generator());
22,326✔
420
      return std::make_unique<EC_Mul2Table_Data_PC>(g, h);
11,163✔
421
   } else {
11,163✔
422
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
423
      EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
4,162✔
424
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
2,081✔
425
#else
426
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
427
#endif
428
   }
2,081✔
429
}
430

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