7#include <botan/internal/ec_inner_data.h>
9#include <botan/der_enc.h>
10#include <botan/internal/barrett.h>
11#include <botan/internal/ec_inner_pc.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/pcurves.h>
16#if defined(BOTAN_HAS_LEGACY_EC_POINT)
17 #include <botan/internal/ec_inner_bn.h>
18 #include <botan/internal/point_mul.h>
21#if defined(BOTAN_HAS_XMD)
22 #include <botan/hash.h>
23 #include <botan/internal/xmd.h>
50 m_monty(m_p, m_mod_field),
53 m_p_words(
p.sig_words()),
55 m_order_bits(
order.bits()),
56 m_order_bytes((m_order_bits + 7) / 8),
57 m_a_is_minus_3(
a ==
p - 3),
58 m_a_is_zero(
a.is_zero()),
59 m_has_cofactor(m_cofactor != 1),
60 m_order_is_less_than_p(m_order <
p),
65 const BigInt x3_ax_b = mod_p.reduce(mod_p.cube(
g_x) + mod_p.multiply(
a,
g_x) +
b);
75 if(
const auto name = m_oid.registered_name()) {
85 if(!m_pcurve && !m_has_cofactor) {
94#if defined(BOTAN_HAS_LEGACY_EC_POINT)
96 m_a_r = m_monty.mul(
a, m_monty.R2(), ws);
97 m_b_r = m_monty.mul(
b, m_monty.R2(), ws);
104 throw Not_Implemented(
"EC_Group this group is not supported in this build configuration");
107 fmt(
"EC_Group the group {} is not supported in this build configuration",
oid.to_string()));
124#if defined(BOTAN_HAS_LEGACY_EC_POINT)
125 group->m_curve =
CurveGFp(group.get());
127 if(!group->m_pcurve) {
128 group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order);
151 if(order != this->
order()) {
157 if(g_x != this->
g_x()) {
160 if(g_y != this->
g_y()) {
170 std::span<const uint8_t> base_pt,
182 if(order != this->
order()) {
189 const size_t field_len = this->
p_bytes();
191 if(base_pt.size() == 1 + field_len && (base_pt[0] == 0x02 || base_pt[0] == 0x03)) {
194 const auto g_x = m_g_x.serialize(field_len);
195 const auto g_y = m_g_y.is_odd();
197 const auto sec1_x = base_pt.subspan(1, field_len);
198 const bool sec1_y = (base_pt[0] == 0x03);
200 if(!std::ranges::equal(sec1_x,
g_x)) {
209 }
else if(base_pt.size() == 1 + 2 * field_len && base_pt[0] == 0x04) {
210 const auto g_x = m_g_x.serialize(field_len);
211 const auto g_y = m_g_y.serialize(field_len);
213 const auto sec1_x = base_pt.subspan(1, field_len);
214 const auto sec1_y = base_pt.subspan(1 + field_len, field_len);
216 if(!std::ranges::equal(sec1_x,
g_x)) {
220 if(!std::ranges::equal(sec1_y,
g_y)) {
226 throw Decoding_Error(
"Invalid base point encoding in explicit group");
244 const size_t bit_length = 8 * bytes.size();
250 const size_t shift = bit_length -
order_bits();
252 const size_t new_length = bytes.size() - (shift / 8);
253 const size_t bit_shift = shift % 8;
259 std::vector<uint8_t> sbytes(new_length);
262 for(
size_t i = 0; i != new_length; ++i) {
263 const uint8_t w = bytes[i];
264 sbytes[i] = (w >> bit_shift) |
carry;
265 carry = w << (8 - bit_shift);
279 if(
auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
280 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
285#if defined(BOTAN_HAS_LEGACY_EC_POINT)
286 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(
BigInt(bytes)));
288 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
295 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
297#if defined(BOTAN_HAS_LEGACY_EC_POINT)
298 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
301 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
308 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
310#if defined(BOTAN_HAS_LEGACY_EC_POINT)
311 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
BigInt::one());
313 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
319 if(bn <= 0 || bn >= m_order) {
326#if defined(BOTAN_HAS_LEGACY_EC_POINT)
327 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
329 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
338 auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
339 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(),
gk_x_mod_order);
341#if defined(BOTAN_HAS_LEGACY_EC_POINT)
344 std::vector<BigInt> ws;
345 const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
348 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
BigInt::zero());
350 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
353 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
359 if(bytes.size() != m_order_bytes) {
364 if(
auto s = m_pcurve->deserialize_scalar(bytes)) {
365 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
370#if defined(BOTAN_HAS_LEGACY_EC_POINT)
373 if(r.
is_zero() || r >= m_order) {
377 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
379 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
385 std::span<const uint8_t> bytes)
const {
386 if(bytes.size() != 1 + 2 *
p_bytes() || bytes[0] != 0x04) {
391 if(
auto pt = m_pcurve->deserialize_point_uncompressed(bytes)) {
392 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
397#if defined(BOTAN_HAS_LEGACY_EC_POINT)
400 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
405 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
411 if(bytes.size() != 1 +
p_bytes() || (bytes[0] != 0x02 && bytes[0] != 0x03)) {
416 if(
auto pt = m_pcurve->deserialize_point_compressed(bytes)) {
417 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
422#if defined(BOTAN_HAS_LEGACY_EC_POINT)
425 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
430 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
437 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_identity());
439#if defined(BOTAN_HAS_LEGACY_EC_POINT)
440 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(),
EC_Point(m_curve));
442 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
449 std::span<const uint8_t> input,
450 std::span<const uint8_t> domain_sep) {
455 if(hash_fn.starts_with(
"SHAKE")) {
456 throw Not_Implemented(
"Hash to curve currently does not support expand_message_xof");
459#if defined(BOTAN_HAS_XMD)
471 const size_t k = std::min<size_t>((order_bits + 1) / 2, 256);
473 if(hash->security_level() < k) {
474 throw Invalid_Argument(
fmt(
"Hash {} is too weak for use with a {} bit group", hash->name(), order_bits));
477 return [hash, input, domain_sep](std::span<uint8_t> uniform_bytes) {
482 throw Not_Implemented(
"Hash to curve is not implemented due to XMD being disabled");
487#if defined(BOTAN_HAS_XMD)
488 if(!m_pcurve || !m_pcurve->supports_hash_to_curve()) {
493 if(hash_fn.starts_with(
"SHAKE")) {
498 if(hash ==
nullptr) {
503 const size_t k = std::min<size_t>((
order_bits() + 1) / 2, 256);
504 if(hash->security_level() < k) {
509 return hash->hash_block_size() > 0 && hash->output_length() <= hash->hash_block_size();
517 std::span<const uint8_t> input,
518 std::span<const uint8_t> domain_sep)
const {
519 if(m_pcurve && m_pcurve->supports_hash_to_curve()) {
521 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
523 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
528 std::span<const uint8_t> input,
529 std::span<const uint8_t> domain_sep)
const {
530 if(m_pcurve && m_pcurve->supports_hash_to_curve()) {
532 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
534 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
542 auto pt = m_pcurve->point_to_affine(m_pcurve->mul_by_g(k.value(), rng));
543 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
545#if defined(BOTAN_HAS_LEGACY_EC_POINT)
546 const auto& group = scalar.
group();
550 std::vector<BigInt> ws;
551 auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
552 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
554 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
572 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(*pt));
577#if defined(BOTAN_HAS_LEGACY_EC_POINT)
578 std::vector<BigInt> ws;
579 const auto& group =
p.group();
585 const auto order = group->order() * group->cofactor();
590 auto px_qy = px + qy;
592 if(!px_qy.is_zero()) {
593 px_qy.force_affine();
594 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
599 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
610 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
612#if defined(BOTAN_HAS_LEGACY_EC_POINT)
613 auto pt =
p.to_legacy_point() + q.to_legacy_point();
614 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
616 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
624 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
626#if defined(BOTAN_HAS_LEGACY_EC_POINT)
627 auto pt =
p.to_legacy_point();
629 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
631 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
638 return std::make_unique<EC_Mul2Table_Data_PC>(h);
640#if defined(BOTAN_HAS_LEGACY_EC_POINT)
642 return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
644 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
static Barrett_Reduction for_public_modulus(const BigInt &m)
static BigInt random_integer(RandomNumberGenerator &rng, const BigInt &min, const BigInt &max)
BigInt & square(secure_vector< word > &ws)
T serialize(size_t len) const
DER_Encoder & encode(bool b)
static const EC_AffinePoint_Data_PC & checked_ref(const EC_AffinePoint_Data &data)
std::unique_ptr< EC_Scalar_Data > gk_x_mod_order(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const
const BigInt & g_x() const
std::unique_ptr< EC_AffinePoint_Data > affine_neg(const EC_AffinePoint_Data &p) const
std::unique_ptr< EC_Scalar_Data > scalar_from_bytes_mod_order(std::span< const uint8_t > bytes) const
std::unique_ptr< EC_Scalar_Data > scalar_random(RandomNumberGenerator &rng) const
std::unique_ptr< EC_Scalar_Data > scalar_deserialize(std::span< const uint8_t > bytes) const
bool params_match(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &g_x, const BigInt &g_y, const BigInt &order, const BigInt &cofactor) 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)
std::unique_ptr< EC_AffinePoint_Data > affine_add(const EC_AffinePoint_Data &p, const EC_AffinePoint_Data &q) const
std::unique_ptr< EC_Scalar_Data > scalar_from_bytes_with_trunc(std::span< const uint8_t > bytes) const
std::unique_ptr< EC_Mul2Table_Data > make_mul2_table(const EC_AffinePoint_Data &pt) const
std::unique_ptr< EC_AffinePoint_Data > mul_px_qy(const EC_AffinePoint_Data &p, const EC_Scalar_Data &x, const EC_AffinePoint_Data &q, const EC_Scalar_Data &y, RandomNumberGenerator &rng) const
std::unique_ptr< EC_AffinePoint_Data > point_deserialize_compressed(std::span< const uint8_t > bytes) const
std::unique_ptr< EC_Scalar_Data > scalar_one() const
std::unique_ptr< EC_AffinePoint_Data > point_g_mul(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const
size_t order_bits() const
const BigInt & cofactor() const
std::unique_ptr< EC_AffinePoint_Data > point_identity() const
Return the identity element (aka the point at infinity).
std::unique_ptr< EC_AffinePoint_Data > point_deserialize_uncompressed(std::span< const uint8_t > bytes) const
EC_Group_Data(const EC_Group_Data &other)=delete
EC_Group_Source source() const
void set_oid(const OID &oid)
bool hash_to_curve_supported(std::string_view hash_fn) const
const BigInt & g_y() const
size_t order_bytes() const
std::unique_ptr< EC_Scalar_Data > scalar_from_bigint(const BigInt &bn) const
std::unique_ptr< EC_AffinePoint_Data > point_hash_to_curve_ro(std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep) const
std::unique_ptr< EC_AffinePoint_Data > point_hash_to_curve_nu(std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep) const
const BigInt & order() const
EC_Point mul(const BigInt &k, RandomNumberGenerator &rng, const BigInt &group_order, std::vector< BigInt > &ws) const
static const EC_Scalar_Data_BN & checked_ref(const EC_Scalar_Data &data)
static const EC_Scalar_Data_PC & checked_ref(const EC_Scalar_Data &data)
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< HashFunction > create(std::string_view algo_spec, std::string_view provider="")
static std::shared_ptr< const PrimeOrderCurve > from_params(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &base_x, const BigInt &base_y, const BigInt &order)
static std::shared_ptr< const PrimeOrderCurve > for_named_curve(std::string_view name)
#define BOTAN_HAS_LEGACY_EC_POINT
std::string fmt(std::string_view format, const T &... args)
std::function< void(std::span< uint8_t >)> h2c_expand_message(std::string_view hash_fn, size_t order_bits, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
void expand_message_xmd(HashFunction &hash, std::span< uint8_t > output, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
@ Optimized
Using per curve implementation; fastest available.
@ Generic
A generic implementation that handles many curves in one implementation.
void carry(int64_t &h0, int64_t &h1)
std::vector< T, secure_allocator< T > > secure_vector
EC_Point OS2ECP(std::span< const uint8_t > data, const CurveGFp &curve)