11#include <botan/ec_group.h>
13#include <botan/ber_dec.h>
14#include <botan/der_enc.h>
15#include <botan/mutex.h>
17#include <botan/reducer.h>
19#include <botan/internal/fmt.h>
20#include <botan/internal/point_mul.h>
21#include <botan/internal/primality.h>
24#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
25 #include <botan/internal/ec_h2c.h>
30class EC_Group_Data
final {
32 EC_Group_Data(
const BigInt& p,
38 const BigInt& cofactor,
42 m_base_point(m_curve, g_x, g_y),
48 m_base_mult(m_base_point, m_mod_order),
51 m_order_bits(order.bits()),
52 m_a_is_minus_3(a == p - 3),
53 m_a_is_zero(a.is_zero()),
56 bool params_match(
const BigInt& p,
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);
67 bool params_match(
const EC_Group_Data& other)
const {
69 other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
72 void set_oid(
const OID& oid) {
77 const OID& oid()
const {
return m_oid; }
79 const BigInt& p()
const {
return m_curve.
get_p(); }
81 const BigInt& a()
const {
return m_curve.
get_a(); }
83 const BigInt& b()
const {
return m_curve.
get_b(); }
85 const BigInt& order()
const {
return m_order; }
87 const BigInt& cofactor()
const {
return m_cofactor; }
89 const BigInt& g_x()
const {
return m_g_x; }
91 const BigInt& g_y()
const {
return m_g_y; }
93 size_t p_bits()
const {
return m_p_bits; }
95 size_t p_bytes()
const {
return (m_p_bits + 7) / 8; }
97 size_t order_bits()
const {
return m_order_bits; }
99 size_t order_bytes()
const {
return (m_order_bits + 7) / 8; }
101 const CurveGFp& curve()
const {
return m_curve; }
103 const EC_Point& base_point()
const {
return m_base_point; }
105 bool a_is_minus_3()
const {
return m_a_is_minus_3; }
107 bool a_is_zero()
const {
return m_a_is_zero; }
109 BigInt mod_order(
const BigInt& x)
const {
return m_mod_order.
reduce(x); }
111 BigInt square_mod_order(
const BigInt& x)
const {
return m_mod_order.
square(x); }
113 BigInt multiply_mod_order(
const BigInt& x,
const BigInt& y)
const {
return m_mod_order.
multiply(x, y); }
115 BigInt multiply_mod_order(
const BigInt& x,
const BigInt& y,
const BigInt& z)
const {
119 BigInt inverse_mod_order(
const BigInt& x)
const {
return inverse_mod(x, m_order); }
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);
129 EC_Point m_base_point;
135 Modular_Reducer m_mod_order;
136 EC_Point_Base_Point_Precompute m_base_mult;
145class EC_Group_Data_Map
final {
147 EC_Group_Data_Map() =
default;
151 size_t count = m_registered_curves.size();
152 m_registered_curves.clear();
156 std::shared_ptr<EC_Group_Data> lookup(
const OID& oid) {
159 for(
auto i : m_registered_curves) {
160 if(i->oid() == oid) {
169 for(
auto curve : m_registered_curves) {
170 if(curve->oid().empty() ==
true && curve->params_match(*data)) {
176 m_registered_curves.push_back(data);
181 return std::shared_ptr<EC_Group_Data>();
184 std::shared_ptr<EC_Group_Data> lookup_or_create(
const BigInt& p,
190 const BigInt& cofactor,
195 for(
auto i : m_registered_curves) {
201 if(!oid.empty() && !i->oid().empty() && i->oid() != oid) {
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);
212 if(same_params && same_oid) {
219 if(same_params && oid.empty()) {
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");
235 if(same_params && i->oid().empty() && !oid.empty()) {
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);
251 if(oid.has_value()) {
253 if(data !=
nullptr && !new_group->params_match(*data)) {
254 throw Invalid_Argument(
"Attempting to register an EC group under OID of hardcoded group");
259 if(oid_from_store.has_value()) {
273 if(new_group->params_match(*data)) {
274 new_group->set_oid(oid_from_store);
279 m_registered_curves.push_back(new_group);
285 std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves;
289EC_Group_Data_Map& EC_Group::ec_group_data() {
295 static Allocator_Initializer g_init_allocator;
296 static EC_Group_Data_Map g_ec_data;
302 return ec_group_data().clear();
306std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(
const char* p_str,
311 const char* order_str,
316 const BigInt g_x(g_x_str);
317 const BigInt g_y(g_y_str);
318 const BigInt order(order_str);
325std::pair<std::shared_ptr<EC_Group_Data>,
bool> EC_Group::BER_decode_EC_group(std::span<const uint8_t> bits,
327 BER_Decoder ber(bits);
328 BER_Object obj = ber.get_next_object();
332 BER_Decoder(bits).decode(dom_par_oid);
333 return std::make_pair(ec_group_data().lookup(dom_par_oid),
false);
337 BigInt p, a, b, order, cofactor;
338 std::vector<uint8_t> base_pt;
339 std::vector<uint8_t> seed;
343 .decode_and_check<
size_t>(1,
"Unknown ECC param version code")
345 .decode_and_check(OID(
"1.2.840.10045.1.1"),
"Only prime ECC fields supported")
349 .decode_octet_string_bigint(a)
350 .decode_octet_string_bigint(b)
359 if(p.bits() < 112 || p.bits() > 521) {
360 throw Decoding_Error(
"ECC p parameter is invalid size");
364 throw Decoding_Error(
"ECC p parameter is not a prime");
367 if(a.is_negative() || a >= p) {
368 throw Decoding_Error(
"Invalid ECC a parameter");
371 if(b <= 0 || b >= p) {
372 throw Decoding_Error(
"Invalid ECC b parameter");
376 throw Decoding_Error(
"Invalid ECC order parameter");
379 if(cofactor <= 0 || cofactor >= 16) {
380 throw Decoding_Error(
"Invalid ECC cofactor parameter");
383 std::pair<BigInt, BigInt> base_xy =
Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b);
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);
391 throw Decoding_Error(
"Cannot handle ImplicitCA ECC parameters");
393 throw Decoding_Error(
fmt(
"Unexpected tag {} while decoding ECC domain params",
asn1_tag_to_string(obj.type())));
410 auto data = ec_group_data().lookup(oid);
421 std::shared_ptr<EC_Group_Data> data;
424 data = ec_group_data().lookup(oid.value());
442 m_data = ec_group_data().lookup(oid);
446 if(m_data ==
nullptr) {
447 if(str.size() > 30 && str.substr(0, 29) ==
"-----BEGIN EC PARAMETERS-----") {
452 this->m_data = data.first;
453 this->m_explicit_encoding = data.second;
457 if(m_data ==
nullptr) {
491 if(p.
bits() == 521) {
497 BOTAN_ARG_CHECK(p % 4 == 3,
"EC_Group p must be congruent to 3 modulo 4");
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");
521 m_explicit_encoding = data.second;
524const EC_Group_Data& EC_Group::data()
const {
525 if(m_data ==
nullptr) {
532 return data().a_is_minus_3();
536 return data().a_is_zero();
540 return data().p_bits();
544 return data().p_bytes();
548 return data().order_bits();
552 return data().order_bytes();
568 return data().base_point();
572 return data().order();
584 return data().cofactor();
588 return data().mod_order(k);
592 return data().square_mod_order(x);
600 return data().multiply_mod_order(x, y);
604 return data().multiply_mod_order(x, y, z);
608 return data().inverse_mod_order(x);
616 return data().source();
634 return EC_Point(data().curve(), x, y);
644 std::vector<BigInt>& ws)
const {
645 return data().blinded_base_point_multiply(k, rng, ws);
650 std::vector<BigInt>& ws)
const {
651 const EC_Point pt = data().blinded_base_point_multiply(k, rng, ws);
666 std::vector<BigInt>& ws)
const {
680 const uint8_t input[],
682 std::string_view domain,
683 bool random_oracle)
const {
685 hash_fn, input, input_len,
reinterpret_cast<const uint8_t*
>(domain.data()), domain.size(), random_oracle);
689 const uint8_t input[],
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)
698 throw Not_Implemented(
"EC_Group::hash_to_curve not available for this curve type");
701 return hash_to_curve_sswu(*
this, hash_fn, {input, input_len}, {domain_sep, domain_sep_len}, random_oracle);
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");
710 std::vector<uint8_t> output;
715 const size_t ecpVers1 = 1;
716 const OID curve_type(
"1.2.840.10045.1.1");
737 throw Encoding_Error(
"Cannot encode EC_Group as OID because OID not set");
755 if(m_data == other.m_data) {
792 if(is_builtin && !strong) {
802 if(p <= 3 || order <= 0) {
805 if(a < 0 || a >= p) {
808 if(b <= 0 || b >= p) {
812 const size_t test_prob = 128;
813 const bool is_randomly_generated = is_builtin;
816 if(!
is_prime(p, rng, test_prob, is_randomly_generated)) {
821 if(!
is_prime(order, rng, test_prob, is_randomly_generated)) {
830 if(discriminant == 0) {
847 if(!(base_point * order).is_zero()) {
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
static BigInt random_integer(RandomNumberGenerator &rng, const BigInt &min, const BigInt &max)
static BigInt power_of_2(size_t n)
const BigInt & get_a() const
const BigInt & get_p() const
const BigInt & get_b() const
DER_Encoder & start_sequence()
DER_Encoder & encode_null()
DER_Encoder & encode(bool b)
bool a_is_minus_3() const
static EC_Group from_name(std::string_view name)
static EC_Group from_PEM(std::string_view pem)
BigInt blinded_base_point_multiply_x(const BigInt &k, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
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
BigInt cube_mod_order(const BigInt &x) const
BigInt multiply_mod_order(const BigInt &x, const BigInt &y) const
EC_Point zero_point() const
EC_Group_Source source() const
bool verify_public_element(const EC_Point &y) 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
const EC_Point & get_base_point() const
EC_Point point(const BigInt &x, const BigInt &y) const
static EC_Group from_OID(const OID &oid)
EC_Point blinded_base_point_multiply(const BigInt &k, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
static std::shared_ptr< EC_Group_Data > EC_group_info(const OID &oid)
std::string PEM_encode() const
const BigInt & get_g_x() const
const OID & get_curve_oid() const
BigInt square_mod_order(const BigInt &x) const
EC_Point blinded_var_point_multiply(const EC_Point &point, const BigInt &k, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
static size_t clear_registered_curve_data()
std::vector< uint8_t > DER_encode(EC_Group_Encoding form) const
BigInt inverse_mod_order(const BigInt &x) const
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
EC_Group & operator=(const EC_Group &)
size_t point_size(EC_Point_Format format) const
size_t get_p_bytes() const
EC_Point point_multiply(const BigInt &x, const EC_Point &pt, const BigInt &y) const
static OID EC_group_identity_from_order(const BigInt &order)
EC_Point OS2ECP(const uint8_t bits[], size_t len) const
BigInt random_scalar(RandomNumberGenerator &rng) const
size_t get_order_bits() const
size_t get_order_bytes() const
EC_Point mul(const BigInt &k, RandomNumberGenerator &rng, const BigInt &group_order, std::vector< BigInt > &ws) const
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
bool on_the_curve() const
BigInt cube(const BigInt &x) const
BigInt square(const BigInt &x) const
BigInt multiply(const BigInt &x, const BigInt &y) const
BigInt reduce(const BigInt &x) const
static std::optional< OID > from_name(std::string_view name)
std::string to_string() const
static OID from_string(std::string_view str)
int(* final)(unsigned char *, CTX *)
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)
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
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_prime(const BigInt &n, RandomNumberGenerator &rng, size_t prob, bool is_random)
bool is_bailie_psw_probable_prime(const BigInt &n, const Modular_Reducer &mod_n)
EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp &curve)
lock_guard< T > lock_guard_type
BigInt inverse_mod(const BigInt &n, const BigInt &mod)