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

randombit / botan / 5111374265

29 May 2023 11:19AM UTC coverage: 92.227% (+0.5%) from 91.723%
5111374265

push

github

randombit
Next release will be 3.1.0. Update release notes

75588 of 81959 relevant lines covered (92.23%)

11886470.91 hits per line

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

91.12
/src/lib/pubkey/ec_group/ec_group.cpp
1
/*
2
* ECC Domain Parameters
3
*
4
* (C) 2007 Falko Strenzke, FlexSecure GmbH
5
* (C) 2008,2018 Jack Lloyd
6
* (C) 2018 Tobias Niemann
7
*
8
* Botan is released under the Simplified BSD License (see license.txt)
9
*/
10

11
#include <botan/ec_group.h>
12

13
#include <botan/ber_dec.h>
14
#include <botan/der_enc.h>
15
#include <botan/mutex.h>
16
#include <botan/pem.h>
17
#include <botan/reducer.h>
18
#include <botan/rng.h>
19
#include <botan/internal/fmt.h>
20
#include <botan/internal/point_mul.h>
21
#include <botan/internal/primality.h>
22
#include <vector>
23

24
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
25
   #include <botan/internal/ec_h2c.h>
26
#endif
27

28
namespace Botan {
29

30
class EC_Group_Data final {
31
   public:
32
      EC_Group_Data(const BigInt& p,
861✔
33
                    const BigInt& a,
34
                    const BigInt& b,
35
                    const BigInt& g_x,
36
                    const BigInt& g_y,
37
                    const BigInt& order,
38
                    const BigInt& cofactor,
39
                    const OID& oid,
40
                    EC_Group_Source source) :
861✔
41
            m_curve(p, a, b),
861✔
42
            m_base_point(m_curve, g_x, g_y),
861✔
43
            m_g_x(g_x),
860✔
44
            m_g_y(g_y),
860✔
45
            m_order(order),
860✔
46
            m_cofactor(cofactor),
860✔
47
            m_mod_order(order),
860✔
48
            m_base_mult(m_base_point, m_mod_order),
860✔
49
            m_oid(oid),
860✔
50
            m_p_bits(p.bits()),
860✔
51
            m_order_bits(order.bits()),
860✔
52
            m_a_is_minus_3(a == p - 3),
1,720✔
53
            m_a_is_zero(a.is_zero()),
860✔
54
            m_source(source) {}
861✔
55

56
      bool params_match(const BigInt& p,
1,344✔
57
                        const BigInt& a,
58
                        const BigInt& b,
59
                        const BigInt& g_x,
60
                        const BigInt& g_y,
61
                        const BigInt& order,
62
                        const BigInt& cofactor) const {
63
         return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
240✔
64
                 this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
1,556✔
65
      }
66

67
      bool params_match(const EC_Group_Data& other) const {
70✔
68
         return params_match(
280✔
69
            other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
70✔
70
      }
71

72
      void set_oid(const OID& oid) {
7✔
73
         BOTAN_STATE_CHECK(m_oid.empty());
7✔
74
         m_oid = oid;
7✔
75
      }
7✔
76

77
      const OID& oid() const { return m_oid; }
129,505✔
78

79
      const BigInt& p() const { return m_curve.get_p(); }
1,414✔
80

81
      const BigInt& a() const { return m_curve.get_a(); }
155✔
82

83
      const BigInt& b() const { return m_curve.get_b(); }
151✔
84

85
      const BigInt& order() const { return m_order; }
74✔
86

87
      const BigInt& cofactor() const { return m_cofactor; }
72✔
88

89
      const BigInt& g_x() const { return m_g_x; }
72✔
90

91
      const BigInt& g_y() const { return m_g_y; }
138✔
92

93
      size_t p_bits() const { return m_p_bits; }
1,120✔
94

95
      size_t p_bytes() const { return (m_p_bits + 7) / 8; }
1,085✔
96

97
      size_t order_bits() const { return m_order_bits; }
14,015✔
98

99
      size_t order_bytes() const { return (m_order_bits + 7) / 8; }
18,481✔
100

101
      const CurveGFp& curve() const { return m_curve; }
22,468✔
102

103
      const EC_Point& base_point() const { return m_base_point; }
10,678✔
104

105
      bool a_is_minus_3() const { return m_a_is_minus_3; }
27✔
106

107
      bool a_is_zero() const { return m_a_is_zero; }
27✔
108

109
      BigInt mod_order(const BigInt& x) const { return m_mod_order.reduce(x); }
26,419✔
110

111
      BigInt square_mod_order(const BigInt& x) const { return m_mod_order.square(x); }
892✔
112

113
      BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const { return m_mod_order.multiply(x, y); }
25,371✔
114

115
      BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
892✔
116
         return m_mod_order.multiply(m_mod_order.multiply(x, y), z);
1,784✔
117
      }
118

119
      BigInt inverse_mod_order(const BigInt& x) const { return inverse_mod(x, m_order); }
13,706✔
120

121
      EC_Point blinded_base_point_multiply(const BigInt& k, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
2,904✔
122
         return m_base_mult.mul(k, rng, m_order, ws);
2,904✔
123
      }
124

125
      EC_Group_Source source() const { return m_source; }
106✔
126

127
   private:
128
      CurveGFp m_curve;
129
      EC_Point m_base_point;
130

131
      BigInt m_g_x;
132
      BigInt m_g_y;
133
      BigInt m_order;
134
      BigInt m_cofactor;
135
      Modular_Reducer m_mod_order;
136
      EC_Point_Base_Point_Precompute m_base_mult;
137
      OID m_oid;
138
      size_t m_p_bits;
139
      size_t m_order_bits;
140
      bool m_a_is_minus_3;
141
      bool m_a_is_zero;
142
      EC_Group_Source m_source;
143
};
144

145
class EC_Group_Data_Map final {
146
   public:
147
      EC_Group_Data_Map() = default;
456✔
148

149
      size_t clear() {
1,769✔
150
         lock_guard_type<mutex_type> lock(m_mutex);
1,769✔
151
         size_t count = m_registered_curves.size();
1,769✔
152
         m_registered_curves.clear();
1,769✔
153
         return count;
1,769✔
154
      }
1,769✔
155

156
      std::shared_ptr<EC_Group_Data> lookup(const OID& oid) {
16,827✔
157
         lock_guard_type<mutex_type> lock(m_mutex);
16,827✔
158

159
         for(auto i : m_registered_curves) {
129,217✔
160
            if(i->oid() == oid)
128,318✔
161
               return i;
15,928✔
162
         }
128,318✔
163

164
         // Not found, check hardcoded data
165
         std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
899✔
166

167
         if(data) {
899✔
168
            for(auto curve : m_registered_curves) {
2,017✔
169
               if(curve->oid().empty() == true && curve->params_match(*data)) {
1,187✔
170
                  curve->set_oid(oid);
×
171
                  return curve;
×
172
               }
173
            }
1,187✔
174

175
            m_registered_curves.push_back(data);
830✔
176
            return data;
830✔
177
         }
178

179
         // Nope, unknown curve
180
         return std::shared_ptr<EC_Group_Data>();
899✔
181
      }
16,827✔
182

183
      std::shared_ptr<EC_Group_Data> lookup_or_create(const BigInt& p,
82✔
184
                                                      const BigInt& a,
185
                                                      const BigInt& b,
186
                                                      const BigInt& g_x,
187
                                                      const BigInt& g_y,
188
                                                      const BigInt& order,
189
                                                      const BigInt& cofactor,
190
                                                      const OID& oid,
191
                                                      EC_Group_Source source) {
192
         lock_guard_type<mutex_type> lock(m_mutex);
82✔
193

194
         for(auto i : m_registered_curves) {
1,407✔
195
            /*
196
            * The params may be the same but you are trying to register under a
197
            * different OID than the one we are using, so using a different
198
            * group, since EC_Group's model assumes a single OID per group.
199
            */
200
            if(!oid.empty() && !i->oid().empty() && i->oid() != oid) {
1,386✔
201
               continue;
112✔
202
            }
203

204
            const bool same_oid = !oid.empty() && i->oid() == oid;
1,274✔
205
            const bool same_params = i->params_match(p, a, b, g_x, g_y, order, cofactor);
1,274✔
206

207
            /*
208
            * If the params and OID are the same then we are done, just return
209
            * the already registered curve obj.
210
            */
211
            if(same_params && same_oid) {
1,274✔
212
               return i;
1✔
213
            }
214

215
            /*
216
            * If same params and the new OID is empty, then that's ok too
217
            */
218
            if(same_params && oid.empty()) {
1,273✔
219
               return i;
60✔
220
            }
221

222
            /*
223
            * Check for someone trying to reuse an already in-use OID
224
            */
225
            if(same_oid && !same_params) {
1,213✔
226
               throw Invalid_Argument("Attempting to register a curve using OID " + oid.to_string() +
×
227
                                      " but a distinct curve is already registered using that OID");
×
228
            }
229

230
            /*
231
            * If the same curve was previously created without an OID but is now
232
            * being registered again using an OID, save that OID.
233
            */
234
            if(same_params && i->oid().empty() && !oid.empty()) {
1,213✔
235
               i->set_oid(oid);
×
236
               return i;
61✔
237
            }
238
         }
1,386✔
239

240
         /*
241
         Not found in current list, so we need to create a new entry
242

243
         If an OID is set, try to look up relative our static tables to detect a duplicate
244
         registration under an OID
245
         */
246

247
         std::shared_ptr<EC_Group_Data> new_group =
21✔
248
            std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
20✔
249

250
         if(oid.has_value()) {
20✔
251
            std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
5✔
252
            if(data != nullptr && !new_group->params_match(*data))
5✔
253
               throw Invalid_Argument("Attempting to register an EC group under OID of hardcoded group");
1✔
254
         } else {
5✔
255
            // Here try to use the order as a hint to look up the group id, to identify common groups
256
            const OID oid_from_store = EC_Group::EC_group_identity_from_order(order);
15✔
257
            if(oid_from_store.has_value()) {
15✔
258
               std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid_from_store);
9✔
259

260
               /*
261
               If EC_group_identity_from_order returned an OID then looking up that OID
262
               must always return a result.
263
               */
264
               BOTAN_ASSERT_NOMSG(data != nullptr);
9✔
265

266
               /*
267
               It is possible (if unlikely) that someone is registering another group
268
               that happens to have an order equal to that of a well known group -
269
               so verify all values before assigning the OID.
270
               */
271
               if(new_group->params_match(*data)) {
9✔
272
                  new_group->set_oid(oid_from_store);
7✔
273
               }
274
            }
9✔
275
         }
15✔
276

277
         m_registered_curves.push_back(new_group);
19✔
278
         return new_group;
19✔
279
      }
81✔
280

281
   private:
282
      mutex_type m_mutex;
283
      std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves;
284
};
285

286
//static
287
EC_Group_Data_Map& EC_Group::ec_group_data() {
18,678✔
288
   /*
289
   * This exists purely to ensure the allocator is constructed before g_ec_data,
290
   * which ensures that its destructor runs after ~g_ec_data is complete.
291
   */
292

293
   static Allocator_Initializer g_init_allocator;
18,678✔
294
   static EC_Group_Data_Map g_ec_data;
18,678✔
295
   return g_ec_data;
18,678✔
296
}
297

298
//static
299
size_t EC_Group::clear_registered_curve_data() { return ec_group_data().clear(); }
1,769✔
300

301
//static
302
std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(const char* p_str,
840✔
303
                                                            const char* a_str,
304
                                                            const char* b_str,
305
                                                            const char* g_x_str,
306
                                                            const char* g_y_str,
307
                                                            const char* order_str,
308
                                                            const OID& oid) {
309
   const BigInt p(p_str);
840✔
310
   const BigInt a(a_str);
840✔
311
   const BigInt b(b_str);
840✔
312
   const BigInt g_x(g_x_str);
840✔
313
   const BigInt g_y(g_y_str);
840✔
314
   const BigInt order(order_str);
840✔
315
   const BigInt cofactor(1);  // implicit
840✔
316

317
   return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin);
840✔
318
}
5,880✔
319

320
//static
321
std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len, EC_Group_Source source) {
3,299✔
322
   BER_Decoder ber(bits, len);
3,299✔
323
   BER_Object obj = ber.get_next_object();
3,299✔
324

325
   if(obj.type() == ASN1_Type::Null) [[unlikely]] {
3,291✔
326
      throw Decoding_Error("Cannot handle ImplicitCA ECC parameters");
2✔
327
   } else if(obj.type() == ASN1_Type::ObjectId) {
3,289✔
328
      OID dom_par_oid;
2,977✔
329
      BER_Decoder(bits, len).decode(dom_par_oid);
2,977✔
330
      return ec_group_data().lookup(dom_par_oid);
2,974✔
331
   } else if(obj.type() == ASN1_Type::Sequence) {
3,289✔
332
      BigInt p, a, b, order, cofactor;
310✔
333
      std::vector<uint8_t> base_pt;
310✔
334
      std::vector<uint8_t> seed;
310✔
335

336
      BER_Decoder(bits, len)
589✔
337
         .start_sequence()
618✔
338
         .decode_and_check<size_t>(1, "Unknown ECC param version code")
308✔
339
         .start_sequence()
594✔
340
         .decode_and_check(OID("1.2.840.10045.1.1"), "Only prime ECC fields supported")
572✔
341
         .decode(p)
281✔
342
         .end_cons()
281✔
343
         .start_sequence()
300✔
344
         .decode_octet_string_bigint(a)
281✔
345
         .decode_octet_string_bigint(b)
280✔
346
         .decode_optional_string(seed, ASN1_Type::BitString, ASN1_Type::BitString)
279✔
347
         .end_cons()
279✔
348
         .decode(base_pt, ASN1_Type::OctetString)
276✔
349
         .decode(order)
269✔
350
         .decode(cofactor)
268✔
351
         .end_cons()
268✔
352
         .verify_end();
267✔
353

354
      if(p.bits() < 64 || p.is_negative() || !is_bailie_psw_probable_prime(p))
267✔
355
         throw Decoding_Error("Invalid ECC p parameter");
162✔
356

357
      if(a.is_negative() || a >= p)
210✔
358
         throw Decoding_Error("Invalid ECC a parameter");
13✔
359

360
      if(b <= 0 || b >= p)
184✔
361
         throw Decoding_Error("Invalid ECC b parameter");
55✔
362

363
      if(order <= 0 || !is_bailie_psw_probable_prime(order))
37✔
364
         throw Decoding_Error("Invalid ECC order parameter");
2✔
365

366
      if(cofactor <= 0 || cofactor >= 16)
68✔
367
         throw Decoding_Error("Invalid ECC cofactor parameter");
3✔
368

369
      std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b);
32✔
370

371
      return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID(), source);
32✔
372
   } else {
2,171✔
373
      throw Decoding_Error("Unexpected tag while decoding ECC domain params");
2✔
374
   }
375
}
3,299✔
376

377
EC_Group::EC_Group() = default;
1,923✔
378

379
EC_Group::~EC_Group() = default;
43,092✔
380

381
EC_Group::EC_Group(const OID& domain_oid) {
12,739✔
382
   this->m_data = ec_group_data().lookup(domain_oid);
12,739✔
383
   if(!this->m_data)
12,739✔
384
      throw Invalid_Argument("Unknown EC_Group " + domain_oid.to_string());
×
385
}
12,739✔
386

387
EC_Group::EC_Group(std::string_view str) {
1,120✔
388
   if(str.empty())
1,120✔
389
      return;  // no initialization / uninitialized
390

391
   try {
1,120✔
392
      const OID oid = OID::from_string(str);
1,120✔
393
      if(oid.has_value())
1,114✔
394
         m_data = ec_group_data().lookup(oid);
1,114✔
395
   } catch(...) {}
1,120✔
396

397
   if(m_data == nullptr) {
1,120✔
398
      if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") {
6✔
399
         // OK try it as PEM ...
400
         secure_vector<uint8_t> ber = PEM_Code::decode_check_label(str, "EC PARAMETERS");
6✔
401
         this->m_data = BER_decode_EC_group(ber.data(), ber.size(), EC_Group_Source::ExternalSource);
6✔
402
      }
6✔
403
   }
404

405
   if(m_data == nullptr)
1,120✔
406
      throw Invalid_Argument(fmt("Unknown ECC group '{}'", str));
×
407
}
×
408

409
//static
410
EC_Group EC_Group::EC_Group_from_PEM(std::string_view pem) {
×
411
   const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
×
412
   return EC_Group(ber.data(), ber.size());
×
413
}
×
414

415
EC_Group::EC_Group(const BigInt& p,
50✔
416
                   const BigInt& a,
417
                   const BigInt& b,
418
                   const BigInt& base_x,
419
                   const BigInt& base_y,
420
                   const BigInt& order,
421
                   const BigInt& cofactor,
422
                   const OID& oid) {
50✔
423
   m_data =
50✔
424
      ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
50✔
425
}
50✔
426

427
EC_Group::EC_Group(const uint8_t ber[], size_t ber_len) {
3,293✔
428
   m_data = BER_decode_EC_group(ber, ber_len, EC_Group_Source::ExternalSource);
3,293✔
429
}
3,293✔
430

431
const EC_Group_Data& EC_Group::data() const {
200,261✔
432
   if(m_data == nullptr)
200,261✔
433
      throw Invalid_State("EC_Group uninitialized");
69✔
434
   return *m_data;
200,192✔
435
}
436

437
bool EC_Group::a_is_minus_3() const { return data().a_is_minus_3(); }
27✔
438

439
bool EC_Group::a_is_zero() const { return data().a_is_zero(); }
27✔
440

441
size_t EC_Group::get_p_bits() const { return data().p_bits(); }
1,120✔
442

443
size_t EC_Group::get_p_bytes() const { return data().p_bytes(); }
1,085✔
444

445
size_t EC_Group::get_order_bits() const { return data().order_bits(); }
14,015✔
446

447
size_t EC_Group::get_order_bytes() const { return data().order_bytes(); }
18,481✔
448

449
const BigInt& EC_Group::get_p() const { return data().p(); }
732✔
450

451
const BigInt& EC_Group::get_a() const { return data().a(); }
723✔
452

453
const BigInt& EC_Group::get_b() const { return data().b(); }
669✔
454

455
const EC_Point& EC_Group::get_base_point() const { return data().base_point(); }
10,678✔
456

457
const BigInt& EC_Group::get_order() const { return data().order(); }
41,503✔
458

459
const BigInt& EC_Group::get_g_x() const { return data().g_x(); }
64✔
460

461
const BigInt& EC_Group::get_g_y() const { return data().g_y(); }
64✔
462

463
const BigInt& EC_Group::get_cofactor() const { return data().cofactor(); }
1,229✔
464

465
BigInt EC_Group::mod_order(const BigInt& k) const { return data().mod_order(k); }
26,419✔
466

467
BigInt EC_Group::square_mod_order(const BigInt& x) const { return data().square_mod_order(x); }
892✔
468

469
BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y) const { return data().multiply_mod_order(x, y); }
25,371✔
470

471
BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
892✔
472
   return data().multiply_mod_order(x, y, z);
892✔
473
}
474

475
BigInt EC_Group::inverse_mod_order(const BigInt& x) const { return data().inverse_mod_order(x); }
13,706✔
476

477
const OID& EC_Group::get_curve_oid() const { return data().oid(); }
17,078✔
478

479
EC_Group_Source EC_Group::source() const { return data().source(); }
106✔
480

481
size_t EC_Group::point_size(EC_Point_Format format) const {
123✔
482
   // Hybrid and standard format are (x,y), compressed is y, +1 format byte
483
   if(format == EC_Point_Format::Compressed)
123✔
484
      return (1 + get_p_bytes());
42✔
485
   else
486
      return (1 + 2 * get_p_bytes());
81✔
487
}
488

489
EC_Point EC_Group::OS2ECP(const uint8_t bits[], size_t len) const { return Botan::OS2ECP(bits, len, data().curve()); }
9,845✔
490

491
EC_Point EC_Group::point(const BigInt& x, const BigInt& y) const {
12,577✔
492
   // TODO: randomize the representation?
493
   return EC_Point(data().curve(), x, y);
12,577✔
494
}
495

496
EC_Point EC_Group::point_multiply(const BigInt& x, const EC_Point& pt, const BigInt& y) const {
×
497
   EC_Point_Multi_Point_Precompute xy_mul(get_base_point(), pt);
×
498
   return xy_mul.multi_exp(x, y);
×
499
}
×
500

501
EC_Point EC_Group::blinded_base_point_multiply(const BigInt& k,
2,255✔
502
                                               RandomNumberGenerator& rng,
503
                                               std::vector<BigInt>& ws) const {
504
   return data().blinded_base_point_multiply(k, rng, ws);
2,255✔
505
}
506

507
BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k,
649✔
508
                                               RandomNumberGenerator& rng,
509
                                               std::vector<BigInt>& ws) const {
510
   const EC_Point pt = data().blinded_base_point_multiply(k, rng, ws);
649✔
511

512
   if(pt.is_zero())
1,298✔
513
      return BigInt::zero();
×
514
   return pt.get_affine_x();
649✔
515
}
649✔
516

517
BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const {
1,108✔
518
   return BigInt::random_integer(rng, BigInt::one(), get_order());
3,324✔
519
}
520

521
EC_Point EC_Group::blinded_var_point_multiply(const EC_Point& point,
2,771✔
522
                                              const BigInt& k,
523
                                              RandomNumberGenerator& rng,
524
                                              std::vector<BigInt>& ws) const {
525
   EC_Point_Var_Point_Precompute mul(point, rng, ws);
2,771✔
526
   return mul.mul(k, rng, get_order(), ws);
5,542✔
527
}
2,771✔
528

529
EC_Point EC_Group::zero_point() const { return EC_Point(data().curve()); }
54✔
530

531
EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
30✔
532
                                 const uint8_t input[],
533
                                 size_t input_len,
534
                                 std::string_view domain,
535
                                 bool random_oracle) const {
536
   return this->hash_to_curve(
30✔
537
      hash_fn, input, input_len, reinterpret_cast<const uint8_t*>(domain.data()), domain.size(), random_oracle);
30✔
538
}
539

540
EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
36✔
541
                                 const uint8_t input[],
542
                                 size_t input_len,
543
                                 const uint8_t domain_sep[],
544
                                 size_t domain_sep_len,
545
                                 bool random_oracle) const {
546
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
547

548
   // Only have SSWU currently
549
   if(get_a().is_zero() || get_b().is_zero() || get_p() % 4 == 1) {
36✔
550
      throw Not_Implemented("EC_Group::hash_to_curve not available for this curve type");
×
551
   }
552

553
   return hash_to_curve_sswu(*this, hash_fn, input, input_len, domain_sep, domain_sep_len, random_oracle);
36✔
554

555
#else
556
   BOTAN_UNUSED(hash_fn, random_oracle, input, input_len, domain_sep, domain_sep_len);
557
   throw Not_Implemented("EC_Group::hash_to_curve functionality not available in this configuration");
558
#endif
559
}
560

561
std::vector<uint8_t> EC_Group::DER_encode(EC_Group_Encoding form) const {
769✔
562
   std::vector<uint8_t> output;
769✔
563

564
   DER_Encoder der(output);
769✔
565

566
   if(form == EC_Group_Encoding::Explicit) {
769✔
567
      const size_t ecpVers1 = 1;
7✔
568
      const OID curve_type("1.2.840.10045.1.1");  // prime field
7✔
569

570
      const size_t p_bytes = get_p_bytes();
7✔
571

572
      der.start_sequence()
7✔
573
         .encode(ecpVers1)
7✔
574
         .start_sequence()
7✔
575
         .encode(curve_type)
7✔
576
         .encode(get_p())
7✔
577
         .end_cons()
7✔
578
         .start_sequence()
7✔
579
         .encode(BigInt::encode_1363(get_a(), p_bytes), ASN1_Type::OctetString)
7✔
580
         .encode(BigInt::encode_1363(get_b(), p_bytes), ASN1_Type::OctetString)
14✔
581
         .end_cons()
7✔
582
         .encode(get_base_point().encode(EC_Point_Format::Uncompressed), ASN1_Type::OctetString)
14✔
583
         .encode(get_order())
7✔
584
         .encode(get_cofactor())
7✔
585
         .end_cons();
7✔
586
   } else if(form == EC_Group_Encoding::NamedCurve) {
769✔
587
      const OID oid = get_curve_oid();
762✔
588
      if(oid.empty()) {
762✔
589
         throw Encoding_Error("Cannot encode EC_Group as OID because OID not set");
×
590
      }
591
      der.encode(oid);
762✔
592
   } else if(form == EC_Group_Encoding::ImplicitCA) {
762✔
593
      der.encode_null();
×
594
   } else {
595
      throw Internal_Error("EC_Group::DER_encode: Unknown encoding");
×
596
   }
597

598
   return output;
769✔
599
}
769✔
600

601
std::string EC_Group::PEM_encode() const {
1✔
602
   const std::vector<uint8_t> der = DER_encode(EC_Group_Encoding::Explicit);
1✔
603
   return PEM_Code::encode(der, "EC PARAMETERS");
1✔
604
}
1✔
605

606
bool EC_Group::operator==(const EC_Group& other) const {
54✔
607
   if(m_data == other.m_data)
54✔
608
      return true;  // same shared rep
609

610
   return (get_p() == other.get_p() && get_a() == other.get_a() && get_b() == other.get_b() &&
×
611
           get_g_x() == other.get_g_x() && get_g_y() == other.get_g_y() && get_order() == other.get_order() &&
×
612
           get_cofactor() == other.get_cofactor());
×
613
}
614

615
bool EC_Group::verify_public_element(const EC_Point& point) const {
79✔
616
   //check that public point is not at infinity
617
   if(point.is_zero())
120✔
618
      return false;
619

620
   //check that public point is on the curve
621
   if(point.on_the_curve() == false)
79✔
622
      return false;
623

624
   //check that public point has order q
625
   if((point * get_order()).is_zero() == false)
40✔
626
      return false;
627

628
   if(get_cofactor() > 1) {
40✔
629
      if((point * get_cofactor()).is_zero())
×
630
         return false;
×
631
   }
632

633
   return true;
634
}
635

636
bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
106✔
637
   const bool is_builtin = source() == EC_Group_Source::Builtin;
106✔
638

639
   if(is_builtin && !strong)
106✔
640
      return true;
641

642
   const BigInt& p = get_p();
27✔
643
   const BigInt& a = get_a();
27✔
644
   const BigInt& b = get_b();
27✔
645
   const BigInt& order = get_order();
27✔
646
   const EC_Point& base_point = get_base_point();
27✔
647

648
   if(p <= 3 || order <= 0)
54✔
649
      return false;
×
650
   if(a < 0 || a >= p)
54✔
651
      return false;
×
652
   if(b <= 0 || b >= p)
54✔
653
      return false;
×
654

655
   const size_t test_prob = 128;
27✔
656
   const bool is_randomly_generated = is_builtin;
27✔
657

658
   //check if field modulus is prime
659
   if(!is_prime(p, rng, test_prob, is_randomly_generated)) {
27✔
660
      return false;
661
   }
662

663
   //check if order is prime
664
   if(!is_prime(order, rng, test_prob, is_randomly_generated)) {
27✔
665
      return false;
666
   }
667

668
   //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero
669
   const Modular_Reducer mod_p(p);
27✔
670

671
   const BigInt discriminant = mod_p.reduce(mod_p.multiply(4, mod_p.cube(a)) + mod_p.multiply(27, mod_p.square(b)));
189✔
672

673
   if(discriminant == 0) {
27✔
674
      return false;
675
   }
676

677
   //check for valid cofactor
678
   if(get_cofactor() < 1) {
27✔
679
      return false;
680
   }
681

682
   //check if the base point is on the curve
683
   if(!base_point.on_the_curve()) {
27✔
684
      return false;
685
   }
686
   if((base_point * get_cofactor()).is_zero()) {
54✔
687
      return false;
688
   }
689
   //check if order of the base point is correct
690
   if(!(base_point * order).is_zero()) {
27✔
691
      return false;
×
692
   }
693

694
   return true;
695
}
27✔
696

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

© 2025 Coveralls, Inc