Botan 3.5.0
Crypto and TLS for C&
ec_group.cpp
Go to the documentation of this file.
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
28namespace Botan {
29
30class 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 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 const BigInt& cofactor) const {
63 return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
64 this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
65 }
66
67 bool params_match(const EC_Group_Data& other) const {
68 return params_match(
69 other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
70 }
71
72 void set_oid(const OID& oid) {
73 BOTAN_STATE_CHECK(m_oid.empty());
74 m_oid = oid;
75 }
76
77 const OID& oid() const { return m_oid; }
78
79 const BigInt& p() const { return m_curve.get_p(); }
80
81 const BigInt& a() const { return m_curve.get_a(); }
82
83 const BigInt& b() const { return m_curve.get_b(); }
84
85 const BigInt& order() const { return m_order; }
86
87 const BigInt& cofactor() const { return m_cofactor; }
88
89 const BigInt& g_x() const { return m_g_x; }
90
91 const BigInt& g_y() const { return m_g_y; }
92
93 size_t p_bits() const { return m_p_bits; }
94
95 size_t p_bytes() const { return (m_p_bits + 7) / 8; }
96
97 size_t order_bits() const { return m_order_bits; }
98
99 size_t order_bytes() const { return (m_order_bits + 7) / 8; }
100
101 const CurveGFp& curve() const { return m_curve; }
102
103 const EC_Point& base_point() const { return m_base_point; }
104
105 bool a_is_minus_3() const { return m_a_is_minus_3; }
106
107 bool a_is_zero() const { return m_a_is_zero; }
108
109 BigInt mod_order(const BigInt& x) const { return m_mod_order.reduce(x); }
110
111 BigInt square_mod_order(const BigInt& x) const { return m_mod_order.square(x); }
112
113 BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const { return m_mod_order.multiply(x, y); }
114
115 BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
116 return m_mod_order.multiply(m_mod_order.multiply(x, y), z);
117 }
118
119 BigInt inverse_mod_order(const BigInt& x) const { return inverse_mod(x, m_order); }
120
121 EC_Point blinded_base_point_multiply(const BigInt& k, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
122 return m_base_mult.mul(k, rng, m_order, ws);
123 }
124
125 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
145class EC_Group_Data_Map final {
146 public:
147 EC_Group_Data_Map() = default;
148
149 size_t clear() {
151 size_t count = m_registered_curves.size();
152 m_registered_curves.clear();
153 return count;
154 }
155
156 std::shared_ptr<EC_Group_Data> lookup(const OID& oid) {
158
159 for(auto i : m_registered_curves) {
160 if(i->oid() == oid) {
161 return i;
162 }
163 }
164
165 // Not found, check hardcoded data
166 std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
167
168 if(data) {
169 for(auto curve : m_registered_curves) {
170 if(curve->oid().empty() == true && curve->params_match(*data)) {
171 curve->set_oid(oid);
172 return curve;
173 }
174 }
175
176 m_registered_curves.push_back(data);
177 return data;
178 }
179
180 // Nope, unknown curve
181 return std::shared_ptr<EC_Group_Data>();
182 }
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 EC_Group_Source source) {
194
195 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 if(!oid.empty() && !i->oid().empty() && i->oid() != oid) {
202 continue;
203 }
204
205 const bool same_oid = !oid.empty() && i->oid() == oid;
206 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 if(same_params && same_oid) {
213 return i;
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()) {
220 return i;
221 }
222
223 /*
224 * Check for someone trying to reuse an already in-use OID
225 */
226 if(same_oid && !same_params) {
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()) {
236 i->set_oid(oid);
237 return i;
238 }
239 }
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 =
249 std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
250
251 if(oid.has_value()) {
252 std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
253 if(data != nullptr && !new_group->params_match(*data)) {
254 throw Invalid_Argument("Attempting to register an EC group under OID of hardcoded group");
255 }
256 } else {
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);
259 if(oid_from_store.has_value()) {
260 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 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 if(new_group->params_match(*data)) {
274 new_group->set_oid(oid_from_store);
275 }
276 }
277 }
278
279 m_registered_curves.push_back(new_group);
280 return new_group;
281 }
282
283 private:
284 mutex_type m_mutex;
285 std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves;
286};
287
288//static
289EC_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 static Allocator_Initializer g_init_allocator;
296 static EC_Group_Data_Map g_ec_data;
297 return g_ec_data;
298}
299
300//static
302 return ec_group_data().clear();
303}
304
305//static
306std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(const char* p_str,
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);
314 const BigInt a(a_str);
315 const BigInt b(b_str);
316 const BigInt g_x(g_x_str);
317 const BigInt g_y(g_y_str);
318 const BigInt order(order_str);
319 const BigInt cofactor(1); // implicit
320
321 return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin);
322}
323
324//static
325std::pair<std::shared_ptr<EC_Group_Data>, bool> EC_Group::BER_decode_EC_group(std::span<const uint8_t> bits,
326 EC_Group_Source source) {
327 BER_Decoder ber(bits);
328 BER_Object obj = ber.get_next_object();
329
330 if(obj.type() == ASN1_Type::ObjectId) {
331 OID dom_par_oid;
332 BER_Decoder(bits).decode(dom_par_oid);
333 return std::make_pair(ec_group_data().lookup(dom_par_oid), false);
334 }
335
336 if(obj.type() == ASN1_Type::Sequence) {
337 BigInt p, a, b, order, cofactor;
338 std::vector<uint8_t> base_pt;
339 std::vector<uint8_t> seed;
340
341 BER_Decoder(bits)
342 .start_sequence()
343 .decode_and_check<size_t>(1, "Unknown ECC param version code")
344 .start_sequence()
345 .decode_and_check(OID("1.2.840.10045.1.1"), "Only prime ECC fields supported")
346 .decode(p)
347 .end_cons()
348 .start_sequence()
349 .decode_octet_string_bigint(a)
350 .decode_octet_string_bigint(b)
351 .decode_optional_string(seed, ASN1_Type::BitString, ASN1_Type::BitString)
352 .end_cons()
353 .decode(base_pt, ASN1_Type::OctetString)
354 .decode(order)
355 .decode(cofactor)
356 .end_cons()
357 .verify_end();
358
359 if(p.bits() < 112 || p.bits() > 521) {
360 throw Decoding_Error("ECC p parameter is invalid size");
361 }
362
363 if(p.is_negative() || !is_bailie_psw_probable_prime(p)) {
364 throw Decoding_Error("ECC p parameter is not a prime");
365 }
366
367 if(a.is_negative() || a >= p) {
368 throw Decoding_Error("Invalid ECC a parameter");
369 }
370
371 if(b <= 0 || b >= p) {
372 throw Decoding_Error("Invalid ECC b parameter");
373 }
374
375 if(order <= 0 || !is_bailie_psw_probable_prime(order)) {
376 throw Decoding_Error("Invalid ECC order parameter");
377 }
378
379 if(cofactor <= 0 || cofactor >= 16) {
380 throw Decoding_Error("Invalid ECC cofactor parameter");
381 }
382
383 std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b);
384
385 auto data =
386 ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID(), source);
387 return std::make_pair(data, true);
388 }
389
390 if(obj.type() == ASN1_Type::Null) {
391 throw Decoding_Error("Cannot handle ImplicitCA ECC parameters");
392 } else {
393 throw Decoding_Error(fmt("Unexpected tag {} while decoding ECC domain params", asn1_tag_to_string(obj.type())));
394 }
395}
396
397EC_Group::EC_Group() = default;
398
399EC_Group::~EC_Group() = default;
400
401EC_Group::EC_Group(const EC_Group&) = default;
402
403EC_Group& EC_Group::operator=(const EC_Group&) = default;
404
405// Internal constructor
406EC_Group::EC_Group(std::shared_ptr<EC_Group_Data>&& data) : m_data(std::move(data)) {}
407
408//static
410 auto data = ec_group_data().lookup(oid);
411
412 if(!data) {
413 throw Invalid_Argument(fmt("No EC_Group associated with OID '{}'", oid.to_string()));
414 }
415
416 return EC_Group(std::move(data));
417}
418
419//static
421 std::shared_ptr<EC_Group_Data> data;
422
423 if(auto oid = OID::from_name(name)) {
424 data = ec_group_data().lookup(oid.value());
425 }
426
427 if(!data) {
428 throw Invalid_Argument(fmt("Unknown EC_Group '{}'", name));
429 }
430
431 return EC_Group(std::move(data));
432}
433
434EC_Group::EC_Group(std::string_view str) {
435 if(str.empty()) {
436 return; // no initialization / uninitialized
437 }
438
439 try {
440 const OID oid = OID::from_string(str);
441 if(oid.has_value()) {
442 m_data = ec_group_data().lookup(oid);
443 }
444 } catch(...) {}
445
446 if(m_data == nullptr) {
447 if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") {
448 // OK try it as PEM ...
449 const auto ber = PEM_Code::decode_check_label(str, "EC PARAMETERS");
450
451 auto data = BER_decode_EC_group(ber, EC_Group_Source::ExternalSource);
452 this->m_data = data.first;
453 this->m_explicit_encoding = data.second;
454 }
455 }
456
457 if(m_data == nullptr) {
458 throw Invalid_Argument(fmt("Unknown ECC group '{}'", str));
459 }
460}
461
462//static
463EC_Group EC_Group::from_PEM(std::string_view pem) {
464 const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
465 return EC_Group(ber);
466}
467
469 const BigInt& a,
470 const BigInt& b,
471 const BigInt& base_x,
472 const BigInt& base_y,
473 const BigInt& order,
474 const BigInt& cofactor,
475 const OID& oid) {
476 m_data =
477 ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
478}
479
481 const BigInt& p,
482 const BigInt& a,
483 const BigInt& b,
484 const BigInt& base_x,
485 const BigInt& base_y,
486 const BigInt& order) {
487 BOTAN_ARG_CHECK(oid.has_value(), "An OID is required for creating an EC_Group");
488 BOTAN_ARG_CHECK(p.bits() >= 128, "EC_Group p too small");
489 BOTAN_ARG_CHECK(p.bits() <= 521, "EC_Group p too large");
490
491 if(p.bits() == 521) {
492 BOTAN_ARG_CHECK(p == BigInt::power_of_2(521) - 1, "EC_Group with p of 521 bits must be 2**521-1");
493 } else {
494 BOTAN_ARG_CHECK(p.bits() % 32 == 0, "EC_Group p must be a multiple of 32 bits");
495 }
496
497 BOTAN_ARG_CHECK(p % 4 == 3, "EC_Group p must be congruent to 3 modulo 4");
498
499 BOTAN_ARG_CHECK(a >= 0 && a < p, "EC_Group a is invalid");
500 BOTAN_ARG_CHECK(b > 0 && b < p, "EC_Group b is invalid");
501 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p, "EC_Group base_x is invalid");
502 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p, "EC_Group base_y is invalid");
503 BOTAN_ARG_CHECK(p.bits() == order.bits(), "EC_Group p and order must have the same number of bits");
504
505 BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(p), "EC_Group p is not prime");
506 BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(order), "EC_Group order is not prime");
507
508 // This catches someone "ignoring" a cofactor and just trying to
509 // provide the subgroup order
510 BOTAN_ARG_CHECK((p - order).abs().bits() <= (p.bits() / 2) + 1, "Hasse bound invalid");
511
512 BigInt cofactor(1);
513
514 m_data =
515 ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
516}
517
518EC_Group::EC_Group(std::span<const uint8_t> ber) {
519 auto data = BER_decode_EC_group(ber, EC_Group_Source::ExternalSource);
520 m_data = data.first;
521 m_explicit_encoding = data.second;
522}
523
524const EC_Group_Data& EC_Group::data() const {
525 if(m_data == nullptr) {
526 throw Invalid_State("EC_Group uninitialized");
527 }
528 return *m_data;
529}
530
532 return data().a_is_minus_3();
533}
534
536 return data().a_is_zero();
537}
538
539size_t EC_Group::get_p_bits() const {
540 return data().p_bits();
541}
542
543size_t EC_Group::get_p_bytes() const {
544 return data().p_bytes();
545}
546
548 return data().order_bits();
549}
550
552 return data().order_bytes();
553}
554
555const BigInt& EC_Group::get_p() const {
556 return data().p();
557}
558
559const BigInt& EC_Group::get_a() const {
560 return data().a();
561}
562
563const BigInt& EC_Group::get_b() const {
564 return data().b();
565}
566
568 return data().base_point();
569}
570
572 return data().order();
573}
574
575const BigInt& EC_Group::get_g_x() const {
576 return data().g_x();
577}
578
579const BigInt& EC_Group::get_g_y() const {
580 return data().g_y();
581}
582
584 return data().cofactor();
585}
586
588 return data().mod_order(k);
589}
590
592 return data().square_mod_order(x);
593}
594
598
600 return data().multiply_mod_order(x, y);
601}
602
603BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const {
604 return data().multiply_mod_order(x, y, z);
605}
606
608 return data().inverse_mod_order(x);
609}
610
612 return data().oid();
613}
614
616 return data().source();
617}
618
620 // Hybrid and standard format are (x,y), compressed is y, +1 format byte
621 if(format == EC_Point_Format::Compressed) {
622 return (1 + get_p_bytes());
623 } else {
624 return (1 + 2 * get_p_bytes());
625 }
626}
627
628EC_Point EC_Group::OS2ECP(const uint8_t bits[], size_t len) const {
629 return Botan::OS2ECP(bits, len, data().curve());
630}
631
632EC_Point EC_Group::point(const BigInt& x, const BigInt& y) const {
633 // TODO: randomize the representation?
634 return EC_Point(data().curve(), x, y);
635}
636
637EC_Point EC_Group::point_multiply(const BigInt& x, const EC_Point& pt, const BigInt& y) const {
639 return xy_mul.multi_exp(x, y);
640}
641
644 std::vector<BigInt>& ws) const {
645 return data().blinded_base_point_multiply(k, rng, ws);
646}
647
650 std::vector<BigInt>& ws) const {
651 const EC_Point pt = data().blinded_base_point_multiply(k, rng, ws);
652
653 if(pt.is_zero()) {
654 return BigInt::zero();
655 }
656 return pt.get_affine_x();
657}
658
662
664 const BigInt& k,
666 std::vector<BigInt>& ws) const {
668 // We pass order*cofactor here to "correctly" handle the case where the
669 // point is on the curve but not in the prime order subgroup. This only
670 // matters for groups with cofactor > 1
671 // See https://github.com/randombit/botan/issues/3800
672 return mul.mul(k, rng, get_order() * get_cofactor(), ws);
673}
674
676 return EC_Point(data().curve());
677}
678
679EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
680 const uint8_t input[],
681 size_t input_len,
682 std::string_view domain,
683 bool random_oracle) const {
684 return this->hash_to_curve(
685 hash_fn, input, input_len, reinterpret_cast<const uint8_t*>(domain.data()), domain.size(), random_oracle);
686}
687
688EC_Point EC_Group::hash_to_curve(std::string_view hash_fn,
689 const uint8_t input[],
690 size_t input_len,
691 const uint8_t domain_sep[],
692 size_t domain_sep_len,
693 bool random_oracle) const {
694#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
695
696 // Only have SSWU currently
697 if(get_a().is_zero() || get_b().is_zero() || get_p() % 4 == 1) {
698 throw Not_Implemented("EC_Group::hash_to_curve not available for this curve type");
699 }
700
701 return hash_to_curve_sswu(*this, hash_fn, {input, input_len}, {domain_sep, domain_sep_len}, random_oracle);
702
703#else
704 BOTAN_UNUSED(hash_fn, random_oracle, input, input_len, domain_sep, domain_sep_len);
705 throw Not_Implemented("EC_Group::hash_to_curve functionality not available in this configuration");
706#endif
707}
708
709std::vector<uint8_t> EC_Group::DER_encode(EC_Group_Encoding form) const {
710 std::vector<uint8_t> output;
711
712 DER_Encoder der(output);
713
714 if(form == EC_Group_Encoding::Explicit) {
715 const size_t ecpVers1 = 1;
716 const OID curve_type("1.2.840.10045.1.1"); // prime field
717
718 const size_t p_bytes = get_p_bytes();
719
720 der.start_sequence()
721 .encode(ecpVers1)
723 .encode(curve_type)
724 .encode(get_p())
725 .end_cons()
727 .encode(get_a().serialize(p_bytes), ASN1_Type::OctetString)
728 .encode(get_b().serialize(p_bytes), ASN1_Type::OctetString)
729 .end_cons()
731 .encode(get_order())
733 .end_cons();
734 } else if(form == EC_Group_Encoding::NamedCurve) {
735 const OID oid = get_curve_oid();
736 if(oid.empty()) {
737 throw Encoding_Error("Cannot encode EC_Group as OID because OID not set");
738 }
739 der.encode(oid);
740 } else if(form == EC_Group_Encoding::ImplicitCA) {
741 der.encode_null();
742 } else {
743 throw Internal_Error("EC_Group::DER_encode: Unknown encoding");
744 }
745
746 return output;
747}
748
749std::string EC_Group::PEM_encode() const {
750 const std::vector<uint8_t> der = DER_encode(EC_Group_Encoding::Explicit);
751 return PEM_Code::encode(der, "EC PARAMETERS");
752}
753
754bool EC_Group::operator==(const EC_Group& other) const {
755 if(m_data == other.m_data) {
756 return true; // same shared rep
757 }
758
759 return (get_p() == other.get_p() && get_a() == other.get_a() && get_b() == other.get_b() &&
760 get_g_x() == other.get_g_x() && get_g_y() == other.get_g_y() && get_order() == other.get_order() &&
761 get_cofactor() == other.get_cofactor());
762}
763
765 //check that public point is not at infinity
766 if(point.is_zero()) {
767 return false;
768 }
769
770 //check that public point is on the curve
771 if(point.on_the_curve() == false) {
772 return false;
773 }
774
775 //check that public point has order q
776 if((point * get_order()).is_zero() == false) {
777 return false;
778 }
779
780 if(get_cofactor() > 1) {
781 if((point * get_cofactor()).is_zero()) {
782 return false;
783 }
784 }
785
786 return true;
787}
788
789bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
790 const bool is_builtin = source() == EC_Group_Source::Builtin;
791
792 if(is_builtin && !strong) {
793 return true;
794 }
795
796 const BigInt& p = get_p();
797 const BigInt& a = get_a();
798 const BigInt& b = get_b();
799 const BigInt& order = get_order();
800 const EC_Point& base_point = get_base_point();
801
802 if(p <= 3 || order <= 0) {
803 return false;
804 }
805 if(a < 0 || a >= p) {
806 return false;
807 }
808 if(b <= 0 || b >= p) {
809 return false;
810 }
811
812 const size_t test_prob = 128;
813 const bool is_randomly_generated = is_builtin;
814
815 //check if field modulus is prime
816 if(!is_prime(p, rng, test_prob, is_randomly_generated)) {
817 return false;
818 }
819
820 //check if order is prime
821 if(!is_prime(order, rng, test_prob, is_randomly_generated)) {
822 return false;
823 }
824
825 //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero
826 const Modular_Reducer mod_p(p);
827
828 const BigInt discriminant = mod_p.reduce(mod_p.multiply(4, mod_p.cube(a)) + mod_p.multiply(27, mod_p.square(b)));
829
830 if(discriminant == 0) {
831 return false;
832 }
833
834 //check for valid cofactor
835 if(get_cofactor() < 1) {
836 return false;
837 }
838
839 //check if the base point is on the curve
840 if(!base_point.on_the_curve()) {
841 return false;
842 }
843 if((base_point * get_cofactor()).is_zero()) {
844 return false;
845 }
846 //check if order of the base point is correct
847 if(!(base_point * order).is_zero()) {
848 return false;
849 }
850
851 // check the Hasse bound (roughly)
852 if((p - get_cofactor() * order).abs().bits() > (p.bits() / 2) + 1) {
853 return false;
854 }
855
856 return true;
857}
858
859} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:118
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
static BigInt zero()
Definition bigint.h:50
static BigInt random_integer(RandomNumberGenerator &rng, const BigInt &min, const BigInt &max)
Definition big_rand.cpp:43
static BigInt one()
Definition bigint.h:55
size_t bits() const
Definition bigint.cpp:295
static BigInt power_of_2(size_t n)
Definition bigint.h:825
const BigInt & get_a() const
Definition curve_gfp.h:98
const BigInt & get_p() const
Definition curve_gfp.h:109
const BigInt & get_b() const
Definition curve_gfp.h:103
DER_Encoder & start_sequence()
Definition der_enc.h:64
DER_Encoder & encode_null()
Definition der_enc.cpp:243
DER_Encoder & end_cons()
Definition der_enc.cpp:171
DER_Encoder & encode(bool b)
Definition der_enc.cpp:250
bool a_is_minus_3() const
Definition ec_group.cpp:531
static EC_Group from_name(std::string_view name)
Definition ec_group.cpp:420
static EC_Group from_PEM(std::string_view pem)
Definition ec_group.cpp:463
BigInt blinded_base_point_multiply_x(const BigInt &k, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
Definition ec_group.cpp:648
const BigInt & get_b() const
Definition ec_group.cpp:563
const BigInt & get_a() const
Definition ec_group.cpp:559
const BigInt & get_g_y() const
Definition ec_group.cpp:579
const BigInt & get_cofactor() const
Definition ec_group.cpp:583
BigInt mod_order(const BigInt &x) const
Definition ec_group.cpp:587
bool operator==(const EC_Group &other) const
Definition ec_group.cpp:754
BigInt cube_mod_order(const BigInt &x) const
Definition ec_group.cpp:595
BigInt multiply_mod_order(const BigInt &x, const BigInt &y) const
Definition ec_group.cpp:599
EC_Point zero_point() const
Definition ec_group.cpp:675
EC_Group_Source source() const
Definition ec_group.cpp:615
bool a_is_zero() const
Definition ec_group.cpp:535
bool verify_public_element(const EC_Point &y) const
Definition ec_group.cpp:764
const BigInt & get_p() const
Definition ec_group.cpp:555
bool verify_group(RandomNumberGenerator &rng, bool strong=false) const
Definition ec_group.cpp:789
const BigInt & get_order() const
Definition ec_group.cpp:571
size_t get_p_bits() const
Definition ec_group.cpp:539
const EC_Point & get_base_point() const
Definition ec_group.cpp:567
EC_Point point(const BigInt &x, const BigInt &y) const
Definition ec_group.cpp:632
static EC_Group from_OID(const OID &oid)
Definition ec_group.cpp:409
EC_Point blinded_base_point_multiply(const BigInt &k, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
Definition ec_group.cpp:642
static std::shared_ptr< EC_Group_Data > EC_group_info(const OID &oid)
Definition ec_named.cpp:15
std::string PEM_encode() const
Definition ec_group.cpp:749
const BigInt & get_g_x() const
Definition ec_group.cpp:575
const OID & get_curve_oid() const
Definition ec_group.cpp:611
BigInt square_mod_order(const BigInt &x) const
Definition ec_group.cpp:591
EC_Point blinded_var_point_multiply(const EC_Point &point, const BigInt &k, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
Definition ec_group.cpp:663
static size_t clear_registered_curve_data()
Definition ec_group.cpp:301
std::vector< uint8_t > DER_encode(EC_Group_Encoding form) const
Definition ec_group.cpp:709
BigInt inverse_mod_order(const BigInt &x) const
Definition ec_group.cpp:607
EC_Point hash_to_curve(std::string_view hash_fn, const uint8_t input[], size_t input_len, const uint8_t domain_sep[], size_t domain_sep_len, bool random_oracle=true) const
Definition ec_group.cpp:688
EC_Group & operator=(const EC_Group &)
size_t point_size(EC_Point_Format format) const
Definition ec_group.cpp:619
size_t get_p_bytes() const
Definition ec_group.cpp:543
EC_Point point_multiply(const BigInt &x, const EC_Point &pt, const BigInt &y) const
Definition ec_group.cpp:637
static OID EC_group_identity_from_order(const BigInt &order)
Definition ec_named.cpp:344
EC_Point OS2ECP(const uint8_t bits[], size_t len) const
Definition ec_group.cpp:628
BigInt random_scalar(RandomNumberGenerator &rng) const
Definition ec_group.cpp:659
size_t get_order_bits() const
Definition ec_group.cpp:547
size_t get_order_bytes() const
Definition ec_group.cpp:551
EC_Point mul(const BigInt &k, RandomNumberGenerator &rng, const BigInt &group_order, std::vector< BigInt > &ws) const
Definition point_mul.cpp:73
EC_Point multi_exp(const BigInt &k1, const BigInt &k2) const
EC_Point mul(const BigInt &k, RandomNumberGenerator &rng, const BigInt &group_order, std::vector< BigInt > &ws) const
BigInt get_affine_x() const
Definition ec_point.cpp:490
bool is_zero() const
Definition ec_point.h:156
bool on_the_curve() const
Definition ec_point.cpp:531
BigInt cube(const BigInt &x) const
Definition reducer.h:52
BigInt square(const BigInt &x) const
Definition reducer.h:45
BigInt multiply(const BigInt &x, const BigInt &y) const
Definition reducer.h:32
BigInt reduce(const BigInt &x) const
Definition reducer.cpp:37
static std::optional< OID > from_name(std::string_view name)
Definition asn1_oid.cpp:72
bool has_value() const
Definition asn1_obj.h:272
bool empty() const
Definition asn1_obj.h:266
std::string to_string() const
Definition asn1_oid.cpp:125
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
std::string name
int(* final)(unsigned char *, CTX *)
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
Definition pem.cpp:39
secure_vector< uint8_t > decode_check_label(DataSource &source, std::string_view label_want)
Definition pem.cpp:49
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition pem.cpp:62
EC_Group_Source
Definition ec_group.h:34
auto hash_to_curve_sswu(std::string_view hash, bool random_oracle, std::span< const uint8_t > pw, std::span< const uint8_t > dst) -> typename C::ProjectivePoint
noop_mutex mutex_type
Definition mutex.h:37
std::string asn1_tag_to_string(ASN1_Type type)
Definition asn1_obj.cpp:93
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
BigInt abs(const BigInt &n)
Definition numthry.h:22
secure_vector< T > lock(const std::vector< T > &in)
Definition secmem.h:70
bool is_prime(const BigInt &n, RandomNumberGenerator &rng, size_t prob, bool is_random)
Definition numthry.cpp:357
EC_Point_Format
Definition ec_point.h:19
bool is_bailie_psw_probable_prime(const BigInt &n, const Modular_Reducer &mod_n)
Definition primality.cpp:89
EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp &curve)
Definition ec_point.cpp:648
lock_guard< T > lock_guard_type
Definition mutex.h:55
EC_Group_Encoding
Definition ec_group.h:24
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition mod_inv.cpp:178