Coverage Report

Created: 2023-06-07 07:00

/src/botan/src/lib/pubkey/ec_group/ec_group.cpp
Line
Count
Source (jump to first uncovered line)
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,
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) :
41
            m_curve(p, a, b),
42
            m_base_point(m_curve, g_x, g_y),
43
            m_g_x(g_x),
44
            m_g_y(g_y),
45
            m_order(order),
46
            m_cofactor(cofactor),
47
            m_mod_order(order),
48
            m_base_mult(m_base_point, m_mod_order),
49
            m_oid(oid),
50
            m_p_bits(p.bits()),
51
            m_order_bits(order.bits()),
52
            m_a_is_minus_3(a == p - 3),
53
            m_a_is_zero(a.is_zero()),
54
1
            m_source(source) {}
55
56
      bool params_match(const BigInt& p,
57
                        const BigInt& a,
58
                        const BigInt& b,
59
                        const BigInt& g_x,
60
                        const BigInt& g_y,
61
                        const BigInt& order,
62
0
                        const BigInt& cofactor) const {
63
0
         return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
64
0
                 this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
65
0
      }
66
67
0
      bool params_match(const EC_Group_Data& other) const {
68
0
         return params_match(
69
0
            other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
70
0
      }
71
72
0
      void set_oid(const OID& oid) {
73
0
         BOTAN_STATE_CHECK(m_oid.empty());
74
0
         m_oid = oid;
75
0
      }
76
77
0
      const OID& oid() const { return m_oid; }
78
79
1.37k
      const BigInt& p() const { return m_curve.get_p(); }
80
81
1.37k
      const BigInt& a() const { return m_curve.get_a(); }
82
83
1.37k
      const BigInt& b() const { return m_curve.get_b(); }
84
85
4.97k
      const BigInt& order() const { return m_order; }
86
87
0
      const BigInt& cofactor() const { return m_cofactor; }
88
89
0
      const BigInt& g_x() const { return m_g_x; }
90
91
0
      const BigInt& g_y() const { return m_g_y; }
92
93
0
      size_t p_bits() const { return m_p_bits; }
94
95
0
      size_t p_bytes() const { return (m_p_bits + 7) / 8; }
96
97
0
      size_t order_bits() const { return m_order_bits; }
98
99
0
      size_t order_bytes() const { return (m_order_bits + 7) / 8; }
100
101
1.70k
      const CurveGFp& curve() const { return m_curve; }
102
103
1
      const EC_Point& base_point() const { return m_base_point; }
104
105
0
      bool a_is_minus_3() const { return m_a_is_minus_3; }
106
107
0
      bool a_is_zero() const { return m_a_is_zero; }
108
109
0
      BigInt mod_order(const BigInt& x) const { return m_mod_order.reduce(x); }
110
111
0
      BigInt square_mod_order(const BigInt& x) const { return m_mod_order.square(x); }
112
113
0
      BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const { return m_mod_order.multiply(x, y); }
114
115
0
      BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
116
0
         return m_mod_order.multiply(m_mod_order.multiply(x, y), z);
117
0
      }
118
119
0
      BigInt inverse_mod_order(const BigInt& x) const { return inverse_mod(x, m_order); }
120
121
4.12k
      EC_Point blinded_base_point_multiply(const BigInt& k, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
122
4.12k
         return m_base_mult.mul(k, rng, m_order, ws);
123
4.12k
      }
124
125
0
      EC_Group_Source source() const { return m_source; }
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
1
      EC_Group_Data_Map() = default;
148
149
0
      size_t clear() {
150
0
         lock_guard_type<mutex_type> lock(m_mutex);
151
0
         size_t count = m_registered_curves.size();
152
0
         m_registered_curves.clear();
153
0
         return count;
154
0
      }
155
156
1
      std::shared_ptr<EC_Group_Data> lookup(const OID& oid) {
157
1
         lock_guard_type<mutex_type> lock(m_mutex);
158
159
1
         for(auto i : m_registered_curves) {
160
0
            if(i->oid() == oid) {
161
0
               return i;
162
0
            }
163
0
         }
164
165
         // Not found, check hardcoded data
166
1
         std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
167
168
1
         if(data) {
169
1
            for(auto curve : m_registered_curves) {
170
0
               if(curve->oid().empty() == true && curve->params_match(*data)) {
171
0
                  curve->set_oid(oid);
172
0
                  return curve;
173
0
               }
174
0
            }
175
176
1
            m_registered_curves.push_back(data);
177
1
            return data;
178
1
         }
179
180
         // Nope, unknown curve
181
0
         return std::shared_ptr<EC_Group_Data>();
182
1
      }
183
184
      std::shared_ptr<EC_Group_Data> lookup_or_create(const BigInt& p,
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
0
                                                      EC_Group_Source source) {
193
0
         lock_guard_type<mutex_type> lock(m_mutex);
194
195
0
         for(auto i : m_registered_curves) {
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
0
            if(!oid.empty() && !i->oid().empty() && i->oid() != oid) {
202
0
               continue;
203
0
            }
204
205
0
            const bool same_oid = !oid.empty() && i->oid() == oid;
206
0
            const bool same_params = i->params_match(p, a, b, g_x, g_y, order, cofactor);
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
0
            if(same_params && same_oid) {
213
0
               return i;
214
0
            }
215
216
            /*
217
            * If same params and the new OID is empty, then that's ok too
218
            */
219
0
            if(same_params && oid.empty()) {
220
0
               return i;
221
0
            }
222
223
            /*
224
            * Check for someone trying to reuse an already in-use OID
225
            */
226
0
            if(same_oid && !same_params) {
227
0
               throw Invalid_Argument("Attempting to register a curve using OID " + oid.to_string() +
228
0
                                      " but a distinct curve is already registered using that OID");
229
0
            }
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
0
            if(same_params && i->oid().empty() && !oid.empty()) {
236
0
               i->set_oid(oid);
237
0
               return i;
238
0
            }
239
0
         }
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
0
         std::shared_ptr<EC_Group_Data> new_group =
249
0
            std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
250
251
0
         if(oid.has_value()) {
252
0
            std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
253
0
            if(data != nullptr && !new_group->params_match(*data)) {
254
0
               throw Invalid_Argument("Attempting to register an EC group under OID of hardcoded group");
255
0
            }
256
0
         } else {
257
            // Here try to use the order as a hint to look up the group id, to identify common groups
258
0
            const OID oid_from_store = EC_Group::EC_group_identity_from_order(order);
259
0
            if(oid_from_store.has_value()) {
260
0
               std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid_from_store);
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
0
               BOTAN_ASSERT_NOMSG(data != nullptr);
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
0
               if(new_group->params_match(*data)) {
274
0
                  new_group->set_oid(oid_from_store);
275
0
               }
276
0
            }
277
0
         }
278
279
0
         m_registered_curves.push_back(new_group);
280
0
         return new_group;
281
0
      }
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
1
EC_Group_Data_Map& EC_Group::ec_group_data() {
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
1
   static Allocator_Initializer g_init_allocator;
296
1
   static EC_Group_Data_Map g_ec_data;
297
1
   return g_ec_data;
298
1
}
299
300
//static
301
0
size_t EC_Group::clear_registered_curve_data() { return ec_group_data().clear(); }
302
303
//static
304
std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(const char* p_str,
305
                                                            const char* a_str,
306
                                                            const char* b_str,
307
                                                            const char* g_x_str,
308
                                                            const char* g_y_str,
309
                                                            const char* order_str,
310
1
                                                            const OID& oid) {
311
1
   const BigInt p(p_str);
312
1
   const BigInt a(a_str);
313
1
   const BigInt b(b_str);
314
1
   const BigInt g_x(g_x_str);
315
1
   const BigInt g_y(g_y_str);
316
1
   const BigInt order(order_str);
317
1
   const BigInt cofactor(1);  // implicit
318
319
1
   return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin);
320
1
}
321
322
//static
323
0
std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len, EC_Group_Source source) {
324
0
   BER_Decoder ber(bits, len);
325
0
   BER_Object obj = ber.get_next_object();
326
327
0
   if(obj.type() == ASN1_Type::Null) [[unlikely]] {
328
0
      throw Decoding_Error("Cannot handle ImplicitCA ECC parameters");
329
0
   } else if(obj.type() == ASN1_Type::ObjectId) {
330
0
      OID dom_par_oid;
331
0
      BER_Decoder(bits, len).decode(dom_par_oid);
332
0
      return ec_group_data().lookup(dom_par_oid);
333
0
   } else if(obj.type() == ASN1_Type::Sequence) {
334
0
      BigInt p, a, b, order, cofactor;
335
0
      std::vector<uint8_t> base_pt;
336
0
      std::vector<uint8_t> seed;
337
338
0
      BER_Decoder(bits, len)
339
0
         .start_sequence()
340
0
         .decode_and_check<size_t>(1, "Unknown ECC param version code")
341
0
         .start_sequence()
342
0
         .decode_and_check(OID("1.2.840.10045.1.1"), "Only prime ECC fields supported")
343
0
         .decode(p)
344
0
         .end_cons()
345
0
         .start_sequence()
346
0
         .decode_octet_string_bigint(a)
347
0
         .decode_octet_string_bigint(b)
348
0
         .decode_optional_string(seed, ASN1_Type::BitString, ASN1_Type::BitString)
349
0
         .end_cons()
350
0
         .decode(base_pt, ASN1_Type::OctetString)
351
0
         .decode(order)
352
0
         .decode(cofactor)
353
0
         .end_cons()
354
0
         .verify_end();
355
356
0
      if(p.bits() < 64 || p.is_negative() || !is_bailie_psw_probable_prime(p)) {
357
0
         throw Decoding_Error("Invalid ECC p parameter");
358
0
      }
359
360
0
      if(a.is_negative() || a >= p) {
361
0
         throw Decoding_Error("Invalid ECC a parameter");
362
0
      }
363
364
0
      if(b <= 0 || b >= p) {
365
0
         throw Decoding_Error("Invalid ECC b parameter");
366
0
      }
367
368
0
      if(order <= 0 || !is_bailie_psw_probable_prime(order)) {
369
0
         throw Decoding_Error("Invalid ECC order parameter");
370
0
      }
371
372
0
      if(cofactor <= 0 || cofactor >= 16) {
373
0
         throw Decoding_Error("Invalid ECC cofactor parameter");
374
0
      }
375
376
0
      std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b);
377
378
0
      return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID(), source);
379
0
   } else {
380
0
      throw Decoding_Error("Unexpected tag while decoding ECC domain params");
381
0
   }
382
0
}
383
384
0
EC_Group::EC_Group() = default;
385
386
1
EC_Group::~EC_Group() = default;
387
388
0
EC_Group::EC_Group(const OID& domain_oid) {
389
0
   this->m_data = ec_group_data().lookup(domain_oid);
390
0
   if(!this->m_data) {
391
0
      throw Invalid_Argument("Unknown EC_Group " + domain_oid.to_string());
392
0
   }
393
0
}
394
395
1
EC_Group::EC_Group(std::string_view str) {
396
1
   if(str.empty()) {
397
0
      return;  // no initialization / uninitialized
398
0
   }
399
400
1
   try {
401
1
      const OID oid = OID::from_string(str);
402
1
      if(oid.has_value()) {
403
1
         m_data = ec_group_data().lookup(oid);
404
1
      }
405
1
   } catch(...) {}
406
407
1
   if(m_data == nullptr) {
408
0
      if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") {
409
         // OK try it as PEM ...
410
0
         secure_vector<uint8_t> ber = PEM_Code::decode_check_label(str, "EC PARAMETERS");
411
0
         this->m_data = BER_decode_EC_group(ber.data(), ber.size(), EC_Group_Source::ExternalSource);
412
0
      }
413
0
   }
414
415
1
   if(m_data == nullptr) {
416
0
      throw Invalid_Argument(fmt("Unknown ECC group '{}'", str));
417
0
   }
418
1
}
419
420
//static
421
0
EC_Group EC_Group::EC_Group_from_PEM(std::string_view pem) {
422
0
   const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
423
0
   return EC_Group(ber.data(), ber.size());
424
0
}
425
426
EC_Group::EC_Group(const BigInt& p,
427
                   const BigInt& a,
428
                   const BigInt& b,
429
                   const BigInt& base_x,
430
                   const BigInt& base_y,
431
                   const BigInt& order,
432
                   const BigInt& cofactor,
433
0
                   const OID& oid) {
434
0
   m_data =
435
0
      ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
436
0
}
437
438
0
EC_Group::EC_Group(const uint8_t ber[], size_t ber_len) {
439
0
   m_data = BER_decode_EC_group(ber, ber_len, EC_Group_Source::ExternalSource);
440
0
}
441
442
14.9k
const EC_Group_Data& EC_Group::data() const {
443
14.9k
   if(m_data == nullptr) {
444
0
      throw Invalid_State("EC_Group uninitialized");
445
0
   }
446
14.9k
   return *m_data;
447
14.9k
}
448
449
0
bool EC_Group::a_is_minus_3() const { return data().a_is_minus_3(); }
450
451
0
bool EC_Group::a_is_zero() const { return data().a_is_zero(); }
452
453
0
size_t EC_Group::get_p_bits() const { return data().p_bits(); }
454
455
0
size_t EC_Group::get_p_bytes() const { return data().p_bytes(); }
456
457
0
size_t EC_Group::get_order_bits() const { return data().order_bits(); }
458
459
0
size_t EC_Group::get_order_bytes() const { return data().order_bytes(); }
460
461
1.37k
const BigInt& EC_Group::get_p() const { return data().p(); }
462
463
1.37k
const BigInt& EC_Group::get_a() const { return data().a(); }
464
465
1.37k
const BigInt& EC_Group::get_b() const { return data().b(); }
466
467
1
const EC_Point& EC_Group::get_base_point() const { return data().base_point(); }
468
469
4.97k
const BigInt& EC_Group::get_order() const { return data().order(); }
470
471
0
const BigInt& EC_Group::get_g_x() const { return data().g_x(); }
472
473
0
const BigInt& EC_Group::get_g_y() const { return data().g_y(); }
474
475
0
const BigInt& EC_Group::get_cofactor() const { return data().cofactor(); }
476
477
0
BigInt EC_Group::mod_order(const BigInt& k) const { return data().mod_order(k); }
478
479
0
BigInt EC_Group::square_mod_order(const BigInt& x) const { return data().square_mod_order(x); }
480
481
0
BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y) const { return data().multiply_mod_order(x, y); }
482
483
0
BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
484
0
   return data().multiply_mod_order(x, y, z);
485
0
}
486
487
0
BigInt EC_Group::inverse_mod_order(const BigInt& x) const { return data().inverse_mod_order(x); }
488
489
0
const OID& EC_Group::get_curve_oid() const { return data().oid(); }
490
491
0
EC_Group_Source EC_Group::source() const { return data().source(); }
492
493
0
size_t EC_Group::point_size(EC_Point_Format format) const {
494
   // Hybrid and standard format are (x,y), compressed is y, +1 format byte
495
0
   if(format == EC_Point_Format::Compressed) {
496
0
      return (1 + get_p_bytes());
497
0
   } else {
498
0
      return (1 + 2 * get_p_bytes());
499
0
   }
500
0
}
501
502
0
EC_Point EC_Group::OS2ECP(const uint8_t bits[], size_t len) const { return Botan::OS2ECP(bits, len, data().curve()); }
503
504
1.70k
EC_Point EC_Group::point(const BigInt& x, const BigInt& y) const {
505
   // TODO: randomize the representation?
506
1.70k
   return EC_Point(data().curve(), x, y);
507
1.70k
}
508
509
0
EC_Point EC_Group::point_multiply(const BigInt& x, const EC_Point& pt, const BigInt& y) const {
510
0
   EC_Point_Multi_Point_Precompute xy_mul(get_base_point(), pt);
511
0
   return xy_mul.multi_exp(x, y);
512
0
}
513
514
EC_Point EC_Group::blinded_base_point_multiply(const BigInt& k,
515
                                               RandomNumberGenerator& rng,
516
4.12k
                                               std::vector<BigInt>& ws) const {
517
4.12k
   return data().blinded_base_point_multiply(k, rng, ws);
518
4.12k
}
519
520
BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k,
521
                                               RandomNumberGenerator& rng,
522
0
                                               std::vector<BigInt>& ws) const {
523
0
   const EC_Point pt = data().blinded_base_point_multiply(k, rng, ws);
524
525
0
   if(pt.is_zero()) {
526
0
      return BigInt::zero();
527
0
   }
528
0
   return pt.get_affine_x();
529
0
}
530
531
0
BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const {
532
0
   return BigInt::random_integer(rng, BigInt::one(), get_order());
533
0
}
534
535
EC_Point EC_Group::blinded_var_point_multiply(const EC_Point& point,
536
                                              const BigInt& k,
537
                                              RandomNumberGenerator& rng,
538
4.97k
                                              std::vector<BigInt>& ws) const {
539
4.97k
   EC_Point_Var_Point_Precompute mul(point, rng, ws);
540
4.97k
   return mul.mul(k, rng, get_order(), ws);
541
4.97k
}
542
543
0
EC_Point EC_Group::zero_point() const { return EC_Point(data().curve()); }
544
545
EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
546
                                 const uint8_t input[],
547
                                 size_t input_len,
548
                                 std::string_view domain,
549
0
                                 bool random_oracle) const {
550
0
   return this->hash_to_curve(
551
0
      hash_fn, input, input_len, reinterpret_cast<const uint8_t*>(domain.data()), domain.size(), random_oracle);
552
0
}
553
554
EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
555
                                 const uint8_t input[],
556
                                 size_t input_len,
557
                                 const uint8_t domain_sep[],
558
                                 size_t domain_sep_len,
559
0
                                 bool random_oracle) const {
560
0
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
561
562
   // Only have SSWU currently
563
0
   if(get_a().is_zero() || get_b().is_zero() || get_p() % 4 == 1) {
564
0
      throw Not_Implemented("EC_Group::hash_to_curve not available for this curve type");
565
0
   }
566
567
0
   return hash_to_curve_sswu(*this, hash_fn, input, input_len, domain_sep, domain_sep_len, random_oracle);
568
569
#else
570
   BOTAN_UNUSED(hash_fn, random_oracle, input, input_len, domain_sep, domain_sep_len);
571
   throw Not_Implemented("EC_Group::hash_to_curve functionality not available in this configuration");
572
#endif
573
0
}
574
575
0
std::vector<uint8_t> EC_Group::DER_encode(EC_Group_Encoding form) const {
576
0
   std::vector<uint8_t> output;
577
578
0
   DER_Encoder der(output);
579
580
0
   if(form == EC_Group_Encoding::Explicit) {
581
0
      const size_t ecpVers1 = 1;
582
0
      const OID curve_type("1.2.840.10045.1.1");  // prime field
583
584
0
      const size_t p_bytes = get_p_bytes();
585
586
0
      der.start_sequence()
587
0
         .encode(ecpVers1)
588
0
         .start_sequence()
589
0
         .encode(curve_type)
590
0
         .encode(get_p())
591
0
         .end_cons()
592
0
         .start_sequence()
593
0
         .encode(BigInt::encode_1363(get_a(), p_bytes), ASN1_Type::OctetString)
594
0
         .encode(BigInt::encode_1363(get_b(), p_bytes), ASN1_Type::OctetString)
595
0
         .end_cons()
596
0
         .encode(get_base_point().encode(EC_Point_Format::Uncompressed), ASN1_Type::OctetString)
597
0
         .encode(get_order())
598
0
         .encode(get_cofactor())
599
0
         .end_cons();
600
0
   } else if(form == EC_Group_Encoding::NamedCurve) {
601
0
      const OID oid = get_curve_oid();
602
0
      if(oid.empty()) {
603
0
         throw Encoding_Error("Cannot encode EC_Group as OID because OID not set");
604
0
      }
605
0
      der.encode(oid);
606
0
   } else if(form == EC_Group_Encoding::ImplicitCA) {
607
0
      der.encode_null();
608
0
   } else {
609
0
      throw Internal_Error("EC_Group::DER_encode: Unknown encoding");
610
0
   }
611
612
0
   return output;
613
0
}
614
615
0
std::string EC_Group::PEM_encode() const {
616
0
   const std::vector<uint8_t> der = DER_encode(EC_Group_Encoding::Explicit);
617
0
   return PEM_Code::encode(der, "EC PARAMETERS");
618
0
}
619
620
0
bool EC_Group::operator==(const EC_Group& other) const {
621
0
   if(m_data == other.m_data) {
622
0
      return true;  // same shared rep
623
0
   }
624
625
0
   return (get_p() == other.get_p() && get_a() == other.get_a() && get_b() == other.get_b() &&
626
0
           get_g_x() == other.get_g_x() && get_g_y() == other.get_g_y() && get_order() == other.get_order() &&
627
0
           get_cofactor() == other.get_cofactor());
628
0
}
629
630
0
bool EC_Group::verify_public_element(const EC_Point& point) const {
631
   //check that public point is not at infinity
632
0
   if(point.is_zero()) {
633
0
      return false;
634
0
   }
635
636
   //check that public point is on the curve
637
0
   if(point.on_the_curve() == false) {
638
0
      return false;
639
0
   }
640
641
   //check that public point has order q
642
0
   if((point * get_order()).is_zero() == false) {
643
0
      return false;
644
0
   }
645
646
0
   if(get_cofactor() > 1) {
647
0
      if((point * get_cofactor()).is_zero()) {
648
0
         return false;
649
0
      }
650
0
   }
651
652
0
   return true;
653
0
}
654
655
0
bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
656
0
   const bool is_builtin = source() == EC_Group_Source::Builtin;
657
658
0
   if(is_builtin && !strong) {
659
0
      return true;
660
0
   }
661
662
0
   const BigInt& p = get_p();
663
0
   const BigInt& a = get_a();
664
0
   const BigInt& b = get_b();
665
0
   const BigInt& order = get_order();
666
0
   const EC_Point& base_point = get_base_point();
667
668
0
   if(p <= 3 || order <= 0) {
669
0
      return false;
670
0
   }
671
0
   if(a < 0 || a >= p) {
672
0
      return false;
673
0
   }
674
0
   if(b <= 0 || b >= p) {
675
0
      return false;
676
0
   }
677
678
0
   const size_t test_prob = 128;
679
0
   const bool is_randomly_generated = is_builtin;
680
681
   //check if field modulus is prime
682
0
   if(!is_prime(p, rng, test_prob, is_randomly_generated)) {
683
0
      return false;
684
0
   }
685
686
   //check if order is prime
687
0
   if(!is_prime(order, rng, test_prob, is_randomly_generated)) {
688
0
      return false;
689
0
   }
690
691
   //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero
692
0
   const Modular_Reducer mod_p(p);
693
694
0
   const BigInt discriminant = mod_p.reduce(mod_p.multiply(4, mod_p.cube(a)) + mod_p.multiply(27, mod_p.square(b)));
695
696
0
   if(discriminant == 0) {
697
0
      return false;
698
0
   }
699
700
   //check for valid cofactor
701
0
   if(get_cofactor() < 1) {
702
0
      return false;
703
0
   }
704
705
   //check if the base point is on the curve
706
0
   if(!base_point.on_the_curve()) {
707
0
      return false;
708
0
   }
709
0
   if((base_point * get_cofactor()).is_zero()) {
710
0
      return false;
711
0
   }
712
   //check if order of the base point is correct
713
0
   if(!(base_point * order).is_zero()) {
714
0
      return false;
715
0
   }
716
717
0
   return true;
718
0
}
719
720
}  // namespace Botan