Botan 3.8.1
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,2024 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/numthry.h>
17#include <botan/pem.h>
18#include <botan/rng.h>
19#include <botan/internal/barrett.h>
20#include <botan/internal/ec_inner_data.h>
21#include <botan/internal/fmt.h>
22#include <botan/internal/primality.h>
23#include <vector>
24
25namespace Botan {
26
27class EC_Group_Data_Map final {
28 public:
29 EC_Group_Data_Map() = default;
30
31 size_t clear() {
33 size_t count = m_registered_curves.size();
34 m_registered_curves.clear();
35 return count;
36 }
37
38 std::shared_ptr<EC_Group_Data> lookup(const OID& oid) {
40
41 for(auto i : m_registered_curves) {
42 if(i->oid() == oid) {
43 return i;
44 }
45 }
46
47 // Not found, check hardcoded data
48 std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
49
50 if(data) {
51 m_registered_curves.push_back(data);
52 return data;
53 }
54
55 // Nope, unknown curve
56 return std::shared_ptr<EC_Group_Data>();
57 }
58
59 std::shared_ptr<EC_Group_Data> lookup_or_create(const BigInt& p,
60 const BigInt& a,
61 const BigInt& b,
62 const BigInt& g_x,
63 const BigInt& g_y,
64 const BigInt& order,
65 const BigInt& cofactor,
66 const OID& oid,
67 EC_Group_Source source) {
68 BOTAN_ASSERT_NOMSG(oid.has_value());
69
71
72 for(auto i : m_registered_curves) {
73 if(i->oid() == oid) {
74 /*
75 * If both OID and params are the same then we are done, just return
76 * the already registered curve obj.
77 *
78 * First verify that the params match, to catch an application
79 * that is attempting to register a EC_Group under the same OID as
80 * another group currently in use
81 */
82 if(!i->params_match(p, a, b, g_x, g_y, order, cofactor)) {
83 throw Invalid_Argument("Attempting to register a curve using OID " + oid.to_string() +
84 " but a distinct curve is already registered using that OID");
85 }
86
87 return i;
88 }
89
90 /*
91 * If the same curve was previously created without an OID but is now
92 * being registered again using an OID, save that OID.
93 *
94 * TODO(Botan4) remove this block; this situation won't be possible since
95 * we will require all groups to have an OID
96 */
97 if(i->oid().empty() && i->params_match(p, a, b, g_x, g_y, order, cofactor)) {
98 i->set_oid(oid);
99 return i;
100 }
101 }
102
103 /*
104 * Not found in current list, so we need to create a new entry
105 */
106 auto new_group = [&] {
107 if(auto g = EC_Group::EC_group_info(oid); g != nullptr) {
108 /*
109 * This turned out to be the OID of one of the builtin groups. Verify
110 * that all of the provided parameters match that builtin group.
111 */
112 BOTAN_ARG_CHECK(g->params_match(p, a, b, g_x, g_y, order, cofactor),
113 "Attempting to register an EC group under OID of hardcoded group");
114
115 return g;
116 } else {
117 /*
118 * This path is taken for an application registering a new EC_Group with an OID specified
119 */
120 return EC_Group_Data::create(p, a, b, g_x, g_y, order, cofactor, oid, source);
121 }
122 }();
123
124 m_registered_curves.push_back(new_group);
125 return new_group;
126 }
127
128 std::shared_ptr<EC_Group_Data> lookup_or_create_without_oid(const BigInt& p,
129 const BigInt& a,
130 const BigInt& b,
131 const BigInt& g_x,
132 const BigInt& g_y,
133 const BigInt& order,
134 const BigInt& cofactor,
135 EC_Group_Source source) {
137
138 for(auto i : m_registered_curves) {
139 if(i->params_match(p, a, b, g_x, g_y, order, cofactor)) {
140 return i;
141 }
142 }
143
144 // Try to use the order as a hint to look up the group id
145 const OID oid_from_order = EC_Group::EC_group_identity_from_order(order);
146 if(oid_from_order.has_value()) {
147 auto new_group = EC_Group::EC_group_info(oid_from_order);
148
149 // Have to check all params in the (unlikely/malicious) event of an order collision
150 if(new_group && new_group->params_match(p, a, b, g_x, g_y, order, cofactor)) {
151 m_registered_curves.push_back(new_group);
152 return new_group;
153 }
154 }
155
156 /*
157 * At this point we have failed to identify the group; it is not any of
158 * the builtin values, nor is it a group that the user had previously
159 * registered explicitly. We create the group data without an OID.
160 *
161 * TODO(Botan4) remove this; throw an exception instead
162 */
163 auto new_group = EC_Group_Data::create(p, a, b, g_x, g_y, order, cofactor, OID(), source);
164 m_registered_curves.push_back(new_group);
165 return new_group;
166 }
167
168 private:
169 mutex_type m_mutex;
170 // TODO(Botan4): Once OID is required we could make this into a map
171 std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves;
172};
173
174//static
175EC_Group_Data_Map& EC_Group::ec_group_data() {
176 /*
177 * This exists purely to ensure the allocator is constructed before g_ec_data,
178 * which ensures that its destructor runs after ~g_ec_data is complete.
179 */
180
181 static Allocator_Initializer g_init_allocator;
182 static EC_Group_Data_Map g_ec_data;
183 return g_ec_data;
184}
185
186//static
188 return ec_group_data().clear();
189}
190
191//static
192std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(const char* p_str,
193 const char* a_str,
194 const char* b_str,
195 const char* g_x_str,
196 const char* g_y_str,
197 const char* order_str,
198 const OID& oid) {
199 BOTAN_ARG_CHECK(oid.has_value(), "EC_Group::load_EC_group_info OID must be set");
200
201 const BigInt p(p_str);
202 const BigInt a(a_str);
203 const BigInt b(b_str);
204 const BigInt g_x(g_x_str);
205 const BigInt g_y(g_y_str);
206 const BigInt order(order_str);
207 const BigInt cofactor(1); // implicit
208
209 return EC_Group_Data::create(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin);
210}
211
212//static
213std::pair<std::shared_ptr<EC_Group_Data>, bool> EC_Group::BER_decode_EC_group(std::span<const uint8_t> bits,
214 EC_Group_Source source) {
215 BER_Decoder ber(bits);
216
217 auto next_obj_type = ber.peek_next_object().type_tag();
218
219 if(next_obj_type == ASN1_Type::ObjectId) {
220 OID oid;
221 ber.decode(oid);
222
223 auto data = ec_group_data().lookup(oid);
224 if(!data) {
225 throw Decoding_Error(fmt("Unknown namedCurve OID '{}'", oid.to_string()));
226 }
227
228 return std::make_pair(data, false);
229 } else if(next_obj_type == ASN1_Type::Sequence) {
230 BigInt p, a, b, order, cofactor;
231 std::vector<uint8_t> base_pt;
232 std::vector<uint8_t> seed;
233
234 ber.start_sequence()
235 .decode_and_check<size_t>(1, "Unknown ECC param version code")
236 .start_sequence()
237 .decode_and_check(OID({1, 2, 840, 10045, 1, 1}), "Only prime ECC fields supported")
238 .decode(p)
239 .end_cons()
240 .start_sequence()
241 .decode_octet_string_bigint(a)
242 .decode_octet_string_bigint(b)
243 .decode_optional_string(seed, ASN1_Type::BitString, ASN1_Type::BitString)
244 .end_cons()
245 .decode(base_pt, ASN1_Type::OctetString)
246 .decode(order)
247 .decode(cofactor)
248 .end_cons()
249 .verify_end();
250
251 if(p.bits() < 112 || p.bits() > 521 || p.is_negative()) {
252 throw Decoding_Error("ECC p parameter is invalid size");
253 }
254
255 // TODO(Botan4) we can remove this check since we'll only accept pre-registered groups
257 if(!is_bailie_psw_probable_prime(p, mod_p)) {
258 throw Decoding_Error("ECC p parameter is not a prime");
259 }
260
261 if(a.is_negative() || a >= p) {
262 throw Decoding_Error("Invalid ECC a parameter");
263 }
264
265 if(b <= 0 || b >= p) {
266 throw Decoding_Error("Invalid ECC b parameter");
267 }
268
269 if(order.is_negative() || order.is_zero() || order >= 2 * p) {
270 throw Decoding_Error("Invalid ECC group order");
271 }
272
273 // TODO(Botan4) we can remove this check since we'll only accept pre-registered groups
276 throw Decoding_Error("Invalid ECC order parameter");
277 }
278
279 // TODO(Botan4) Require cofactor == 1
280 if(cofactor <= 0 || cofactor >= 16) {
281 throw Decoding_Error("Invalid ECC cofactor parameter");
282 }
283
284 const size_t p_bytes = p.bytes();
285 if(base_pt.size() != 1 + p_bytes && base_pt.size() != 1 + 2 * p_bytes) {
286 throw Decoding_Error("Invalid ECC base point encoding");
287 }
288
289 auto [g_x, g_y] = [&]() {
290 const uint8_t hdr = base_pt[0];
291
292 if(hdr == 0x04 && base_pt.size() == 1 + 2 * p_bytes) {
293 BigInt x = BigInt::decode(&base_pt[1], p_bytes);
294 BigInt y = BigInt::decode(&base_pt[p_bytes + 1], p_bytes);
295
296 if(x < p && y < p) {
297 return std::make_pair(x, y);
298 }
299 } else if((hdr == 0x02 || hdr == 0x03) && base_pt.size() == 1 + p_bytes) {
300 // TODO(Botan4) remove this branch; we won't support compressed points
301 BigInt x = BigInt::decode(&base_pt[1], p_bytes);
302 BigInt y = sqrt_modulo_prime(((x * x + a) * x + b) % p, p);
303
304 if(x < p && y >= 0) {
305 const bool y_mod_2 = (hdr & 0x01) == 1;
306 if(y.get_bit(0) != y_mod_2) {
307 y = p - y;
308 }
309
310 return std::make_pair(x, y);
311 }
312 }
313
314 throw Decoding_Error("Invalid ECC base point encoding");
315 }();
316
317 // TODO(Botan4) we can remove this check since we'll only accept pre-registered groups
318 auto y2 = mod_p.square(g_y);
319 auto x3_ax_b = mod_p.reduce(mod_p.cube(g_x) + mod_p.multiply(a, g_x) + b);
320 if(y2 != x3_ax_b) {
321 throw Decoding_Error("Invalid ECC base point");
322 }
323
324 auto data = ec_group_data().lookup_or_create_without_oid(p, a, b, g_x, g_y, order, cofactor, source);
325 return std::make_pair(data, true);
326 } else if(next_obj_type == ASN1_Type::Null) {
327 throw Decoding_Error("Decoding ImplicitCA ECC parameters is not supported");
328 } else {
329 throw Decoding_Error(
330 fmt("Unexpected tag {} while decoding ECC domain params", asn1_tag_to_string(next_obj_type)));
331 }
332}
333
334EC_Group::EC_Group() = default;
335
336EC_Group::~EC_Group() = default;
337
338EC_Group::EC_Group(const EC_Group&) = default;
339
340EC_Group& EC_Group::operator=(const EC_Group&) = default;
341
342// Internal constructor
343EC_Group::EC_Group(std::shared_ptr<EC_Group_Data>&& data) : m_data(std::move(data)) {}
344
345//static
346bool EC_Group::supports_named_group(std::string_view name) {
347 return EC_Group::known_named_groups().contains(std::string(name));
348}
349
350//static
352#if defined(BOTAN_HAS_LEGACY_EC_POINT) || defined(BOTAN_HAS_PCURVES_GENERIC)
353 return true;
354#else
355 return false;
356#endif
357}
358
359//static
361 auto data = ec_group_data().lookup(oid);
362
363 if(!data) {
364 throw Invalid_Argument(fmt("No EC_Group associated with OID '{}'", oid.to_string()));
365 }
366
367 return EC_Group(std::move(data));
368}
369
370//static
371EC_Group EC_Group::from_name(std::string_view name) {
372 std::shared_ptr<EC_Group_Data> data;
373
374 if(auto oid = OID::from_name(name)) {
375 data = ec_group_data().lookup(oid.value());
376 }
377
378 if(!data) {
379 throw Invalid_Argument(fmt("Unknown EC_Group '{}'", name));
380 }
381
382 return EC_Group(std::move(data));
383}
384
385EC_Group::EC_Group(std::string_view str) {
386 if(str.empty()) {
387 return; // no initialization / uninitialized
388 }
389
390 try {
391 const OID oid = OID::from_string(str);
392 if(oid.has_value()) {
393 m_data = ec_group_data().lookup(oid);
394 }
395 } catch(...) {}
396
397 if(m_data == nullptr) {
398 if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") {
399 // OK try it as PEM ...
400 const auto ber = PEM_Code::decode_check_label(str, "EC PARAMETERS");
401
402 auto data = BER_decode_EC_group(ber, EC_Group_Source::ExternalSource);
403 this->m_data = data.first;
404 this->m_explicit_encoding = data.second;
405 }
406 }
407
408 if(m_data == nullptr) {
409 throw Invalid_Argument(fmt("Unknown ECC group '{}'", str));
410 }
411}
412
413//static
414EC_Group EC_Group::from_PEM(std::string_view pem) {
415 const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
416 return EC_Group(ber);
417}
418
420 const BigInt& a,
421 const BigInt& b,
422 const BigInt& base_x,
423 const BigInt& base_y,
424 const BigInt& order,
425 const BigInt& cofactor,
426 const OID& oid) {
427 if(oid.has_value()) {
428 m_data = ec_group_data().lookup_or_create(
429 p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
430 } else {
431 m_data = ec_group_data().lookup_or_create_without_oid(
432 p, a, b, base_x, base_y, order, cofactor, EC_Group_Source::ExternalSource);
433 }
434}
435
437 const BigInt& p,
438 const BigInt& a,
439 const BigInt& b,
440 const BigInt& base_x,
441 const BigInt& base_y,
442 const BigInt& order) {
443 BOTAN_ARG_CHECK(oid.has_value(), "An OID is required for creating an EC_Group");
444
445 // TODO(Botan4) remove this and require 192 bits minimum
446#if defined(BOTAN_DISABLE_DEPRECATED_FEATURES)
447 constexpr size_t p_bits_lower_bound = 192;
448#else
449 constexpr size_t p_bits_lower_bound = 128;
450#endif
451
452 BOTAN_ARG_CHECK(p.bits() >= p_bits_lower_bound, "EC_Group p too small");
453 BOTAN_ARG_CHECK(p.bits() <= 521, "EC_Group p too large");
454
455 if(p.bits() == 521) {
456 const auto p521 = BigInt::power_of_2(521) - 1;
457 BOTAN_ARG_CHECK(p == p521, "EC_Group with p of 521 bits must be 2**521-1");
458 } else if(p.bits() == 239) {
459 const auto x962_p239 = []() {
460 BigInt p239;
461 for(size_t i = 0; i != 239; ++i) {
462 if(i < 47 || ((i >= 94) && (i != 143))) {
463 p239.set_bit(i);
464 }
465 }
466 return p239;
467 }();
468
469 BOTAN_ARG_CHECK(p == x962_p239, "EC_Group with p of 239 bits must be the X9.62 prime");
470 } else {
471 BOTAN_ARG_CHECK(p.bits() % 32 == 0, "EC_Group p must be a multiple of 32 bits");
472 }
473
474 BOTAN_ARG_CHECK(p % 4 == 3, "EC_Group p must be congruent to 3 modulo 4");
475
476 BOTAN_ARG_CHECK(a >= 0 && a < p, "EC_Group a is invalid");
477 BOTAN_ARG_CHECK(b > 0 && b < p, "EC_Group b is invalid");
478 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p, "EC_Group base_x is invalid");
479 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p, "EC_Group base_y is invalid");
480 BOTAN_ARG_CHECK(p.bits() == order.bits(), "EC_Group p and order must have the same number of bits");
481
483 BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(p, mod_p), "EC_Group p is not prime");
484
486 BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(order, mod_order), "EC_Group order is not prime");
487
488 // This catches someone "ignoring" a cofactor and just trying to
489 // provide the subgroup order
490 BOTAN_ARG_CHECK((p - order).abs().bits() <= (p.bits() / 2) + 1, "Hasse bound invalid");
491
492 // Check that 4*a^3 + 27*b^2 != 0
493 const auto discriminant = mod_p.reduce(mod_p.multiply(4, mod_p.cube(a)) + mod_p.multiply(27, mod_p.square(b)));
494 BOTAN_ARG_CHECK(discriminant != 0, "EC_Group discriminant is invalid");
495
496 // Check that the generator (base_x,base_y) is on the curve; y^2 = x^3 + a*x + b
497 auto y2 = mod_p.square(base_y);
498 auto x3_ax_b = mod_p.reduce(mod_p.cube(base_x) + mod_p.multiply(a, base_x) + b);
499 BOTAN_ARG_CHECK(y2 == x3_ax_b, "EC_Group generator is not on the curve");
500
501 BigInt cofactor(1);
502
503 m_data =
504 ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
505}
506
507EC_Group::EC_Group(std::span<const uint8_t> ber) {
508 auto data = BER_decode_EC_group(ber, EC_Group_Source::ExternalSource);
509 m_data = data.first;
510 m_explicit_encoding = data.second;
511}
512
513const EC_Group_Data& EC_Group::data() const {
514 if(m_data == nullptr) {
515 throw Invalid_State("EC_Group uninitialized");
516 }
517 return *m_data;
518}
519
520size_t EC_Group::get_p_bits() const {
521 return data().p_bits();
522}
523
524size_t EC_Group::get_p_bytes() const {
525 return data().p_bytes();
526}
527
529 return data().order_bits();
530}
531
533 return data().order_bytes();
534}
535
536const BigInt& EC_Group::get_p() const {
537 return data().p();
538}
539
540const BigInt& EC_Group::get_a() const {
541 return data().a();
542}
543
544const BigInt& EC_Group::get_b() const {
545 return data().b();
546}
547
548#if defined(BOTAN_HAS_LEGACY_EC_POINT)
549const EC_Point& EC_Group::get_base_point() const {
550 return data().base_point();
551}
552
553const EC_Point& EC_Group::generator() const {
554 return data().base_point();
555}
556
557bool EC_Group::verify_public_element(const EC_Point& point) const {
558 //check that public point is not at infinity
559 if(point.is_zero()) {
560 return false;
561 }
562
563 //check that public point is on the curve
564 if(point.on_the_curve() == false) {
565 return false;
566 }
567
568 //check that public point has order q
569 if((point * get_order()).is_zero() == false) {
570 return false;
571 }
572
573 if(has_cofactor()) {
574 if((point * get_cofactor()).is_zero()) {
575 return false;
576 }
577 }
578
579 return true;
580}
581
582#endif
583
585 return data().order();
586}
587
588const BigInt& EC_Group::get_g_x() const {
589 return data().g_x();
590}
591
592const BigInt& EC_Group::get_g_y() const {
593 return data().g_y();
594}
595
597 return data().cofactor();
598}
599
601 return data().has_cofactor();
602}
603
605 return data().oid();
606}
607
609 return data().source();
610}
611
613 return data().engine();
614}
615
616std::vector<uint8_t> EC_Group::DER_encode() const {
617 const auto& der_named_curve = data().der_named_curve();
618 // TODO(Botan4) this can be removed because an OID will always be defined
619 if(der_named_curve.empty()) {
620 throw Encoding_Error("Cannot encode EC_Group as OID because OID not set");
621 }
622
623 return der_named_curve;
624}
625
626std::vector<uint8_t> EC_Group::DER_encode(EC_Group_Encoding form) const {
627 if(form == EC_Group_Encoding::Explicit) {
628 std::vector<uint8_t> output;
629 DER_Encoder der(output);
630 const size_t ecpVers1 = 1;
631 const OID curve_type("1.2.840.10045.1.1"); // prime field
632
633 const size_t p_bytes = get_p_bytes();
634
635 const auto generator = EC_AffinePoint::generator(*this).serialize_uncompressed();
636
637 der.start_sequence()
638 .encode(ecpVers1)
640 .encode(curve_type)
641 .encode(get_p())
642 .end_cons()
644 .encode(get_a().serialize(p_bytes), ASN1_Type::OctetString)
645 .encode(get_b().serialize(p_bytes), ASN1_Type::OctetString)
646 .end_cons()
647 .encode(generator, ASN1_Type::OctetString)
648 .encode(get_order())
650 .end_cons();
651 return output;
652 } else if(form == EC_Group_Encoding::NamedCurve) {
653 return this->DER_encode();
654 } else if(form == EC_Group_Encoding::ImplicitCA) {
655 return {0x00, 0x05};
656 } else {
657 throw Internal_Error("EC_Group::DER_encode: Unknown encoding");
658 }
659}
660
662 const std::vector<uint8_t> der = DER_encode(form);
663 return PEM_Code::encode(der, "EC PARAMETERS");
664}
665
666bool EC_Group::operator==(const EC_Group& other) const {
667 if(m_data == other.m_data) {
668 return true; // same shared rep
669 }
670
671 return (get_p() == other.get_p() && get_a() == other.get_a() && get_b() == other.get_b() &&
672 get_g_x() == other.get_g_x() && get_g_y() == other.get_g_y() && get_order() == other.get_order() &&
673 get_cofactor() == other.get_cofactor());
674}
675
676bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
677 const bool is_builtin = source() == EC_Group_Source::Builtin;
678
679 if(is_builtin && !strong) {
680 return true;
681 }
682
683 // TODO(Botan4) this can probably all be removed once the deprecated EC_Group
684 // constructor is removed, since at that point it no longer becomes possible
685 // to create an EC_Group which fails to satisfy these conditions
686
687 const BigInt& p = get_p();
688 const BigInt& a = get_a();
689 const BigInt& b = get_b();
690 const BigInt& order = get_order();
691
692 if(p <= 3 || order <= 0) {
693 return false;
694 }
695 if(a < 0 || a >= p) {
696 return false;
697 }
698 if(b <= 0 || b >= p) {
699 return false;
700 }
701
702 const size_t test_prob = 128;
703 const bool is_randomly_generated = is_builtin;
704
705 //check if field modulus is prime
706 if(!is_prime(p, rng, test_prob, is_randomly_generated)) {
707 return false;
708 }
709
710 //check if order is prime
711 if(!is_prime(order, rng, test_prob, is_randomly_generated)) {
712 return false;
713 }
714
715 //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero
717
718 const BigInt discriminant = mod_p.reduce(mod_p.multiply(4, mod_p.cube(a)) + mod_p.multiply(27, mod_p.square(b)));
719
720 if(discriminant == 0) {
721 return false;
722 }
723
724 //check for valid cofactor
725 if(get_cofactor() < 1) {
726 return false;
727 }
728
729#if defined(BOTAN_HAS_LEGACY_EC_POINT)
730 const EC_Point& base_point = get_base_point();
731 //check if the base point is on the curve
732 if(!base_point.on_the_curve()) {
733 return false;
734 }
735 if((base_point * get_cofactor()).is_zero()) {
736 return false;
737 }
738 //check if order of the base point is correct
739 if(!(base_point * order).is_zero()) {
740 return false;
741 }
742#endif
743
744 // check the Hasse bound (roughly)
745 if((p - get_cofactor() * order).abs().bits() > (p.bits() / 2) + 1) {
746 return false;
747 }
748
749 return true;
750}
751
752EC_Group::Mul2Table::Mul2Table(const EC_AffinePoint& h) : m_tbl(h._group()->make_mul2_table(h._inner())) {}
753
755
756std::optional<EC_AffinePoint> EC_Group::Mul2Table::mul2_vartime(const EC_Scalar& x, const EC_Scalar& y) const {
757 auto pt = m_tbl->mul2_vartime(x._inner(), y._inner());
758 if(pt) {
759 return EC_AffinePoint::_from_inner(std::move(pt));
760 } else {
761 return {};
762 }
763}
764
766 const EC_Scalar& x,
767 const EC_Scalar& y) const {
768 return m_tbl->mul2_vartime_x_mod_order_eq(v._inner(), x._inner(), y._inner());
769}
770
772 const EC_Scalar& c,
773 const EC_Scalar& x,
774 const EC_Scalar& y) const {
775 return this->mul2_vartime_x_mod_order_eq(v, c * x, c * y);
776}
777
778} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:61
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:31
static Barrett_Reduction for_public_modulus(const BigInt &m)
Definition barrett.cpp:33
static BigInt decode(const uint8_t buf[], size_t length)
Definition bigint.h:857
void set_bit(size_t n)
Definition bigint.h:463
size_t bits() const
Definition bigint.cpp:310
static BigInt power_of_2(size_t n)
Definition bigint.h:820
DER_Encoder & start_sequence()
Definition der_enc.h:64
DER_Encoder & end_cons()
Definition der_enc.cpp:171
DER_Encoder & encode(bool b)
Definition der_enc.cpp:250
T serialize_uncompressed() const
Definition ec_apoint.h:187
static EC_AffinePoint _from_inner(std::unique_ptr< EC_AffinePoint_Data > inner)
static EC_AffinePoint generator(const EC_Group &group)
Return the standard group generator.
Definition ec_apoint.cpp:83
std::optional< EC_AffinePoint > mul2_vartime(const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:756
Mul2Table(const EC_AffinePoint &h)
Definition ec_group.cpp:752
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:765
static std::shared_ptr< EC_Group_Data > create(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &g_x, const BigInt &g_y, const BigInt &order, const BigInt &cofactor, const OID &oid, EC_Group_Source source)
static EC_Group from_name(std::string_view name)
Definition ec_group.cpp:371
static EC_Group from_PEM(std::string_view pem)
Definition ec_group.cpp:414
const BigInt & get_b() const
Definition ec_group.cpp:544
const BigInt & get_a() const
Definition ec_group.cpp:540
const BigInt & get_g_y() const
Definition ec_group.cpp:592
const BigInt & get_cofactor() const
Definition ec_group.cpp:596
BigInt mod_order(const BigInt &x) const
Definition ec_group.h:650
bool operator==(const EC_Group &other) const
Definition ec_group.cpp:666
EC_Group_Engine engine() const
Definition ec_group.cpp:612
EC_Group_Source source() const
Definition ec_group.cpp:608
const BigInt & get_p() const
Definition ec_group.cpp:536
bool verify_group(RandomNumberGenerator &rng, bool strong=false) const
Definition ec_group.cpp:676
const BigInt & get_order() const
Definition ec_group.cpp:584
size_t get_p_bits() const
Definition ec_group.cpp:520
static EC_Group from_OID(const OID &oid)
Definition ec_group.cpp:360
static std::shared_ptr< EC_Group_Data > EC_group_info(const OID &oid)
Definition ec_named.cpp:15
std::vector< uint8_t > DER_encode() const
Definition ec_group.cpp:616
const BigInt & get_g_x() const
Definition ec_group.cpp:588
EC_Group(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &base_x, const BigInt &base_y, const BigInt &order, const BigInt &cofactor, const OID &oid=OID())
Definition ec_group.cpp:419
const OID & get_curve_oid() const
Definition ec_group.cpp:604
static bool supports_application_specific_group()
Definition ec_group.cpp:351
static const std::set< std::string > & known_named_groups()
Definition ec_named.cpp:476
bool has_cofactor() const
Definition ec_group.cpp:600
static size_t clear_registered_curve_data()
Definition ec_group.cpp:187
static bool supports_named_group(std::string_view name)
Definition ec_group.cpp:346
EC_Group & operator=(const EC_Group &)
size_t get_p_bytes() const
Definition ec_group.cpp:524
static OID EC_group_identity_from_order(const BigInt &order)
Definition ec_named.cpp:356
std::string PEM_encode(EC_Group_Encoding form=EC_Group_Encoding::Explicit) const
Definition ec_group.cpp:661
size_t get_order_bits() const
Definition ec_group.cpp:528
size_t get_order_bytes() const
Definition ec_group.cpp:532
bool on_the_curve() const
Definition ec_point.cpp:667
const EC_Scalar_Data & _inner() const
Definition ec_scalar.h:226
static std::optional< OID > from_name(std::string_view name)
Definition asn1_oid.cpp:72
bool has_value() const
Definition asn1_obj.h:272
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 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:56
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
EC_Group_Engine
Definition ec_group.h:66
BigInt abs(const BigInt &n)
Definition numthry.h:24
secure_vector< T > lock(const std::vector< T > &in)
Definition secmem.h:77
bool is_bailie_psw_probable_prime(const BigInt &n, const Barrett_Reduction &mod_n)
Definition primality.cpp:96
bool is_prime(const BigInt &n, RandomNumberGenerator &rng, size_t prob, bool is_random)
Definition numthry.cpp:355
lock_guard< T > lock_guard_type
Definition mutex.h:55
BigInt sqrt_modulo_prime(const BigInt &a, const BigInt &p)
Definition numthry.cpp:26
EC_Group_Encoding
Definition ec_group.h:36