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

randombit / botan / 11087146043

28 Sep 2024 09:28PM UTC coverage: 92.003% (+0.7%) from 91.274%
11087146043

push

github

web-flow
Create terraform.yml

82959 of 90170 relevant lines covered (92.0%)

9376319.11 hits per line

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

91.96
/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,
1,150✔
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) :
1,150✔
41
            m_curve(p, a, b),
1,150✔
42
            m_base_point(m_curve, g_x, g_y),
1,150✔
43
            m_g_x(g_x),
1,149✔
44
            m_g_y(g_y),
1,149✔
45
            m_order(order),
1,149✔
46
            m_cofactor(cofactor),
1,149✔
47
            m_mod_order(order),
1,149✔
48
            m_base_mult(m_base_point, m_mod_order),
1,149✔
49
            m_oid(oid),
1,149✔
50
            m_p_bits(p.bits()),
1,149✔
51
            m_order_bits(order.bits()),
1,149✔
52
            m_a_is_minus_3(a == p - 3),
2,298✔
53
            m_a_is_zero(a.is_zero()),
1,149✔
54
            m_source(source) {}
1,150✔
55

56
      bool params_match(const BigInt& p,
1,712✔
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 &&
334✔
64
                 this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
2,005✔
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; }
126,474✔
78

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

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

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

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

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

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

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

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

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

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

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

101
      const CurveGFp& curve() const { return m_curve; }
23,477✔
102

103
      const EC_Point& base_point() const { return m_base_point; }
11,726✔
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); }
28,396✔
110

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

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

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

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

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

125
      EC_Group_Source source() const { return m_source; }
124✔
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;
349✔
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) {
17,706✔
157
         lock_guard_type<mutex_type> lock(m_mutex);
17,706✔
158

159
         for(auto i : m_registered_curves) {
126,522✔
160
            if(i->oid() == oid) {
125,333✔
161
               return i;
16,517✔
162
            }
163
         }
125,333✔
164

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

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

176
            m_registered_curves.push_back(data);
1,119✔
177
            return data;
1,119✔
178
         }
179

180
         // Nope, unknown curve
181
         return std::shared_ptr<EC_Group_Data>();
1,189✔
182
      }
17,706✔
183

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

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

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

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

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

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

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

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

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

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

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

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

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

279
         m_registered_curves.push_back(new_group);
19✔
280
         return new_group;
19✔
281
      }
108✔
282

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

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

295
   static Allocator_Initializer g_init_allocator;
19,584✔
296
   static EC_Group_Data_Map g_ec_data;
19,584✔
297
   return g_ec_data;
19,584✔
298
}
299

300
//static
301
size_t EC_Group::clear_registered_curve_data() {
1,769✔
302
   return ec_group_data().clear();
1,769✔
303
}
304

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

321
   return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin);
1,129✔
322
}
7,903✔
323

324
//static
325
std::pair<std::shared_ptr<EC_Group_Data>, bool> EC_Group::BER_decode_EC_group(const uint8_t bits[],
4,585✔
326
                                                                              size_t len,
327
                                                                              EC_Group_Source source) {
328
   BER_Decoder ber(bits, len);
4,585✔
329
   BER_Object obj = ber.get_next_object();
4,585✔
330

331
   if(obj.type() == ASN1_Type::ObjectId) {
4,577✔
332
      OID dom_par_oid;
4,235✔
333
      BER_Decoder(bits, len).decode(dom_par_oid);
4,235✔
334
      return std::make_pair(ec_group_data().lookup(dom_par_oid), false);
4,232✔
335
   }
4,235✔
336

337
   if(obj.type() == ASN1_Type::Sequence) {
342✔
338
      BigInt p, a, b, order, cofactor;
338✔
339
      std::vector<uint8_t> base_pt;
338✔
340
      std::vector<uint8_t> seed;
338✔
341

342
      BER_Decoder(bits, len)
618✔
343
         .start_sequence()
674✔
344
         .decode_and_check<size_t>(1, "Unknown ECC param version code")
336✔
345
         .start_sequence()
650✔
346
         .decode_and_check(OID("1.2.840.10045.1.1"), "Only prime ECC fields supported")
628✔
347
         .decode(p)
309✔
348
         .end_cons()
309✔
349
         .start_sequence()
329✔
350
         .decode_octet_string_bigint(a)
309✔
351
         .decode_octet_string_bigint(b)
308✔
352
         .decode_optional_string(seed, ASN1_Type::BitString, ASN1_Type::BitString)
306✔
353
         .end_cons()
306✔
354
         .decode(base_pt, ASN1_Type::OctetString)
303✔
355
         .decode(order)
296✔
356
         .decode(cofactor)
295✔
357
         .end_cons()
295✔
358
         .verify_end();
294✔
359

360
      if(p.bits() < 112 || p.bits() > 1024) {
294✔
361
         throw Decoding_Error("ECC p parameter is invalid size");
132✔
362
      }
363

364
      if(p.is_negative() || !is_bailie_psw_probable_prime(p)) {
162✔
365
         throw Decoding_Error("ECC p parameter is not a prime");
34✔
366
      }
367

368
      if(a.is_negative() || a >= p) {
256✔
369
         throw Decoding_Error("Invalid ECC a parameter");
9✔
370
      }
371

372
      if(b <= 0 || b >= p) {
238✔
373
         throw Decoding_Error("Invalid ECC b parameter");
55✔
374
      }
375

376
      if(order <= 0 || !is_bailie_psw_probable_prime(order)) {
64✔
377
         throw Decoding_Error("Invalid ECC order parameter");
2✔
378
      }
379

380
      if(cofactor <= 0 || cofactor >= 16) {
122✔
381
         throw Decoding_Error("Invalid ECC cofactor parameter");
3✔
382
      }
383

384
      std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b);
59✔
385

386
      auto data =
59✔
387
         ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID(), source);
59✔
388
      return std::make_pair(data, true);
58✔
389
   }
2,367✔
390

391
   if(obj.type() == ASN1_Type::Null) {
4✔
392
      throw Decoding_Error("Cannot handle ImplicitCA ECC parameters");
2✔
393
   } else {
394
      throw Decoding_Error(fmt("Unexpected tag {} while decoding ECC domain params", asn1_tag_to_string(obj.type())));
4✔
395
   }
396
}
4,585✔
397

398
EC_Group::EC_Group() = default;
2,200✔
399

400
EC_Group::~EC_Group() = default;
44,746✔
401

402
EC_Group::EC_Group(const EC_Group&) = default;
24,724✔
403

404
EC_Group& EC_Group::operator=(const EC_Group&) = default;
839✔
405

406
EC_Group::EC_Group(const OID& domain_oid) {
12,748✔
407
   this->m_data = ec_group_data().lookup(domain_oid);
12,748✔
408
   if(!this->m_data) {
12,748✔
409
      throw Invalid_Argument("Unknown EC_Group " + domain_oid.to_string());
×
410
   }
411
}
12,748✔
412

413
EC_Group::EC_Group(std::string_view str) {
732✔
414
   if(str.empty()) {
732✔
415
      return;  // no initialization / uninitialized
416
   }
417

418
   try {
732✔
419
      const OID oid = OID::from_string(str);
732✔
420
      if(oid.has_value()) {
726✔
421
         m_data = ec_group_data().lookup(oid);
726✔
422
      }
423
   } catch(...) {}
732✔
424

425
   if(m_data == nullptr) {
732✔
426
      if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") {
6✔
427
         // OK try it as PEM ...
428
         secure_vector<uint8_t> ber = PEM_Code::decode_check_label(str, "EC PARAMETERS");
6✔
429

430
         auto data = BER_decode_EC_group(ber.data(), ber.size(), EC_Group_Source::ExternalSource);
6✔
431
         this->m_data = data.first;
6✔
432
         this->m_explicit_encoding = data.second;
6✔
433
      }
12✔
434
   }
435

436
   if(m_data == nullptr) {
732✔
437
      throw Invalid_Argument(fmt("Unknown ECC group '{}'", str));
×
438
   }
439
}
×
440

441
//static
442
EC_Group EC_Group::EC_Group_from_PEM(std::string_view pem) {
×
443
   const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
×
444
   return EC_Group(ber.data(), ber.size());
×
445
}
×
446

447
EC_Group::EC_Group(const BigInt& p,
50✔
448
                   const BigInt& a,
449
                   const BigInt& b,
450
                   const BigInt& base_x,
451
                   const BigInt& base_y,
452
                   const BigInt& order,
453
                   const BigInt& cofactor,
454
                   const OID& oid) {
50✔
455
   m_data =
50✔
456
      ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
50✔
457
}
50✔
458

459
EC_Group::EC_Group(const uint8_t ber[], size_t ber_len) {
4,579✔
460
   auto data = BER_decode_EC_group(ber, ber_len, EC_Group_Source::ExternalSource);
4,579✔
461
   m_data = data.first;
4,284✔
462
   m_explicit_encoding = data.second;
4,284✔
463
}
4,579✔
464

465
const EC_Group_Data& EC_Group::data() const {
214,743✔
466
   if(m_data == nullptr) {
214,743✔
467
      throw Invalid_State("EC_Group uninitialized");
70✔
468
   }
469
   return *m_data;
214,673✔
470
}
471

472
bool EC_Group::a_is_minus_3() const {
27✔
473
   return data().a_is_minus_3();
27✔
474
}
475

476
bool EC_Group::a_is_zero() const {
27✔
477
   return data().a_is_zero();
27✔
478
}
479

480
size_t EC_Group::get_p_bits() const {
1,078✔
481
   return data().p_bits();
1,078✔
482
}
483

484
size_t EC_Group::get_p_bytes() const {
1,007✔
485
   return data().p_bytes();
1,007✔
486
}
487

488
size_t EC_Group::get_order_bits() const {
14,790✔
489
   return data().order_bits();
14,790✔
490
}
491

492
size_t EC_Group::get_order_bytes() const {
19,282✔
493
   return data().order_bytes();
19,282✔
494
}
495

496
const BigInt& EC_Group::get_p() const {
759✔
497
   return data().p();
759✔
498
}
499

500
const BigInt& EC_Group::get_a() const {
752✔
501
   return data().a();
752✔
502
}
503

504
const BigInt& EC_Group::get_b() const {
698✔
505
   return data().b();
698✔
506
}
507

508
const EC_Point& EC_Group::get_base_point() const {
11,726✔
509
   return data().base_point();
11,726✔
510
}
511

512
const BigInt& EC_Group::get_order() const {
44,992✔
513
   return data().order();
44,992✔
514
}
515

516
const BigInt& EC_Group::get_g_x() const {
66✔
517
   return data().g_x();
66✔
518
}
519

520
const BigInt& EC_Group::get_g_y() const {
66✔
521
   return data().g_y();
66✔
522
}
523

524
const BigInt& EC_Group::get_cofactor() const {
3,585✔
525
   return data().cofactor();
3,585✔
526
}
527

528
BigInt EC_Group::mod_order(const BigInt& k) const {
28,396✔
529
   return data().mod_order(k);
28,396✔
530
}
531

532
BigInt EC_Group::square_mod_order(const BigInt& x) const {
906✔
533
   return data().square_mod_order(x);
906✔
534
}
535

536
BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y) const {
26,917✔
537
   return data().multiply_mod_order(x, y);
26,917✔
538
}
539

540
BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
906✔
541
   return data().multiply_mod_order(x, y, z);
906✔
542
}
543

544
BigInt EC_Group::inverse_mod_order(const BigInt& x) const {
14,310✔
545
   return data().inverse_mod_order(x);
14,310✔
546
}
547

548
const OID& EC_Group::get_curve_oid() const {
18,093✔
549
   return data().oid();
18,093✔
550
}
551

552
EC_Group_Source EC_Group::source() const {
124✔
553
   return data().source();
124✔
554
}
555

556
size_t EC_Group::point_size(EC_Point_Format format) const {
123✔
557
   // Hybrid and standard format are (x,y), compressed is y, +1 format byte
558
   if(format == EC_Point_Format::Compressed) {
123✔
559
      return (1 + get_p_bytes());
42✔
560
   } else {
561
      return (1 + 2 * get_p_bytes());
81✔
562
   }
563
}
564

565
EC_Point EC_Group::OS2ECP(const uint8_t bits[], size_t len) const {
10,816✔
566
   return Botan::OS2ECP(bits, len, data().curve());
10,816✔
567
}
568

569
EC_Point EC_Group::point(const BigInt& x, const BigInt& y) const {
12,615✔
570
   // TODO: randomize the representation?
571
   return EC_Point(data().curve(), x, y);
12,615✔
572
}
573

574
EC_Point EC_Group::point_multiply(const BigInt& x, const EC_Point& pt, const BigInt& y) const {
×
575
   EC_Point_Multi_Point_Precompute xy_mul(get_base_point(), pt);
×
576
   return xy_mul.multi_exp(x, y);
×
577
}
×
578

579
EC_Point EC_Group::blinded_base_point_multiply(const BigInt& k,
2,072✔
580
                                               RandomNumberGenerator& rng,
581
                                               std::vector<BigInt>& ws) const {
582
   return data().blinded_base_point_multiply(k, rng, ws);
2,072✔
583
}
584

585
BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k,
679✔
586
                                               RandomNumberGenerator& rng,
587
                                               std::vector<BigInt>& ws) const {
588
   const EC_Point pt = data().blinded_base_point_multiply(k, rng, ws);
679✔
589

590
   if(pt.is_zero()) {
1,358✔
591
      return BigInt::zero();
×
592
   }
593
   return pt.get_affine_x();
679✔
594
}
679✔
595

596
BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const {
941✔
597
   return BigInt::random_integer(rng, BigInt::one(), get_order());
2,823✔
598
}
599

600
EC_Point EC_Group::blinded_var_point_multiply(const EC_Point& point,
2,626✔
601
                                              const BigInt& k,
602
                                              RandomNumberGenerator& rng,
603
                                              std::vector<BigInt>& ws) const {
604
   EC_Point_Var_Point_Precompute mul(point, rng, ws);
2,626✔
605
   // We pass order*cofactor here to "correctly" handle the case where the
606
   // point is on the curve but not in the prime order subgroup. This only
607
   // matters for groups with cofactor > 1
608
   // See https://github.com/randombit/botan/issues/3800
609
   return mul.mul(k, rng, get_order() * get_cofactor(), ws);
5,252✔
610
}
2,626✔
611

612
EC_Point EC_Group::zero_point() const {
54✔
613
   return EC_Point(data().curve());
54✔
614
}
615

616
EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
30✔
617
                                 const uint8_t input[],
618
                                 size_t input_len,
619
                                 std::string_view domain,
620
                                 bool random_oracle) const {
621
   return this->hash_to_curve(
30✔
622
      hash_fn, input, input_len, reinterpret_cast<const uint8_t*>(domain.data()), domain.size(), random_oracle);
30✔
623
}
624

625
EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
36✔
626
                                 const uint8_t input[],
627
                                 size_t input_len,
628
                                 const uint8_t domain_sep[],
629
                                 size_t domain_sep_len,
630
                                 bool random_oracle) const {
631
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
632

633
   // Only have SSWU currently
634
   if(get_a().is_zero() || get_b().is_zero() || get_p() % 4 == 1) {
36✔
635
      throw Not_Implemented("EC_Group::hash_to_curve not available for this curve type");
×
636
   }
637

638
   return hash_to_curve_sswu(*this, hash_fn, {input, input_len}, {domain_sep, domain_sep_len}, random_oracle);
36✔
639

640
#else
641
   BOTAN_UNUSED(hash_fn, random_oracle, input, input_len, domain_sep, domain_sep_len);
642
   throw Not_Implemented("EC_Group::hash_to_curve functionality not available in this configuration");
643
#endif
644
}
645

646
std::vector<uint8_t> EC_Group::DER_encode(EC_Group_Encoding form) const {
915✔
647
   std::vector<uint8_t> output;
915✔
648

649
   DER_Encoder der(output);
915✔
650

651
   if(form == EC_Group_Encoding::Explicit) {
915✔
652
      const size_t ecpVers1 = 1;
34✔
653
      const OID curve_type("1.2.840.10045.1.1");  // prime field
34✔
654

655
      const size_t p_bytes = get_p_bytes();
34✔
656

657
      der.start_sequence()
34✔
658
         .encode(ecpVers1)
34✔
659
         .start_sequence()
34✔
660
         .encode(curve_type)
34✔
661
         .encode(get_p())
34✔
662
         .end_cons()
34✔
663
         .start_sequence()
34✔
664
         .encode(BigInt::encode_1363(get_a(), p_bytes), ASN1_Type::OctetString)
34✔
665
         .encode(BigInt::encode_1363(get_b(), p_bytes), ASN1_Type::OctetString)
68✔
666
         .end_cons()
34✔
667
         .encode(get_base_point().encode(EC_Point_Format::Uncompressed), ASN1_Type::OctetString)
68✔
668
         .encode(get_order())
34✔
669
         .encode(get_cofactor())
34✔
670
         .end_cons();
34✔
671
   } else if(form == EC_Group_Encoding::NamedCurve) {
915✔
672
      const OID oid = get_curve_oid();
881✔
673
      if(oid.empty()) {
881✔
674
         throw Encoding_Error("Cannot encode EC_Group as OID because OID not set");
×
675
      }
676
      der.encode(oid);
881✔
677
   } else if(form == EC_Group_Encoding::ImplicitCA) {
881✔
678
      der.encode_null();
×
679
   } else {
680
      throw Internal_Error("EC_Group::DER_encode: Unknown encoding");
×
681
   }
682

683
   return output;
915✔
684
}
915✔
685

686
std::string EC_Group::PEM_encode() const {
1✔
687
   const std::vector<uint8_t> der = DER_encode(EC_Group_Encoding::Explicit);
1✔
688
   return PEM_Code::encode(der, "EC PARAMETERS");
1✔
689
}
1✔
690

691
bool EC_Group::operator==(const EC_Group& other) const {
54✔
692
   if(m_data == other.m_data) {
54✔
693
      return true;  // same shared rep
694
   }
695

696
   return (get_p() == other.get_p() && get_a() == other.get_a() && get_b() == other.get_b() &&
×
697
           get_g_x() == other.get_g_x() && get_g_y() == other.get_g_y() && get_order() == other.get_order() &&
×
698
           get_cofactor() == other.get_cofactor());
×
699
}
700

701
bool EC_Group::verify_public_element(const EC_Point& point) const {
97✔
702
   //check that public point is not at infinity
703
   if(point.is_zero()) {
138✔
704
      return false;
705
   }
706

707
   //check that public point is on the curve
708
   if(point.on_the_curve() == false) {
97✔
709
      return false;
710
   }
711

712
   //check that public point has order q
713
   if((point * get_order()).is_zero() == false) {
58✔
714
      return false;
715
   }
716

717
   if(get_cofactor() > 1) {
58✔
718
      if((point * get_cofactor()).is_zero()) {
×
719
         return false;
×
720
      }
721
   }
722

723
   return true;
724
}
725

726
bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
124✔
727
   const bool is_builtin = source() == EC_Group_Source::Builtin;
124✔
728

729
   if(is_builtin && !strong) {
124✔
730
      return true;
731
   }
732

733
   const BigInt& p = get_p();
27✔
734
   const BigInt& a = get_a();
27✔
735
   const BigInt& b = get_b();
27✔
736
   const BigInt& order = get_order();
27✔
737
   const EC_Point& base_point = get_base_point();
27✔
738

739
   if(p <= 3 || order <= 0) {
54✔
740
      return false;
×
741
   }
742
   if(a < 0 || a >= p) {
54✔
743
      return false;
×
744
   }
745
   if(b <= 0 || b >= p) {
54✔
746
      return false;
×
747
   }
748

749
   const size_t test_prob = 128;
27✔
750
   const bool is_randomly_generated = is_builtin;
27✔
751

752
   //check if field modulus is prime
753
   if(!is_prime(p, rng, test_prob, is_randomly_generated)) {
27✔
754
      return false;
755
   }
756

757
   //check if order is prime
758
   if(!is_prime(order, rng, test_prob, is_randomly_generated)) {
27✔
759
      return false;
760
   }
761

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

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

767
   if(discriminant == 0) {
27✔
768
      return false;
769
   }
770

771
   //check for valid cofactor
772
   if(get_cofactor() < 1) {
27✔
773
      return false;
774
   }
775

776
   //check if the base point is on the curve
777
   if(!base_point.on_the_curve()) {
27✔
778
      return false;
779
   }
780
   if((base_point * get_cofactor()).is_zero()) {
54✔
781
      return false;
782
   }
783
   //check if order of the base point is correct
784
   if(!(base_point * order).is_zero()) {
27✔
785
      return false;
786
   }
787

788
   // check the Hasse bound (roughly)
789
   if((p - get_cofactor() * order).abs().bits() > (p.bits() / 2) + 1) {
108✔
790
      return false;
×
791
   }
792

793
   return true;
794
}
27✔
795

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