11#include <botan/ec_group.h>
13#include <botan/ber_dec.h>
14#include <botan/der_enc.h>
15#include <botan/mutex.h>
16#include <botan/numthry.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>
27class EC_Group_Data_Map final {
29 EC_Group_Data_Map() =
default;
33 const size_t count = m_registered_curves.size();
34 m_registered_curves.clear();
38 bool unregister(
const OID& oid) {
41 throw Invalid_Argument(
"OID must not be empty");
45 for(
size_t i = 0; i < m_registered_curves.size(); i++) {
46 if(m_registered_curves[i]->oid() == oid) {
47 m_registered_curves.erase(m_registered_curves.begin() + i);
54 std::shared_ptr<EC_Group_Data> lookup(
const OID& oid) {
57 for(
auto i : m_registered_curves) {
69 if(data->oid() != oid) {
70 for(
const auto& i : m_registered_curves) {
71 if(i->oid() == data->oid()) {
77 m_registered_curves.push_back(data);
82 return std::shared_ptr<EC_Group_Data>();
85 std::shared_ptr<EC_Group_Data> lookup_or_create(
const BigInt& p,
91 const BigInt& cofactor,
98 for(
auto i : m_registered_curves) {
108 if(!i->params_match(p, a, b, g_x, g_y, order, cofactor)) {
109 throw Invalid_Argument(
"Attempting to register a curve using OID " + oid.to_string() +
110 " but a distinct curve is already registered using that OID");
123 if(i->oid().empty() && i->params_match(p, a, b, g_x, g_y, order, cofactor)) {
132 auto new_group = [&] {
139 "Attempting to register an EC group under OID of hardcoded group");
150 m_registered_curves.push_back(new_group);
154 std::shared_ptr<EC_Group_Data> lookup_from_params(
const BigInt& p,
157 std::span<const uint8_t> base_pt,
159 const BigInt& cofactor) {
162 for(
auto i : m_registered_curves) {
163 if(i->params_match(p, a, b, base_pt, order, cofactor)) {
170 if(oid_from_order.has_value()) {
174 if(new_group && new_group->params_match(p, a, b, base_pt, order, cofactor)) {
175 m_registered_curves.push_back(new_group);
184 std::shared_ptr<EC_Group_Data> lookup_or_create_without_oid(
const BigInt& p,
190 const BigInt& cofactor,
194 for(
auto i : m_registered_curves) {
195 if(i->params_match(p, a, b, g_x, g_y, order, cofactor)) {
202 if(oid_from_order.has_value()) {
206 if(new_group && new_group->params_match(p, a, b, g_x, g_y, order, cofactor)) {
207 m_registered_curves.push_back(new_group);
220 m_registered_curves.push_back(new_group);
227 std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves;
231EC_Group_Data_Map& EC_Group::ec_group_data() {
237 static const Allocator_Initializer g_init_allocator;
238 static EC_Group_Data_Map g_ec_data;
244 return ec_group_data().clear();
248std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(
const char* p_str,
253 const char* order_str,
260 const BigInt g_x(g_x_str);
261 const BigInt g_y(g_y_str);
262 const BigInt order(order_str);
269std::pair<std::shared_ptr<EC_Group_Data>,
bool> EC_Group::DER_decode_EC_group(std::span<const uint8_t> der,
273 auto next_obj_type = dec.peek_next_object().type_tag();
277 dec.decode(oid).verify_end();
279 auto data = ec_group_data().lookup(oid);
281 throw Decoding_Error(
fmt(
"Unknown namedCurve OID '{}'", oid.to_string()));
284 return std::make_pair(data,
false);
291 std::vector<uint8_t> base_pt;
292 std::vector<uint8_t> seed;
295 .decode_and_check<
size_t>(1,
"Unknown ECC param version code")
297 .decode_and_check(OID({1, 2, 840, 10045, 1, 1}),
"Only prime ECC fields supported")
301 .decode_octet_string_bigint(a)
302 .decode_octet_string_bigint(b)
312 if(cofactor <= 0 || cofactor >= 16) {
313 throw Decoding_Error(
"Invalid ECC cofactor parameter");
316 if(p.bits() < 112 || p.bits() > 521 || p.signum() < 0) {
317 throw Decoding_Error(
"ECC p parameter is invalid size");
321 if(a.signum() < 0 || a >= p) {
322 throw Decoding_Error(
"Invalid ECC a parameter");
326 if(b.signum() <= 0 || b >= p) {
327 throw Decoding_Error(
"Invalid ECC b parameter");
330 if(order.signum() <= 0 || order >= 2 * p) {
331 throw Decoding_Error(
"Invalid ECC group order");
334 if(
auto data = ec_group_data().lookup_from_params(p, a, b, base_pt, order, cofactor)) {
335 return std::make_pair(data,
true);
346 throw Decoding_Error(
"ECC p parameter is not a prime");
351 throw Decoding_Error(
"Invalid ECC order parameter");
354 const size_t p_bytes = p.bytes();
355 if(base_pt.size() != 1 + p_bytes && base_pt.size() != 1 + 2 * p_bytes) {
356 throw Decoding_Error(
"Invalid ECC base point encoding");
359 auto [g_x, g_y] = [&]() {
360 const uint8_t hdr = base_pt[0];
362 if(hdr == 0x04 && base_pt.size() == 1 + 2 * p_bytes) {
364 const BigInt y =
BigInt::from_bytes(std::span{base_pt}.subspan(1 + p_bytes, p_bytes));
367 return std::make_pair(x, y);
369 }
else if((hdr == 0x02 || hdr == 0x03) && base_pt.size() == 1 + p_bytes) {
374 if(x < p && y >= 0) {
375 const bool y_mod_2 = (hdr & 0x01) == 1;
376 if(y.get_bit(0) != y_mod_2) {
380 return std::make_pair(x, y);
384 throw Decoding_Error(
"Invalid ECC base point encoding");
388 auto y2 = mod_p.square(g_y);
389 auto x3_ax_b = mod_p.reduce(mod_p.cube(g_x) + mod_p.multiply(a, g_x) + b);
391 throw Decoding_Error(
"Invalid ECC base point");
401 return std::make_pair(data,
true);
403 throw Decoding_Error(
"Decoding ImplicitCA ECC parameters is not supported");
405 throw Decoding_Error(
435 if(ec_group_data().lookup(oid.value()) !=
nullptr) {
450#if defined(BOTAN_HAS_LEGACY_EC_POINT) || defined(BOTAN_HAS_PCURVES_GENERIC)
459#if defined(BOTAN_HAS_LEGACY_EC_POINT)
468 auto data = ec_group_data().lookup(oid);
479 std::shared_ptr<EC_Group_Data> data;
482 data = ec_group_data().lookup(oid.value());
500 m_data = ec_group_data().lookup(oid);
504 if(m_data ==
nullptr) {
505 if(str.size() > 30 && str.starts_with(
"-----BEGIN EC PARAMETERS-----")) {
510 this->m_data = data.first;
511 this->m_explicit_encoding = data.second;
515 if(m_data ==
nullptr) {
536 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p,
"EC_Group base_x is invalid");
537 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p,
"EC_Group base_y is invalid");
546 const auto discriminant = mod_p.reduce(mod_p.multiply(
BigInt::from_s32(4), mod_p.cube(a)) +
548 BOTAN_ARG_CHECK(discriminant != 0,
"EC_Group discriminant is invalid");
551 auto y2 = mod_p.square(base_y);
552 auto x3_ax_b = mod_p.reduce(mod_p.cube(base_x) + mod_p.multiply(a, base_x) + b);
553 BOTAN_ARG_CHECK(y2 == x3_ax_b,
"EC_Group generator is not on the curve");
556 m_data = ec_group_data().lookup_or_create(
559 m_data = ec_group_data().lookup_or_create_without_oid(
574#if defined(BOTAN_DISABLE_DEPRECATED_FEATURES)
575 constexpr size_t p_bits_lower_bound = 192;
577 constexpr size_t p_bits_lower_bound = 128;
583 if(p.
bits() == 521) {
585 BOTAN_ARG_CHECK(p == p521,
"EC_Group with p of 521 bits must be 2**521-1");
586 }
else if(p.
bits() == 239) {
587 const auto x962_p239 = []() {
589 for(
size_t i = 0; i != 239; ++i) {
590 if(i < 47 || ((i >= 94) && (i != 143))) {
597 BOTAN_ARG_CHECK(p == x962_p239,
"EC_Group with p of 239 bits must be the X9.62 prime");
602 BOTAN_ARG_CHECK(p % 4 == 3,
"EC_Group p must be congruent to 3 modulo 4");
606 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p,
"EC_Group base_x is invalid");
607 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p,
"EC_Group base_y is invalid");
621 const auto discriminant = mod_p.reduce(mod_p.multiply(
BigInt::from_s32(4), mod_p.cube(a)) +
623 BOTAN_ARG_CHECK(discriminant != 0,
"EC_Group discriminant is invalid");
626 auto y2 = mod_p.square(base_y);
627 auto x3_ax_b = mod_p.reduce(mod_p.cube(base_x) + mod_p.multiply(a, base_x) + b);
628 BOTAN_ARG_CHECK(y2 == x3_ax_b,
"EC_Group generator is not on the curve");
639 m_explicit_encoding = data.second;
644 return ec_group_data().unregister(oid);
648 if(m_data ==
nullptr) {
655 return data().p_bits();
659 return data().p_bytes();
663 return data().order_bits();
667 return data().order_bytes();
682#if defined(BOTAN_HAS_LEGACY_EC_POINT)
683const EC_Point& EC_Group::get_base_point()
const {
684 return data().base_point();
687const EC_Point& EC_Group::generator()
const {
688 return data().base_point();
691bool EC_Group::verify_public_element(
const EC_Point& point)
const {
693 if(point.is_zero()) {
698 if(point.on_the_curve() ==
false) {
703 if((point *
get_order()).is_zero() ==
false) {
719 return data().order();
731 return data().cofactor();
735 return data().has_cofactor();
743 return data().source();
747 return data().engine();
751 return data().hash_to_curve_supported(hash_fn);
755 const auto& der_named_curve = data().der_named_curve();
757 if(der_named_curve.empty()) {
758 throw Encoding_Error(
"Cannot encode EC_Group as OID because OID not set");
761 return der_named_curve;
766 std::vector<uint8_t> output;
768 const size_t ecpVers1 = 1;
769 const OID curve_type(
"1.2.840.10045.1.1");
800 const std::vector<uint8_t> der =
DER_encode(form);
805 if(m_data == other.m_data) {
817 if(is_builtin && !strong) {
830 if(p <= 3 || order <= 0) {
833 if(a < 0 || a >= p) {
836 if(b <= 0 || b >= p) {
840 const size_t test_prob = 128;
841 const bool is_randomly_generated = is_builtin;
844 if(!
is_prime(p, rng, test_prob, is_randomly_generated)) {
849 if(!
is_prime(order, rng, test_prob, is_randomly_generated)) {
859 if(discriminant == 0) {
872 const BigInt x3_ax_b = mod_p.reduce(mod_p.cube(g_x) + mod_p.multiply(a, g_x) + b);
884 if(n_minus_one_g != g_pt->negate()) {
888#if defined(BOTAN_HAS_LEGACY_EC_POINT)
892 const EC_Point& base_point = get_base_point();
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
static Barrett_Reduction for_public_modulus(const BigInt &m)
static BigInt from_bytes(std::span< const uint8_t > bytes)
static BigInt power_of_2(size_t n)
static BigInt from_s32(int32_t n)
BigInt & square(secure_vector< word > &ws)
DER_Encoder & start_sequence()
DER_Encoder & encode(bool b)
static std::optional< EC_AffinePoint > from_bigint_xy(const EC_Group &group, const BigInt &x, const BigInt &y)
static EC_AffinePoint g_mul(const EC_Scalar &scalar, RandomNumberGenerator &rng)
Multiply by the group generator returning a complete point.
T serialize_uncompressed() const
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.
Mul2Table & operator=(const Mul2Table &other)=delete
std::optional< EC_AffinePoint > mul2_vartime(const EC_Scalar &x, const EC_Scalar &y) const
BOTAN_FUTURE_EXPLICIT Mul2Table(const EC_AffinePoint &h)
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
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)
static EC_Group from_PEM(std::string_view pem)
const BigInt & get_b() const
const BigInt & get_a() const
const BigInt & get_g_y() const
const BigInt & get_cofactor() const
BigInt mod_order(const BigInt &x) const
bool operator==(const EC_Group &other) const
static bool supports_application_specific_group_with_cofactor()
EC_Group_Engine engine() const
EC_Group_Source source() const
const BigInt & get_p() const
bool verify_group(RandomNumberGenerator &rng, bool strong=false) const
const BigInt & get_order() const
size_t get_p_bits() const
static EC_Group from_OID(const OID &oid)
static std::shared_ptr< EC_Group_Data > EC_group_info(const OID &oid)
std::vector< uint8_t > DER_encode() const
const BigInt & get_g_x() const
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())
const OID & get_curve_oid() const
static bool supports_application_specific_group()
static const std::set< std::string > & known_named_groups()
bool has_cofactor() const
static size_t clear_registered_curve_data()
static bool unregister(const OID &oid)
static bool supports_named_group(std::string_view name)
EC_Group & operator=(const EC_Group &)
size_t get_p_bytes() const
static OID EC_group_identity_from_order(const BigInt &order)
std::string PEM_encode(EC_Group_Encoding form=EC_Group_Encoding::Explicit) const
bool hash_to_curve_supported(std::string_view hash_fn) const
size_t get_order_bits() const
size_t get_order_bytes() const
static EC_Scalar one(const EC_Group &group)
const EC_Scalar_Data & _inner() const
static std::optional< OID > from_name(std::string_view name)
std::string to_string() const
static OID from_string(std::string_view str)
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
secure_vector< uint8_t > decode_check_label(DataSource &source, std::string_view label_want)
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
std::string asn1_tag_to_string(ASN1_Type type)
std::string fmt(std::string_view format, const T &... args)
BigInt abs(const BigInt &n)
secure_vector< T > lock(const std::vector< T > &in)
bool is_bailie_psw_probable_prime(const BigInt &n, const Barrett_Reduction &mod_n)
bool is_prime(const BigInt &n, RandomNumberGenerator &rng, size_t prob, bool is_random)
lock_guard< T > lock_guard_type
BigInt sqrt_modulo_prime(const BigInt &a, const BigInt &p)