Botan 3.6.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/pem.h>
17#include <botan/reducer.h>
18#include <botan/rng.h>
19#include <botan/internal/ec_inner_data.h>
20#include <botan/internal/fmt.h>
21#include <botan/internal/primality.h>
22#include <vector>
23
24namespace Botan {
25
26class EC_Group_Data_Map final {
27 public:
28 EC_Group_Data_Map() = default;
29
30 size_t clear() {
32 size_t count = m_registered_curves.size();
33 m_registered_curves.clear();
34 return count;
35 }
36
37 std::shared_ptr<EC_Group_Data> lookup(const OID& oid) {
39
40 for(auto i : m_registered_curves) {
41 if(i->oid() == oid) {
42 return i;
43 }
44 }
45
46 // Not found, check hardcoded data
47 std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
48
49 if(data) {
50 for(auto curve : m_registered_curves) {
51 if(curve->oid().empty() == true && curve->params_match(*data)) {
52 curve->set_oid(oid);
53 return curve;
54 }
55 }
56
57 m_registered_curves.push_back(data);
58 return data;
59 }
60
61 // Nope, unknown curve
62 return std::shared_ptr<EC_Group_Data>();
63 }
64
65 std::shared_ptr<EC_Group_Data> lookup_or_create(const BigInt& p,
66 const BigInt& a,
67 const BigInt& b,
68 const BigInt& g_x,
69 const BigInt& g_y,
70 const BigInt& order,
71 const BigInt& cofactor,
72 const OID& oid,
73 EC_Group_Source source) {
75
76 for(auto i : m_registered_curves) {
77 /*
78 * The params may be the same but you are trying to register under a
79 * different OID than the one we are using, so using a different
80 * group, since EC_Group's model assumes a single OID per group.
81 */
82 if(!oid.empty() && !i->oid().empty() && i->oid() != oid) {
83 continue;
84 }
85
86 const bool same_oid = !oid.empty() && i->oid() == oid;
87 const bool same_params = i->params_match(p, a, b, g_x, g_y, order, cofactor);
88
89 /*
90 * If the params and OID are the same then we are done, just return
91 * the already registered curve obj.
92 */
93 if(same_params && same_oid) {
94 return i;
95 }
96
97 /*
98 * If same params and the new OID is empty, then that's ok too
99 */
100 if(same_params && oid.empty()) {
101 return i;
102 }
103
104 /*
105 * Check for someone trying to reuse an already in-use OID
106 */
107 if(same_oid && !same_params) {
108 throw Invalid_Argument("Attempting to register a curve using OID " + oid.to_string() +
109 " but a distinct curve is already registered using that OID");
110 }
111
112 /*
113 * If the same curve was previously created without an OID but is now
114 * being registered again using an OID, save that OID.
115 */
116 if(same_params && i->oid().empty() && !oid.empty()) {
117 i->set_oid(oid);
118 return i;
119 }
120 }
121
122 /*
123 Not found in current list, so we need to create a new entry
124
125 If an OID is set, try to look up relative our static tables to detect a duplicate
126 registration under an OID
127 */
128
129 std::shared_ptr<EC_Group_Data> new_group =
130 std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
131
132 if(oid.has_value()) {
133 std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid);
134 if(data != nullptr && !new_group->params_match(*data)) {
135 throw Invalid_Argument("Attempting to register an EC group under OID of hardcoded group");
136 }
137 } else {
138 // Here try to use the order as a hint to look up the group id, to identify common groups
139 const OID oid_from_store = EC_Group::EC_group_identity_from_order(order);
140 if(oid_from_store.has_value()) {
141 std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid_from_store);
142
143 /*
144 If EC_group_identity_from_order returned an OID then looking up that OID
145 must always return a result.
146 */
147 BOTAN_ASSERT_NOMSG(data != nullptr);
148
149 /*
150 It is possible (if unlikely) that someone is registering another group
151 that happens to have an order equal to that of a well known group -
152 so verify all values before assigning the OID.
153 */
154 if(new_group->params_match(*data)) {
155 new_group->set_oid(oid_from_store);
156 }
157 }
158 }
159
160 m_registered_curves.push_back(new_group);
161 return new_group;
162 }
163
164 private:
165 mutex_type m_mutex;
166 std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves;
167};
168
169//static
170EC_Group_Data_Map& EC_Group::ec_group_data() {
171 /*
172 * This exists purely to ensure the allocator is constructed before g_ec_data,
173 * which ensures that its destructor runs after ~g_ec_data is complete.
174 */
175
176 static Allocator_Initializer g_init_allocator;
177 static EC_Group_Data_Map g_ec_data;
178 return g_ec_data;
179}
180
181//static
183 return ec_group_data().clear();
184}
185
186//static
187std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(const char* p_str,
188 const char* a_str,
189 const char* b_str,
190 const char* g_x_str,
191 const char* g_y_str,
192 const char* order_str,
193 const OID& oid) {
194 const BigInt p(p_str);
195 const BigInt a(a_str);
196 const BigInt b(b_str);
197 const BigInt g_x(g_x_str);
198 const BigInt g_y(g_y_str);
199 const BigInt order(order_str);
200 const BigInt cofactor(1); // implicit
201
202 return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin);
203}
204
205//static
206std::pair<std::shared_ptr<EC_Group_Data>, bool> EC_Group::BER_decode_EC_group(std::span<const uint8_t> bits,
207 EC_Group_Source source) {
208 BER_Decoder ber(bits);
209 BER_Object obj = ber.get_next_object();
210
211 if(obj.type() == ASN1_Type::ObjectId) {
212 OID oid;
213 BER_Decoder(bits).decode(oid);
214
215 auto data = ec_group_data().lookup(oid);
216 if(!data) {
217 throw Decoding_Error(fmt("Unknown namedCurve OID '{}'", oid.to_string()));
218 }
219
220 return std::make_pair(data, false);
221 }
222
223 if(obj.type() == ASN1_Type::Sequence) {
224 BigInt p, a, b, order, cofactor;
225 std::vector<uint8_t> base_pt;
226 std::vector<uint8_t> seed;
227
228 BER_Decoder(bits)
229 .start_sequence()
230 .decode_and_check<size_t>(1, "Unknown ECC param version code")
231 .start_sequence()
232 .decode_and_check(OID("1.2.840.10045.1.1"), "Only prime ECC fields supported")
233 .decode(p)
234 .end_cons()
235 .start_sequence()
236 .decode_octet_string_bigint(a)
237 .decode_octet_string_bigint(b)
238 .decode_optional_string(seed, ASN1_Type::BitString, ASN1_Type::BitString)
239 .end_cons()
240 .decode(base_pt, ASN1_Type::OctetString)
241 .decode(order)
242 .decode(cofactor)
243 .end_cons()
244 .verify_end();
245
246 if(p.bits() < 112 || p.bits() > 521) {
247 throw Decoding_Error("ECC p parameter is invalid size");
248 }
249
250 if(p.is_negative() || !is_bailie_psw_probable_prime(p)) {
251 throw Decoding_Error("ECC p parameter is not a prime");
252 }
253
254 if(a.is_negative() || a >= p) {
255 throw Decoding_Error("Invalid ECC a parameter");
256 }
257
258 if(b <= 0 || b >= p) {
259 throw Decoding_Error("Invalid ECC b parameter");
260 }
261
262 if(order <= 0 || !is_bailie_psw_probable_prime(order)) {
263 throw Decoding_Error("Invalid ECC order parameter");
264 }
265
266 if(cofactor <= 0 || cofactor >= 16) {
267 throw Decoding_Error("Invalid ECC cofactor parameter");
268 }
269
270 std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b);
271
272 auto data =
273 ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID(), source);
274 return std::make_pair(data, true);
275 }
276
277 if(obj.type() == ASN1_Type::Null) {
278 throw Decoding_Error("Cannot handle ImplicitCA ECC parameters");
279 } else {
280 throw Decoding_Error(fmt("Unexpected tag {} while decoding ECC domain params", asn1_tag_to_string(obj.type())));
281 }
282}
283
284EC_Group::EC_Group() = default;
285
286EC_Group::~EC_Group() = default;
287
288EC_Group::EC_Group(const EC_Group&) = default;
289
290EC_Group& EC_Group::operator=(const EC_Group&) = default;
291
292// Internal constructor
293EC_Group::EC_Group(std::shared_ptr<EC_Group_Data>&& data) : m_data(std::move(data)) {}
294
295//static
297 auto data = ec_group_data().lookup(oid);
298
299 if(!data) {
300 throw Invalid_Argument(fmt("No EC_Group associated with OID '{}'", oid.to_string()));
301 }
302
303 return EC_Group(std::move(data));
304}
305
306//static
308 std::shared_ptr<EC_Group_Data> data;
309
310 if(auto oid = OID::from_name(name)) {
311 data = ec_group_data().lookup(oid.value());
312 }
313
314 if(!data) {
315 throw Invalid_Argument(fmt("Unknown EC_Group '{}'", name));
316 }
317
318 return EC_Group(std::move(data));
319}
320
321EC_Group::EC_Group(std::string_view str) {
322 if(str.empty()) {
323 return; // no initialization / uninitialized
324 }
325
326 try {
327 const OID oid = OID::from_string(str);
328 if(oid.has_value()) {
329 m_data = ec_group_data().lookup(oid);
330 }
331 } catch(...) {}
332
333 if(m_data == nullptr) {
334 if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") {
335 // OK try it as PEM ...
336 const auto ber = PEM_Code::decode_check_label(str, "EC PARAMETERS");
337
338 auto data = BER_decode_EC_group(ber, EC_Group_Source::ExternalSource);
339 this->m_data = data.first;
340 this->m_explicit_encoding = data.second;
341 }
342 }
343
344 if(m_data == nullptr) {
345 throw Invalid_Argument(fmt("Unknown ECC group '{}'", str));
346 }
347}
348
349//static
350EC_Group EC_Group::from_PEM(std::string_view pem) {
351 const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
352 return EC_Group(ber);
353}
354
356 const BigInt& a,
357 const BigInt& b,
358 const BigInt& base_x,
359 const BigInt& base_y,
360 const BigInt& order,
361 const BigInt& cofactor,
362 const OID& oid) {
363 m_data =
364 ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
365}
366
368 const BigInt& p,
369 const BigInt& a,
370 const BigInt& b,
371 const BigInt& base_x,
372 const BigInt& base_y,
373 const BigInt& order) {
374 BOTAN_ARG_CHECK(oid.has_value(), "An OID is required for creating an EC_Group");
375 BOTAN_ARG_CHECK(p.bits() >= 128, "EC_Group p too small");
376 BOTAN_ARG_CHECK(p.bits() <= 521, "EC_Group p too large");
377
378 if(p.bits() == 521) {
379 BOTAN_ARG_CHECK(p == BigInt::power_of_2(521) - 1, "EC_Group with p of 521 bits must be 2**521-1");
380 } else {
381 BOTAN_ARG_CHECK(p.bits() % 32 == 0, "EC_Group p must be a multiple of 32 bits");
382 }
383
384 BOTAN_ARG_CHECK(p % 4 == 3, "EC_Group p must be congruent to 3 modulo 4");
385
386 BOTAN_ARG_CHECK(a >= 0 && a < p, "EC_Group a is invalid");
387 BOTAN_ARG_CHECK(b > 0 && b < p, "EC_Group b is invalid");
388 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p, "EC_Group base_x is invalid");
389 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p, "EC_Group base_y is invalid");
390 BOTAN_ARG_CHECK(p.bits() == order.bits(), "EC_Group p and order must have the same number of bits");
391
392 BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(p), "EC_Group p is not prime");
393 BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(order), "EC_Group order is not prime");
394
395 // This catches someone "ignoring" a cofactor and just trying to
396 // provide the subgroup order
397 BOTAN_ARG_CHECK((p - order).abs().bits() <= (p.bits() / 2) + 1, "Hasse bound invalid");
398
399 BigInt cofactor(1);
400
401 m_data =
402 ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
403}
404
405EC_Group::EC_Group(std::span<const uint8_t> ber) {
406 auto data = BER_decode_EC_group(ber, EC_Group_Source::ExternalSource);
407 m_data = data.first;
408 m_explicit_encoding = data.second;
409}
410
411const EC_Group_Data& EC_Group::data() const {
412 if(m_data == nullptr) {
413 throw Invalid_State("EC_Group uninitialized");
414 }
415 return *m_data;
416}
417
418size_t EC_Group::get_p_bits() const {
419 return data().p_bits();
420}
421
422size_t EC_Group::get_p_bytes() const {
423 return data().p_bytes();
424}
425
427 return data().order_bits();
428}
429
431 return data().order_bytes();
432}
433
434const BigInt& EC_Group::get_p() const {
435 return data().p();
436}
437
438const BigInt& EC_Group::get_a() const {
439 return data().a();
440}
441
442const BigInt& EC_Group::get_b() const {
443 return data().b();
444}
445
447 return data().base_point();
448}
449
451 return data().base_point();
452}
453
455 return data().order();
456}
457
458const BigInt& EC_Group::get_g_x() const {
459 return data().g_x();
460}
461
462const BigInt& EC_Group::get_g_y() const {
463 return data().g_y();
464}
465
467 return data().cofactor();
468}
469
471 return data().has_cofactor();
472}
473
475 return data().mod_order(k);
476}
477
479 return data().oid();
480}
481
483 return data().source();
484}
485
486std::vector<uint8_t> EC_Group::DER_encode() const {
487 const auto& der_named_curve = data().der_named_curve();
488 // TODO(Botan4) this can be removed because an OID will always be defined
489 if(der_named_curve.empty()) {
490 throw Encoding_Error("Cannot encode EC_Group as OID because OID not set");
491 }
492
493 return der_named_curve;
494}
495
496std::vector<uint8_t> EC_Group::DER_encode(EC_Group_Encoding form) const {
497 if(form == EC_Group_Encoding::Explicit) {
498 std::vector<uint8_t> output;
499 DER_Encoder der(output);
500 const size_t ecpVers1 = 1;
501 const OID curve_type("1.2.840.10045.1.1"); // prime field
502
503 const size_t p_bytes = get_p_bytes();
504
505 der.start_sequence()
506 .encode(ecpVers1)
508 .encode(curve_type)
509 .encode(get_p())
510 .end_cons()
512 .encode(get_a().serialize(p_bytes), ASN1_Type::OctetString)
513 .encode(get_b().serialize(p_bytes), ASN1_Type::OctetString)
514 .end_cons()
516 .encode(get_order())
518 .end_cons();
519 return output;
520 } else if(form == EC_Group_Encoding::NamedCurve) {
521 return this->DER_encode();
522 } else if(form == EC_Group_Encoding::ImplicitCA) {
523 return {0x00, 0x05};
524 } else {
525 throw Internal_Error("EC_Group::DER_encode: Unknown encoding");
526 }
527}
528
529std::string EC_Group::PEM_encode() const {
530 const std::vector<uint8_t> der = DER_encode(EC_Group_Encoding::Explicit);
531 return PEM_Code::encode(der, "EC PARAMETERS");
532}
533
534bool EC_Group::operator==(const EC_Group& other) const {
535 if(m_data == other.m_data) {
536 return true; // same shared rep
537 }
538
539 return (get_p() == other.get_p() && get_a() == other.get_a() && get_b() == other.get_b() &&
540 get_g_x() == other.get_g_x() && get_g_y() == other.get_g_y() && get_order() == other.get_order() &&
541 get_cofactor() == other.get_cofactor());
542}
543
545 //check that public point is not at infinity
546 if(point.is_zero()) {
547 return false;
548 }
549
550 //check that public point is on the curve
551 if(point.on_the_curve() == false) {
552 return false;
553 }
554
555 //check that public point has order q
556 if((point * get_order()).is_zero() == false) {
557 return false;
558 }
559
560 if(has_cofactor()) {
561 if((point * get_cofactor()).is_zero()) {
562 return false;
563 }
564 }
565
566 return true;
567}
568
569bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
570 const bool is_builtin = source() == EC_Group_Source::Builtin;
571
572 if(is_builtin && !strong) {
573 return true;
574 }
575
576 const BigInt& p = get_p();
577 const BigInt& a = get_a();
578 const BigInt& b = get_b();
579 const BigInt& order = get_order();
580 const EC_Point& base_point = get_base_point();
581
582 if(p <= 3 || order <= 0) {
583 return false;
584 }
585 if(a < 0 || a >= p) {
586 return false;
587 }
588 if(b <= 0 || b >= p) {
589 return false;
590 }
591
592 const size_t test_prob = 128;
593 const bool is_randomly_generated = is_builtin;
594
595 //check if field modulus is prime
596 if(!is_prime(p, rng, test_prob, is_randomly_generated)) {
597 return false;
598 }
599
600 //check if order is prime
601 if(!is_prime(order, rng, test_prob, is_randomly_generated)) {
602 return false;
603 }
604
605 //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero
606 const Modular_Reducer mod_p(p);
607
608 const BigInt discriminant = mod_p.reduce(mod_p.multiply(4, mod_p.cube(a)) + mod_p.multiply(27, mod_p.square(b)));
609
610 if(discriminant == 0) {
611 return false;
612 }
613
614 //check for valid cofactor
615 if(get_cofactor() < 1) {
616 return false;
617 }
618
619 //check if the base point is on the curve
620 if(!base_point.on_the_curve()) {
621 return false;
622 }
623 if((base_point * get_cofactor()).is_zero()) {
624 return false;
625 }
626 //check if order of the base point is correct
627 if(!(base_point * order).is_zero()) {
628 return false;
629 }
630
631 // check the Hasse bound (roughly)
632 if((p - get_cofactor() * order).abs().bits() > (p.bits() / 2) + 1) {
633 return false;
634 }
635
636 return true;
637}
638
639EC_Group::Mul2Table::Mul2Table(const EC_AffinePoint& h) : m_tbl(h._group()->make_mul2_table(h._inner())) {}
640
642
643std::optional<EC_AffinePoint> EC_Group::Mul2Table::mul2_vartime(const EC_Scalar& x, const EC_Scalar& y) const {
644 auto pt = m_tbl->mul2_vartime(x._inner(), y._inner());
645 if(pt) {
646 return EC_AffinePoint::_from_inner(std::move(pt));
647 } else {
648 return {};
649 }
650}
651
653 const EC_Scalar& x,
654 const EC_Scalar& y) const {
655 return m_tbl->mul2_vartime_x_mod_order_eq(v._inner(), x._inner(), y._inner());
656}
657
659 const EC_Scalar& c,
660 const EC_Scalar& x,
661 const EC_Scalar& y) const {
662 return this->mul2_vartime_x_mod_order_eq(v, c * x, c * y);
663}
664
665} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
size_t bits() const
Definition bigint.cpp:295
static BigInt power_of_2(size_t n)
Definition bigint.h:830
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
static EC_AffinePoint _from_inner(std::unique_ptr< EC_AffinePoint_Data > inner)
std::optional< EC_AffinePoint > mul2_vartime(const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:643
Mul2Table(const EC_AffinePoint &h)
Definition ec_group.cpp:639
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:652
static EC_Group from_name(std::string_view name)
Definition ec_group.cpp:307
static EC_Group from_PEM(std::string_view pem)
Definition ec_group.cpp:350
const BigInt & get_b() const
Definition ec_group.cpp:442
const BigInt & get_a() const
Definition ec_group.cpp:438
const BigInt & get_g_y() const
Definition ec_group.cpp:462
const BigInt & get_cofactor() const
Definition ec_group.cpp:466
BigInt mod_order(const BigInt &x) const
Definition ec_group.cpp:474
bool operator==(const EC_Group &other) const
Definition ec_group.cpp:534
EC_Group_Source source() const
Definition ec_group.cpp:482
const EC_Point & generator() const
Definition ec_group.cpp:450
bool verify_public_element(const EC_Point &y) const
Definition ec_group.cpp:544
const BigInt & get_p() const
Definition ec_group.cpp:434
bool verify_group(RandomNumberGenerator &rng, bool strong=false) const
Definition ec_group.cpp:569
const BigInt & get_order() const
Definition ec_group.cpp:454
size_t get_p_bits() const
Definition ec_group.cpp:418
const EC_Point & get_base_point() const
Definition ec_group.cpp:446
EC_Point point(const BigInt &x, const BigInt &y) const
Definition ec_group.h:594
static EC_Group from_OID(const OID &oid)
Definition ec_group.cpp:296
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:486
std::string PEM_encode() const
Definition ec_group.cpp:529
const BigInt & get_g_x() const
Definition ec_group.cpp:458
const OID & get_curve_oid() const
Definition ec_group.cpp:478
bool has_cofactor() const
Definition ec_group.cpp:470
static size_t clear_registered_curve_data()
Definition ec_group.cpp:182
EC_Group & operator=(const EC_Group &)
size_t get_p_bytes() const
Definition ec_group.cpp:422
static OID EC_group_identity_from_order(const BigInt &order)
Definition ec_named.cpp:356
size_t get_order_bits() const
Definition ec_group.cpp:426
size_t get_order_bytes() const
Definition ec_group.cpp:430
bool is_zero() const
Definition ec_point.h:167
bool on_the_curve() const
Definition ec_point.cpp:531
const EC_Scalar_Data & _inner() const
Definition ec_scalar.h:211
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
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
EC_Group_Source
Definition ec_group.h:36
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:355
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
const SIMD_8x32 & b
lock_guard< T > lock_guard_type
Definition mutex.h:55
EC_Group_Encoding
Definition ec_group.h:26