7#include <botan/internal/ec_inner_data.h>
9#include <botan/der_enc.h>
10#include <botan/internal/ec_inner_pc.h>
11#include <botan/internal/fmt.h>
12#include <botan/internal/pcurves.h>
14#if defined(BOTAN_HAS_LEGACY_EC_POINT)
15 #include <botan/internal/ec_inner_bn.h>
16 #include <botan/internal/point_mul.h>
19#if defined(BOTAN_HAS_XMD)
20 #include <botan/internal/xmd.h>
47 m_monty(m_p, m_mod_field),
50 m_p_words(
p.sig_words()),
52 m_order_bits(
order.bits()),
53 m_order_bytes((m_order_bits + 7) / 8),
54 m_a_is_minus_3(
a ==
p - 3),
55 m_a_is_zero(
a.is_zero()),
56 m_has_cofactor(m_cofactor != 1),
57 m_order_is_less_than_p(m_order <
p),
61 DER_Encoder der(m_der_named_curve);
64 const std::string name = m_oid.human_name_or_empty();
67 m_pcurve = PCurve::PrimeOrderCurve::for_named_curve(name);
70 m_engine = EC_Group_Engine::Optimized;
75 if(!m_pcurve && !m_has_cofactor) {
84#if defined(BOTAN_HAS_LEGACY_EC_POINT)
86 m_a_r = m_monty.mul(a, m_monty.R2(), ws);
87 m_b_r = m_monty.mul(b, m_monty.R2(), ws);
89 m_engine = EC_Group_Engine::Legacy;
94 throw Not_Implemented(
"EC_Group this group is not supported in this build configuration");
96 throw Not_Implemented(
97 fmt(
"EC_Group the group {} is not supported in this build configuration", oid.to_string()));
114#if defined(BOTAN_HAS_LEGACY_EC_POINT)
115 group->m_curve =
CurveGFp(group.get());
117 if(!group->m_pcurve) {
118 group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order);
132 return (this->p() ==
p && this->a() ==
a && this->b() ==
b && this->order() ==
order &&
133 this->cofactor() ==
cofactor && this->g_x() ==
g_x && this->g_y() ==
g_y);
150 const size_t bit_length = 8 * bytes.size();
156 const size_t shift = bit_length -
order_bits();
158 const size_t new_length = bytes.size() - (shift / 8);
159 const size_t bit_shift = shift % 8;
165 std::vector<uint8_t> sbytes(new_length);
168 for(
size_t i = 0; i != new_length; ++i) {
169 const uint8_t w = bytes[i];
170 sbytes[i] = (w >> bit_shift) |
carry;
171 carry = w << (8 - bit_shift);
185 if(
auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
186 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
191#if defined(BOTAN_HAS_LEGACY_EC_POINT)
192 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(
BigInt(bytes)));
194 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
201 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
203#if defined(BOTAN_HAS_LEGACY_EC_POINT)
204 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
207 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
214 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
216#if defined(BOTAN_HAS_LEGACY_EC_POINT)
217 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
BigInt::one());
219 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
225 if(bn <= 0 || bn >= m_order) {
232#if defined(BOTAN_HAS_LEGACY_EC_POINT)
233 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
235 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
244 auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
245 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(),
gk_x_mod_order);
247#if defined(BOTAN_HAS_LEGACY_EC_POINT)
250 std::vector<BigInt> ws;
251 const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
254 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
BigInt::zero());
256 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
259 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
265 if(bytes.size() != m_order_bytes) {
270 if(
auto s = m_pcurve->deserialize_scalar(bytes)) {
271 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
276#if defined(BOTAN_HAS_LEGACY_EC_POINT)
279 if(r.
is_zero() || r >= m_order) {
283 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
285 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
293 if(bytes.size() >= 1 + 2 * 4 && (bytes[0] == 0x06 || bytes[0] == 0x07)) {
294 bool hdr_y_is_even = bytes[0] == 0x06;
295 bool y_is_even = (bytes.back() & 0x01) == 0;
297 if(hdr_y_is_even == y_is_even) {
298 std::vector<uint8_t> sec1(bytes.begin(), bytes.end());
306 if(
auto pt = m_pcurve->deserialize_point(bytes)) {
307 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
312#if defined(BOTAN_HAS_LEGACY_EC_POINT)
314 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
316 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
326std::function<void(std::span<uint8_t>)> h2c_expand_message(std::string_view hash_fn,
327 std::span<const uint8_t> input,
328 std::span<const uint8_t> domain_sep) {
333 if(hash_fn.starts_with(
"SHAKE")) {
334 throw Not_Implemented(
"Hash to curve currently does not support expand_message_xof");
337 return [=](std::span<uint8_t> uniform_bytes) {
338#if defined(BOTAN_HAS_XMD)
339 expand_message_xmd(hash_fn, uniform_bytes, input, domain_sep);
341 BOTAN_UNUSED(hash_fn, uniform_bytes, input, domain_sep);
342 throw Not_Implemented(
"Hash to curve is not implemented due to XMD being disabled");
350 std::span<const uint8_t> input,
351 std::span<const uint8_t> domain_sep)
const {
353 auto pt = m_pcurve->hash_to_curve_ro(h2c_expand_message(hash_fn, input, domain_sep));
354 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
356 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
361 std::span<const uint8_t> input,
362 std::span<const uint8_t> domain_sep)
const {
364 auto pt = m_pcurve->hash_to_curve_nu(h2c_expand_message(hash_fn, input, domain_sep));
365 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
367 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
375 auto pt = m_pcurve->point_to_affine(m_pcurve->mul_by_g(k.value(), rng));
376 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
378#if defined(BOTAN_HAS_LEGACY_EC_POINT)
379 const auto& group = scalar.
group();
383 std::vector<BigInt> ws;
384 auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
385 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
387 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
405 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(*pt));
410#if defined(BOTAN_HAS_LEGACY_EC_POINT)
411 std::vector<BigInt> ws;
412 const auto& group =
p.group();
418 const auto order = group->order() * group->cofactor();
423 auto px_qy = px + qy;
425 if(!px_qy.is_zero()) {
426 px_qy.force_affine();
427 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
432 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
443 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt));
445#if defined(BOTAN_HAS_LEGACY_EC_POINT)
446 auto pt =
p.to_legacy_point() + q.to_legacy_point();
447 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
449 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
457 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
459#if defined(BOTAN_HAS_LEGACY_EC_POINT)
460 auto pt =
p.to_legacy_point();
462 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
464 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
471 return std::make_unique<EC_Mul2Table_Data_PC>(h);
473#if defined(BOTAN_HAS_LEGACY_EC_POINT)
475 return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
477 throw Not_Implemented(
"Legacy EC interfaces disabled in this build configuration");
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
static BigInt random_integer(RandomNumberGenerator &rng, const BigInt &min, const BigInt &max)
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_AffinePoint_Data > point_deserialize(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_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
EC_Group_Data(const EC_Group_Data &other)=delete
EC_Group_Source source() const
void set_oid(const OID &oid)
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::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)
#define BOTAN_HAS_LEGACY_EC_POINT
@ 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)