From 3de01c7f9d0ec60aa59de7ce40ff39e8ebf7e8fd Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Fri, 15 Nov 2024 07:26:47 -0500 Subject: [PATCH] Cleanups relating to CurveGFp This removes CurveGFp_Repr and its subclasses. Now the Montgomery logic previously implemented there is delegated to the already existing Montgomery_Params. This also guts CurveGFp; at this point it could easily be removed but unfortunately this type is used in a couple of interfaces which, while already deprecated, are still part of the public API. So complete removal will have to wait for Botan4. --- src/lib/math/numbertheory/monty.cpp | 75 ++- src/lib/math/numbertheory/monty.h | 20 +- src/lib/pubkey/ec_group/curve_gfp.cpp | 165 ------- src/lib/pubkey/ec_group/curve_gfp.h | 192 +------- src/lib/pubkey/ec_group/ec_group.cpp | 10 +- src/lib/pubkey/ec_group/ec_group.h | 5 + src/lib/pubkey/ec_group/ec_inner_bn.cpp | 65 +-- src/lib/pubkey/ec_group/ec_inner_data.cpp | 36 +- src/lib/pubkey/ec_group/ec_inner_data.h | 65 ++- src/lib/pubkey/ec_group/ec_point.cpp | 542 ++++++++++++++-------- src/lib/pubkey/ec_group/ec_point.h | 64 +-- 11 files changed, 575 insertions(+), 664 deletions(-) delete mode 100644 src/lib/pubkey/ec_group/curve_gfp.cpp diff --git a/src/lib/math/numbertheory/monty.cpp b/src/lib/math/numbertheory/monty.cpp index f21dad2a763..09b57de928b 100644 --- a/src/lib/math/numbertheory/monty.cpp +++ b/src/lib/math/numbertheory/monty.cpp @@ -1,5 +1,5 @@ /* -* (C) 2018 Jack Lloyd +* (C) 2018,2024 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -48,9 +48,9 @@ Montgomery_Params::Montgomery_Params(const BigInt& p) { m_r3 = mod_p.multiply(m_r1, m_r2); } -BigInt Montgomery_Params::inv_mod_p(const BigInt& x) const { +BigInt Montgomery_Params::inv_mod_p(const BigInt& x, secure_vector& ws) const { // TODO use Montgomery inverse here? - return inverse_mod(x, p()); + return this->mul(inverse_mod(x, p()), this->R3(), ws); } BigInt Montgomery_Params::redc(const BigInt& x, secure_vector& ws) const { @@ -68,8 +68,26 @@ BigInt Montgomery_Params::redc(const BigInt& x, secure_vector& ws) const { return z; } +void Montgomery_Params::redc_in_place(BigInt& x, secure_vector& ws) const { + const size_t output_size = 2 * m_p_words; + + if(ws.size() < output_size) { + ws.resize(output_size); + } + + x.grow_to(output_size); + + bigint_monty_redc(x.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size()); +} + BigInt Montgomery_Params::mul(const BigInt& x, const BigInt& y, secure_vector& ws) const { - const size_t output_size = 2 * m_p_words + 2; + BigInt z = BigInt::with_capacity(2 * m_p_words); + this->mul(z, x, y, ws); + return z; +} + +void Montgomery_Params::mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector& ws) const { + const size_t output_size = 2 * m_p_words; if(ws.size() < output_size) { ws.resize(output_size); @@ -78,7 +96,10 @@ BigInt Montgomery_Params::mul(const BigInt& x, const BigInt& y, secure_vector y, secure_vector& ws) const { + BigInt z = BigInt::with_capacity(2 * m_p_words); + this->mul(z, x, y, ws); return z; } -BigInt Montgomery_Params::mul(const BigInt& x, const secure_vector& y, secure_vector& ws) const { - const size_t output_size = 2 * m_p_words + 2; +void Montgomery_Params::mul(BigInt& z, const BigInt& x, std::span y, secure_vector& ws) const { + const size_t output_size = 2 * m_p_words; if(ws.size() < output_size) { ws.resize(output_size); } - BigInt z = BigInt::with_capacity(output_size); + if(z.size() < output_size) { + z.grow_to(output_size); + } BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); @@ -116,11 +143,9 @@ BigInt Montgomery_Params::mul(const BigInt& x, const secure_vector& y, sec ws.size()); bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size()); - - return z; } -void Montgomery_Params::mul_by(BigInt& x, const secure_vector& y, secure_vector& ws) const { +void Montgomery_Params::mul_by(BigInt& x, std::span y, secure_vector& ws) const { const size_t output_size = 2 * m_p_words; if(ws.size() < 2 * output_size) { @@ -183,21 +208,34 @@ void Montgomery_Params::mul_by(BigInt& x, const BigInt& y, secure_vector& } BigInt Montgomery_Params::sqr(const BigInt& x, secure_vector& ws) const { + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + return this->sqr(std::span{x._data(), x.size()}, ws); +} + +BigInt Montgomery_Params::sqr(std::span x, secure_vector& ws) const { + BigInt z = BigInt::with_capacity(2 * m_p_words); + this->sqr(z, x, ws); + return z; +} + +void Montgomery_Params::sqr(BigInt& z, const BigInt& x, secure_vector& ws) const { + this->sqr(z, std::span{x._data(), x.size()}, ws); +} + +void Montgomery_Params::sqr(BigInt& z, std::span x, secure_vector& ws) const { const size_t output_size = 2 * m_p_words; if(ws.size() < output_size) { ws.resize(output_size); } - BigInt z = BigInt::with_capacity(output_size); - - BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + if(z.size() < output_size) { + z.grow_to(output_size); + } - bigint_sqr(z.mutable_data(), z.size(), x._data(), x.size(), std::min(m_p_words, x.size()), ws.data(), ws.size()); + bigint_sqr(z.mutable_data(), z.size(), x.data(), x.size(), std::min(m_p_words, x.size()), ws.data(), ws.size()); bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size()); - - return z; } void Montgomery_Params::square_this(BigInt& x, secure_vector& ws) const { @@ -381,8 +419,7 @@ Montgomery_Int Montgomery_Int::cube(secure_vector& ws) const { Montgomery_Int Montgomery_Int::multiplicative_inverse() const { secure_vector ws; - const BigInt iv = m_params->mul(m_params->inv_mod_p(m_v), m_params->R3(), ws); - return Montgomery_Int(m_params, iv, false); + return Montgomery_Int(m_params, m_params->inv_mod_p(m_v, ws), false); } Montgomery_Int Montgomery_Int::additive_inverse() const { diff --git a/src/lib/math/numbertheory/monty.h b/src/lib/math/numbertheory/monty.h index f1cb970b30c..5090b210f77 100644 --- a/src/lib/math/numbertheory/monty.h +++ b/src/lib/math/numbertheory/monty.h @@ -1,5 +1,5 @@ /* -* (C) 2018 Jack Lloyd +* (C) 2018,2024 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -154,19 +154,31 @@ class BOTAN_TEST_API Montgomery_Params final { BigInt redc(const BigInt& x, secure_vector& ws) const; + void redc_in_place(BigInt& x, secure_vector& ws) const; + + void mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector& ws) const; + + void mul(BigInt& z, const BigInt& x, std::span y, secure_vector& ws) const; + BigInt mul(const BigInt& x, const BigInt& y, secure_vector& ws) const; - BigInt mul(const BigInt& x, const secure_vector& y, secure_vector& ws) const; + BigInt mul(const BigInt& x, std::span y, secure_vector& ws) const; - void mul_by(BigInt& x, const secure_vector& y, secure_vector& ws) const; + void mul_by(BigInt& x, std::span y, secure_vector& ws) const; void mul_by(BigInt& x, const BigInt& y, secure_vector& ws) const; BigInt sqr(const BigInt& x, secure_vector& ws) const; + BigInt sqr(std::span x, secure_vector& ws) const; + + void sqr(BigInt& z, const BigInt& x, secure_vector& ws) const; + + void sqr(BigInt& z, std::span x, secure_vector& ws) const; + void square_this(BigInt& x, secure_vector& ws) const; - BigInt inv_mod_p(const BigInt& x) const; + BigInt inv_mod_p(const BigInt& x, secure_vector& ws) const; private: BigInt m_p; diff --git a/src/lib/pubkey/ec_group/curve_gfp.cpp b/src/lib/pubkey/ec_group/curve_gfp.cpp deleted file mode 100644 index 9db949d141e..00000000000 --- a/src/lib/pubkey/ec_group/curve_gfp.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* -* Elliptic curves over GF(p) Montgomery Representation -* (C) 2014,2015,2018 Jack Lloyd -* 2016 Matthias Gierlings -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include - -#include -#include -#include -#include - -namespace Botan { - -namespace { - -class CurveGFp_Montgomery final : public CurveGFp_Repr { - public: - CurveGFp_Montgomery(const BigInt& p, const BigInt& a, const BigInt& b) : - m_p(p), - m_a(a), - m_b(b), - m_p_bits(m_p.bits()), - m_p_words(m_p.sig_words()), - m_p_dash(monty_inverse(m_p.word_at(0))) { - Modular_Reducer mod_p(m_p); - - m_r.set_bit(m_p_words * BOTAN_MP_WORD_BITS); - m_r = mod_p.reduce(m_r); - - m_r2 = mod_p.square(m_r); - m_r3 = mod_p.multiply(m_r, m_r2); - m_a_r = mod_p.multiply(m_r, m_a); - m_b_r = mod_p.multiply(m_r, m_b); - - m_a_is_zero = m_a.is_zero(); - m_a_is_minus_3 = (m_a + 3 == m_p); - } - - bool a_is_zero() const override { return m_a_is_zero; } - - bool a_is_minus_3() const override { return m_a_is_minus_3; } - - const BigInt& get_a() const override { return m_a; } - - const BigInt& get_b() const override { return m_b; } - - const BigInt& get_p() const override { return m_p; } - - const BigInt& get_a_rep() const override { return m_a_r; } - - const BigInt& get_b_rep() const override { return m_b_r; } - - const BigInt& get_1_rep() const override { return m_r; } - - bool is_one(const BigInt& x) const override { return x == m_r; } - - size_t get_p_bits() const override { return m_p_bits; } - - size_t get_ws_size() const override { return 2 * m_p_words; } - - BigInt invert_element(const BigInt& x, secure_vector& ws) const override; - - void to_curve_rep(BigInt& x, secure_vector& ws) const override; - - void from_curve_rep(BigInt& x, secure_vector& ws) const override; - - void curve_mul_words( - BigInt& z, const word x_words[], size_t x_size, const BigInt& y, secure_vector& ws) const override; - - void curve_sqr_words(BigInt& z, const word x_words[], size_t x_size, secure_vector& ws) const override; - - private: - BigInt m_p; - BigInt m_a, m_b; - BigInt m_a_r, m_b_r; - size_t m_p_bits; // cache of m_p.bits() - size_t m_p_words; // cache of m_p.sig_words() - - // Montgomery parameters - BigInt m_r, m_r2, m_r3; - word m_p_dash; - - bool m_a_is_zero; - bool m_a_is_minus_3; -}; - -BigInt CurveGFp_Montgomery::invert_element(const BigInt& x, secure_vector& ws) const { - // Should we use Montgomery inverse instead? - const BigInt inv = inverse_mod(x, m_p); - BigInt res; - curve_mul(res, inv, m_r3, ws); - return res; -} - -void CurveGFp_Montgomery::to_curve_rep(BigInt& x, secure_vector& ws) const { - const BigInt tx = x; - curve_mul(x, tx, m_r2, ws); -} - -void CurveGFp_Montgomery::from_curve_rep(BigInt& z, secure_vector& ws) const { - if(ws.size() < get_ws_size()) { - ws.resize(get_ws_size()); - } - - const size_t output_size = 2 * m_p_words; - if(z.size() < output_size) { - z.grow_to(output_size); - } - - bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size()); -} - -void CurveGFp_Montgomery::curve_mul_words( - BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector& ws) const { - BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); - - if(ws.size() < get_ws_size()) { - ws.resize(get_ws_size()); - } - - const size_t output_size = 2 * m_p_words; - if(z.size() < output_size) { - z.grow_to(output_size); - } - - bigint_mul(z.mutable_data(), - z.size(), - x_w, - x_size, - std::min(m_p_words, x_size), - y._data(), - y.size(), - std::min(m_p_words, y.size()), - ws.data(), - ws.size()); - - bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size()); -} - -void CurveGFp_Montgomery::curve_sqr_words(BigInt& z, const word x[], size_t x_size, secure_vector& ws) const { - if(ws.size() < get_ws_size()) { - ws.resize(get_ws_size()); - } - - const size_t output_size = 2 * m_p_words; - if(z.size() < output_size) { - z.grow_to(output_size); - } - - bigint_sqr(z.mutable_data(), z.size(), x, x_size, std::min(m_p_words, x_size), ws.data(), ws.size()); - - bigint_monty_redc(z.mutable_data(), m_p._data(), m_p_words, m_p_dash, ws.data(), ws.size()); -} - -} // namespace - -std::shared_ptr CurveGFp::choose_repr(const BigInt& p, const BigInt& a, const BigInt& b) { - return std::make_shared(p, a, b); -} - -} // namespace Botan diff --git a/src/lib/pubkey/ec_group/curve_gfp.h b/src/lib/pubkey/ec_group/curve_gfp.h index b47a797a56f..c77c10899e3 100644 --- a/src/lib/pubkey/ec_group/curve_gfp.h +++ b/src/lib/pubkey/ec_group/curve_gfp.h @@ -2,7 +2,7 @@ * Elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke -* 2010-2011,2012,2014 Jack Lloyd +* 2010-2011,2012,2014,2024 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -11,215 +11,73 @@ #define BOTAN_GFP_CURVE_H_ #include -#include // Currently exposed in EC_Point //BOTAN_FUTURE_INTERNAL_HEADER(curve_gfp.h) namespace Botan { -class BOTAN_UNSTABLE_API CurveGFp_Repr { - public: - virtual ~CurveGFp_Repr() = default; - - friend class CurveGFp; - - protected: - virtual const BigInt& get_p() const = 0; - virtual const BigInt& get_a() const = 0; - virtual const BigInt& get_b() const = 0; - - size_t get_p_words() const { - const size_t W_bits = sizeof(word) * 8; - return (get_p_bits() + W_bits - 1) / W_bits; - } - - virtual size_t get_p_bits() const = 0; - - virtual size_t get_ws_size() const = 0; - - virtual bool is_one(const BigInt& x) const = 0; - - virtual bool a_is_zero() const = 0; - - virtual bool a_is_minus_3() const = 0; - - /* - * Returns to_curve_rep(get_a()) - */ - virtual const BigInt& get_a_rep() const = 0; - - /* - * Returns to_curve_rep(get_b()) - */ - virtual const BigInt& get_b_rep() const = 0; - - /* - * Returns to_curve_rep(1) - */ - virtual const BigInt& get_1_rep() const = 0; - - virtual BigInt invert_element(const BigInt& x, secure_vector& ws) const = 0; - - virtual void to_curve_rep(BigInt& x, secure_vector& ws) const = 0; - - virtual void from_curve_rep(BigInt& x, secure_vector& ws) const = 0; - - void curve_mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector& ws) const { - BOTAN_DEBUG_ASSERT(x.sig_words() <= get_p_words()); - curve_mul_words(z, x._data(), x.size(), y, ws); - } - - virtual void curve_mul_words( - BigInt& z, const word x_words[], size_t x_size, const BigInt& y, secure_vector& ws) const = 0; - - void curve_sqr(BigInt& z, const BigInt& x, secure_vector& ws) const { - BOTAN_DEBUG_ASSERT(x.sig_words() <= get_p_words()); - curve_sqr_words(z, x._data(), x.size(), ws); - } - - virtual void curve_sqr_words(BigInt& z, const word x_words[], size_t x_size, secure_vector& ws) const = 0; -}; +class EC_Group_Data; /** -* This class represents an elliptic curve over GF(p) +* This is an internal type which is only exposed for accidental +* historical reasons. Do not use it in any way. * -* There should not be any reason for applications to use this type. -* If you need EC primitives use the interfaces EC_Group and EC_Point -* -* It is likely this class will be removed entirely in a future major -* release. +* This class will be removed in Botan4. */ class BOTAN_UNSTABLE_API CurveGFp final { public: /** * @return curve coefficient a */ - const BigInt& get_a() const { return m_repr->get_a(); } + const BigInt& get_a() const; /** * @return curve coefficient b */ - const BigInt& get_b() const { return m_repr->get_b(); } + const BigInt& get_b() const; /** * Get prime modulus of the field of the curve * @return prime modulus of the field of the curve */ - const BigInt& get_p() const { return m_repr->get_p(); } + const BigInt& get_p() const; + + size_t get_p_words() const; + + CurveGFp(const CurveGFp&) = default; private: friend class EC_Point; - friend class EC_Group; friend class EC_Group_Data; - friend class EC_Point_Base_Point_Precompute; - friend class EC_Point_Var_Point_Precompute; - friend class EC_Mul2Table_Data_BN; /** * Create an uninitialized CurveGFp */ CurveGFp() = default; - /** - * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p) - * @param p prime number of the field - * @param a first coefficient - * @param b second coefficient - */ - CurveGFp(const BigInt& p, const BigInt& a, const BigInt& b) : m_repr(choose_repr(p, a, b)) {} - - CurveGFp(const CurveGFp&) = default; + CurveGFp(const EC_Group_Data* group); CurveGFp& operator=(const CurveGFp&) = default; - size_t get_p_words() const { return m_repr->get_p_words(); } + void swap(CurveGFp& other) { std::swap(m_group, other.m_group); } - size_t get_p_bits() const { return m_repr->get_p_bits(); } + bool operator==(const CurveGFp& other) const { return (m_group == other.m_group); } - size_t get_p_bytes() const { return (get_p_bits() + 7) / 8; } - - size_t get_ws_size() const { return m_repr->get_ws_size(); } - - const BigInt& get_a_rep() const { return m_repr->get_a_rep(); } - - const BigInt& get_b_rep() const { return m_repr->get_b_rep(); } - - const BigInt& get_1_rep() const { return m_repr->get_1_rep(); } - - bool a_is_minus_3() const { return m_repr->a_is_minus_3(); } - - bool a_is_zero() const { return m_repr->a_is_zero(); } - - bool is_one(const BigInt& x) const { return m_repr->is_one(x); } - - BigInt invert_element(const BigInt& x, secure_vector& ws) const { return m_repr->invert_element(x, ws); } - - void to_rep(BigInt& x, secure_vector& ws) const { m_repr->to_curve_rep(x, ws); } - - void from_rep(BigInt& x, secure_vector& ws) const { m_repr->from_curve_rep(x, ws); } - - BigInt from_rep_to_tmp(const BigInt& x, secure_vector& ws) const { - BigInt xt(x); - m_repr->from_curve_rep(xt, ws); - return xt; - } - - // TODO: from_rep taking && ref - - void mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector& ws) const { - m_repr->curve_mul(z, x, y, ws); - } - - void mul(BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector& ws) const { - m_repr->curve_mul_words(z, x_w, x_size, y, ws); - } - - void sqr(BigInt& z, const BigInt& x, secure_vector& ws) const { m_repr->curve_sqr(z, x, ws); } - - void sqr(BigInt& z, const word x_w[], size_t x_size, secure_vector& ws) const { - m_repr->curve_sqr_words(z, x_w, x_size, ws); - } - - BigInt mul(const BigInt& x, const BigInt& y, secure_vector& ws) const { return mul_to_tmp(x, y, ws); } - - BigInt sqr(const BigInt& x, secure_vector& ws) const { return sqr_to_tmp(x, ws); } - - BigInt mul_to_tmp(const BigInt& x, const BigInt& y, secure_vector& ws) const { - BigInt z; - m_repr->curve_mul(z, x, y, ws); - return z; - } - - BigInt sqr_to_tmp(const BigInt& x, secure_vector& ws) const { - BigInt z; - m_repr->curve_sqr(z, x, ws); - return z; + private: + const EC_Group_Data& group() const { + BOTAN_ASSERT_NONNULL(m_group); + return *m_group; } - void swap(CurveGFp& other) { std::swap(m_repr, other.m_repr); } - - friend void swap(CurveGFp& x, CurveGFp& y) { x.swap(y); } - /** - * Equality operator - * @param other a curve - * @return true iff *this is the same as other + * Raw pointer + * + * This EC_Group_Data is not owned because instead the EC_Group_Data + * owns this CurveGFp, so we can always access it safely. If it was + * a shared_ptr this would cause a reference cycle. */ - inline bool operator==(const CurveGFp& other) const { - if(m_repr.get() == other.m_repr.get()) { - return true; - } - - return (get_p() == other.get_p()) && (get_a() == other.get_a()) && (get_b() == other.get_b()); - } - - inline bool operator!=(const CurveGFp& other) const = default; - - private: - static std::shared_ptr choose_repr(const BigInt& p, const BigInt& a, const BigInt& b); - - std::shared_ptr m_repr; + const EC_Group_Data* m_group = nullptr; }; } // namespace Botan diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp index 725ef09f283..51c56c49ec1 100644 --- a/src/lib/pubkey/ec_group/ec_group.cpp +++ b/src/lib/pubkey/ec_group/ec_group.cpp @@ -126,8 +126,7 @@ class EC_Group_Data_Map final { registration under an OID */ - std::shared_ptr new_group = - std::make_shared(p, a, b, g_x, g_y, order, cofactor, oid, source); + auto new_group = EC_Group_Data::create(p, a, b, g_x, g_y, order, cofactor, oid, source); if(oid.has_value()) { std::shared_ptr data = EC_Group::EC_group_info(oid); @@ -199,7 +198,7 @@ std::shared_ptr EC_Group::load_EC_group_info(const char* p_str, const BigInt order(order_str); const BigInt cofactor(1); // implicit - return std::make_shared(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin); + return EC_Group_Data::create(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin); } //static @@ -267,10 +266,9 @@ std::pair, bool> EC_Group::BER_decode_EC_group(st throw Decoding_Error("Invalid ECC cofactor parameter"); } - std::pair base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b); + const auto [g_x, g_y] = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b); - auto data = - ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID(), source); + auto data = ec_group_data().lookup_or_create(p, a, b, g_x, g_y, order, cofactor, OID(), source); return std::make_pair(data, true); } diff --git a/src/lib/pubkey/ec_group/ec_group.h b/src/lib/pubkey/ec_group/ec_group.h index a6029fb387b..787c89ead6d 100644 --- a/src/lib/pubkey/ec_group/ec_group.h +++ b/src/lib/pubkey/ec_group/ec_group.h @@ -341,26 +341,31 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final { /** * Return the cofactor * @result the cofactor + * TODO(Botan4): Remove this */ const BigInt& get_cofactor() const; /** * Return true if the cofactor is > 1 + * TODO(Botan4): Remove this */ bool has_cofactor() const; /* * For internal use only + * TODO(Botan4): Add underscore prefix */ static std::shared_ptr EC_group_info(const OID& oid); /* * For internal use only + * TODO(Botan4): Add underscore prefix */ static size_t clear_registered_curve_data(); /* * For internal use only + * TODO(Botan4): Add underscore prefix */ static OID EC_group_identity_from_order(const BigInt& order); diff --git a/src/lib/pubkey/ec_group/ec_inner_bn.cpp b/src/lib/pubkey/ec_group/ec_inner_bn.cpp index 92eff62900c..bf8513bbba3 100644 --- a/src/lib/pubkey/ec_group/ec_inner_bn.cpp +++ b/src/lib/pubkey/ec_group/ec_inner_bn.cpp @@ -81,7 +81,7 @@ EC_AffinePoint_Data_BN::EC_AffinePoint_Data_BN(std::shared_ptr pt) : m_group(std::move(group)) { BOTAN_ASSERT_NONNULL(m_group); - m_pt = Botan::OS2ECP(pt.data(), pt.size(), m_group->curve()); + m_pt = Botan::OS2ECP(pt, m_group->curve()); if(!m_pt.is_zero()) { m_xy = m_pt.xy_bytes(); } @@ -191,68 +191,7 @@ bool EC_Mul2Table_Data_BN::mul2_vartime_x_mod_order_eq(const EC_Scalar_Data& v, const auto& bn_y = EC_Scalar_Data_BN::checked_ref(y); const auto pt = m_tbl.multi_exp(bn_x.value(), bn_y.value()); - if(pt.is_zero()) { - return false; - } - - /* - * The trick used below doesn't work for curves with cofactors - */ - if(m_group->has_cofactor()) { - return m_group->mod_order(pt.get_affine_x()) == bn_v.value(); - } - - /* - * Note we're working with the projective coordinate directly here! - * Nominally we're comparing v with the affine x coordinate. - * - * return m_group->mod_order(pt.get_affine_x()) == bn_v.value(); - * - * However by instead projecting r to an identical z as the x - * coordinate, we can compare without having to perform an - * expensive inversion in the field. - * - * That is, given (x*z2) and r, instead of checking if - * (x*z2)*z2^-1 == r, - * we check if - * (x*z2) == (r*z2) - */ - auto& curve = m_group->curve(); - - secure_vector ws; - BigInt vr = bn_v.value(); - curve.to_rep(vr, ws); - BigInt z2, v_z2; - curve.sqr(z2, pt.get_z(), ws); - curve.mul(v_z2, vr, z2, ws); - - /* - * Since (typically) the group order is slightly less than the size - * of the field elements, its possible the signer had to reduce the - * r component. If they did not reduce r, then this value is correct. - * - * Due to the Hasse bound, this case occurs almost always; the - * probability that a reduction was actually required is - * approximately 1 in 2^(n/2) where n is the bit length of the curve. - */ - if(pt.get_x() == v_z2) { - return true; - } - - if(m_group->order_is_less_than_p()) { - vr = bn_v.value() + m_group->order(); - if(vr < m_group->p()) { - curve.to_rep(vr, ws); - curve.mul(v_z2, vr, z2, ws); - - if(pt.get_x() == v_z2) { - return true; - } - } - } - - // Reject: - return false; + return pt._is_x_eq_to_v_mod_order(bn_v.value()); } } // namespace Botan diff --git a/src/lib/pubkey/ec_group/ec_inner_data.cpp b/src/lib/pubkey/ec_group/ec_inner_data.cpp index d5c4f234328..f868e63fb03 100644 --- a/src/lib/pubkey/ec_group/ec_inner_data.cpp +++ b/src/lib/pubkey/ec_group/ec_inner_data.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ namespace Botan { EC_Group_Data::~EC_Group_Data() = default; +// Note this constructor *does not* initialize m_curve, m_base_point or m_base_mult EC_Group_Data::EC_Group_Data(const BigInt& p, const BigInt& a, const BigInt& b, @@ -25,14 +27,17 @@ EC_Group_Data::EC_Group_Data(const BigInt& p, const BigInt& cofactor, const OID& oid, EC_Group_Source source) : - m_curve(p, a, b), - m_base_point(m_curve, g_x, g_y), + m_p(p), + m_a(a), + m_b(b), m_g_x(g_x), m_g_y(g_y), m_order(order), m_cofactor(cofactor), + m_monty(m_p), m_mod_order(order), m_oid(oid), + m_p_words(p.sig_words()), m_p_bits(p.bits()), m_order_bits(order.bits()), m_order_bytes((m_order_bits + 7) / 8), @@ -52,9 +57,29 @@ EC_Group_Data::EC_Group_Data(const BigInt& p, } } - if(!m_pcurve) { - m_base_mult = std::make_unique(m_base_point, m_mod_order); + secure_vector ws; + m_a_r = m_monty.mul(a, m_monty.R2(), ws); + m_b_r = m_monty.mul(b, m_monty.R2(), ws); +} + +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) { + auto group = std::make_shared(p, a, b, g_x, g_y, order, cofactor, oid, source); + + group->m_curve = CurveGFp(group.get()); + group->m_base_point = EC_Point(group->m_curve, g_x, g_y); + if(!group->m_pcurve) { + group->m_base_mult = std::make_unique(group->m_base_point, group->m_mod_order); } + + return group; } bool EC_Group_Data::params_match(const BigInt& p, @@ -215,8 +240,7 @@ std::unique_ptr EC_Group_Data::point_deserialize(std::span< return nullptr; } } else { - auto pt = Botan::OS2ECP(bytes.data(), bytes.size(), curve()); - return std::make_unique(shared_from_this(), std::move(pt)); + return std::make_unique(shared_from_this(), bytes); } } catch(...) { return nullptr; diff --git a/src/lib/pubkey/ec_group/ec_inner_data.h b/src/lib/pubkey/ec_group/ec_inner_data.h index 1bba1789018..f668d01a73d 100644 --- a/src/lib/pubkey/ec_group/ec_inner_data.h +++ b/src/lib/pubkey/ec_group/ec_inner_data.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -113,15 +114,15 @@ class EC_Mul2Table_Data { class EC_Group_Data final : public std::enable_shared_from_this { public: - EC_Group_Data(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 std::shared_ptr 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); ~EC_Group_Data(); @@ -141,16 +142,22 @@ class EC_Group_Data final : public std::enable_shared_from_this { const std::vector& der_named_curve() const { return m_der_named_curve; } - const BigInt& p() const { return m_curve.get_p(); } + const BigInt& p() const { return m_p; } - const BigInt& a() const { return m_curve.get_a(); } + const BigInt& a() const { return m_a; } - const BigInt& b() const { return m_curve.get_b(); } + const BigInt& b() const { return m_b; } const BigInt& order() const { return m_order; } const BigInt& cofactor() const { return m_cofactor; } + const Montgomery_Params& monty() const { return m_monty; } + + const BigInt& monty_a() const { return m_a_r; } + + const BigInt& monty_b() const { return m_b_r; } + bool order_is_less_than_p() const { return m_order_is_less_than_p; } bool has_cofactor() const { return m_has_cofactor; } @@ -159,6 +166,8 @@ class EC_Group_Data final : public std::enable_shared_from_this { const BigInt& g_y() const { return m_g_y; } + size_t p_words() const { return m_p_words; } + size_t p_bits() const { return m_p_bits; } size_t p_bytes() const { return (m_p_bits + 7) / 8; } @@ -259,6 +268,21 @@ class EC_Group_Data final : public std::enable_shared_from_this { return *m_pcurve; } + /** + * Note this constructor should *only* be called by EC_Group_Data::create. + * + * It is only public to allow use of std::make_shared + */ + EC_Group_Data(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); + private: // Possibly nullptr (if pcurves not available or not a standard curve) std::shared_ptr m_pcurve; @@ -266,16 +290,27 @@ class EC_Group_Data final : public std::enable_shared_from_this { // Set only if m_pcurve is nullptr std::unique_ptr m_base_mult; - CurveGFp m_curve; - EC_Point m_base_point; - + BigInt m_p; + BigInt m_a; + BigInt m_b; BigInt m_g_x; BigInt m_g_y; BigInt m_order; BigInt m_cofactor; + + CurveGFp m_curve; + EC_Point m_base_point; + + // Montgomery parameters (only used for legacy EC_Point) + Montgomery_Params m_monty; + + BigInt m_a_r; // (a*r) % p + BigInt m_b_r; // (b*r) % p + Modular_Reducer m_mod_order; OID m_oid; std::vector m_der_named_curve; + size_t m_p_words; size_t m_p_bits; size_t m_order_bits; size_t m_order_bytes; diff --git a/src/lib/pubkey/ec_group/ec_point.cpp b/src/lib/pubkey/ec_group/ec_point.cpp index 9df143b0c63..e1199dd12c6 100644 --- a/src/lib/pubkey/ec_group/ec_point.cpp +++ b/src/lib/pubkey/ec_group/ec_point.cpp @@ -2,7 +2,7 @@ * Point arithmetic on elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke -* 2008-2011,2012,2014,2015,2018 Jack Lloyd +* 2008-2011,2012,2014,2015,2018,2024 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -10,51 +10,128 @@ #include #include +#include #include #include +#include +#include +#include #include namespace Botan { -EC_Point::EC_Point(const CurveGFp& curve) : m_curve(curve), m_coord_x(0), m_coord_y(curve.get_1_rep()), m_coord_z(0) { - // Assumes Montgomery rep of zero is zero +CurveGFp::CurveGFp(const EC_Group_Data* group) : m_group(group) { + BOTAN_ASSERT_NONNULL(m_group); +} + +const BigInt& CurveGFp::get_a() const { + return this->group().a(); +} + +const BigInt& CurveGFp::get_b() const { + return this->group().b(); +} + +const BigInt& CurveGFp::get_p() const { + return this->group().p(); +} + +size_t CurveGFp::get_p_words() const { + return this->group().p_words(); +} + +namespace { + +void to_rep(const EC_Group_Data& group, BigInt& x, secure_vector& ws) { + group.monty().mul_by(x, group.monty().R2(), ws); +} + +void from_rep(const EC_Group_Data& group, BigInt& z, secure_vector& ws) { + group.monty().redc_in_place(z, ws); +} + +BigInt from_rep_to_tmp(const EC_Group_Data& group, const BigInt& x, secure_vector& ws) { + return group.monty().redc(x, ws); +} + +void fe_mul(const EC_Group_Data& group, BigInt& z, const BigInt& x, const BigInt& y, secure_vector& ws) { + group.monty().mul(z, x, y, ws); +} + +void fe_mul( + const EC_Group_Data& group, BigInt& z, const word x_w[], size_t x_size, const BigInt& y, secure_vector& ws) { + group.monty().mul(z, y, std::span{x_w, x_size}, ws); +} + +BigInt fe_mul(const EC_Group_Data& group, const BigInt& x, const BigInt& y, secure_vector& ws) { + return group.monty().mul(x, y, ws); +} + +void fe_sqr(const EC_Group_Data& group, BigInt& z, const BigInt& x, secure_vector& ws) { + group.monty().sqr(z, x, ws); +} + +void fe_sqr(const EC_Group_Data& group, BigInt& z, const word x_w[], size_t x_size, secure_vector& ws) { + group.monty().sqr(z, std::span{x_w, x_size}, ws); +} + +BigInt fe_sqr(const EC_Group_Data& group, const BigInt& x, secure_vector& ws) { + return group.monty().sqr(x, ws); +} + +BigInt invert_element(const EC_Group_Data& group, const BigInt& x, secure_vector& ws) { + return group.monty().inv_mod_p(x, ws); +} + +} // namespace + +EC_Point::EC_Point(const CurveGFp& curve) : m_curve(curve), m_x(0), m_y(curve.group().monty().R1()), m_z(0) {} + +EC_Point EC_Point::zero() const { + return EC_Point(m_curve); } EC_Point::EC_Point(const CurveGFp& curve, BigInt x, BigInt y) : - m_curve(curve), m_coord_x(std::move(x)), m_coord_y(std::move(y)), m_coord_z(m_curve.get_1_rep()) { - if(m_coord_x < 0 || m_coord_x >= curve.get_p()) { + m_curve(curve), m_x(std::move(x)), m_y(std::move(y)), m_z(m_curve.group().monty().R1()) { + const auto& group = m_curve.group(); + + if(m_x < 0 || m_x >= group.p()) { throw Invalid_Argument("Invalid EC_Point affine x"); } - if(m_coord_y < 0 || m_coord_y >= curve.get_p()) { + if(m_y < 0 || m_y >= group.p()) { throw Invalid_Argument("Invalid EC_Point affine y"); } - secure_vector monty_ws(m_curve.get_ws_size()); - m_curve.to_rep(m_coord_x, monty_ws); - m_curve.to_rep(m_coord_y, monty_ws); + secure_vector monty_ws(2 * group.p_words()); + + to_rep(group, m_x, monty_ws); + to_rep(group, m_y, monty_ws); } void EC_Point::randomize_repr(RandomNumberGenerator& rng) { - secure_vector ws(m_curve.get_ws_size()); + const auto& group = m_curve.group(); + secure_vector ws(2 * group.p_words()); randomize_repr(rng, ws); } void EC_Point::randomize_repr(RandomNumberGenerator& rng, secure_vector& ws) { - const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p()); + const auto& group = m_curve.group(); + + const BigInt mask = BigInt::random_integer(rng, 2, group.p()); /* * No reason to convert this to Montgomery representation first, * just pretend the random mask was chosen as Redc(mask) and the * random mask we generated above is in the Montgomery * representation. - * //m_curve.to_rep(mask, ws); */ - const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws); - const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws); - m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws); - m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws); - m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws); + const BigInt mask2 = fe_sqr(group, mask, ws); + const BigInt mask3 = fe_mul(group, mask2, mask, ws); + + m_x = fe_mul(group, m_x, mask2, ws); + m_y = fe_mul(group, m_y, mask3, ws); + m_z = fe_mul(group, m_z, mask, ws); } namespace { @@ -77,14 +154,16 @@ void EC_Point::add_affine( return; } + const auto& group = m_curve.group(); + if(is_zero()) { - m_coord_x.set_words(x_words, x_size); - m_coord_y.set_words(y_words, y_size); - m_coord_z = m_curve.get_1_rep(); + m_x.set_words(x_words, x_size); + m_y.set_words(y_words, y_size); + m_z = group.monty().R1(); return; } - resize_ws(ws_bn, m_curve.get_ws_size()); + resize_ws(ws_bn, 2 * group.p_words()); secure_vector& ws = ws_bn[0].get_word_vector(); secure_vector& sub_ws = ws_bn[1].get_word_vector(); @@ -100,17 +179,17 @@ void EC_Point::add_affine( simplified with Z2 = 1 */ - const BigInt& p = m_curve.get_p(); + const BigInt& p = group.p(); - m_curve.sqr(T3, m_coord_z, ws); // z1^2 - m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 + fe_sqr(group, T3, m_z, ws); // z1^2 + fe_mul(group, T4, x_words, x_size, T3, ws); // x2*z1^2 - m_curve.mul(T2, m_coord_z, T3, ws); // z1^3 - m_curve.mul(T0, y_words, y_size, T2, ws); // y2*z1^3 + fe_mul(group, T2, m_z, T3, ws); // z1^3 + fe_mul(group, T0, y_words, y_size, T2, ws); // y2*z1^3 - T4.mod_sub(m_coord_x, p, sub_ws); // x2*z1^2 - x1*z2^2 + T4.mod_sub(m_x, p, sub_ws); // x2*z1^2 - x1*z2^2 - T0.mod_sub(m_coord_y, p, sub_ws); + T0.mod_sub(m_y, p, sub_ws); if(T4.is_zero()) { if(T0.is_zero()) { @@ -119,33 +198,33 @@ void EC_Point::add_affine( } // setting to zero: - m_coord_x.clear(); - m_coord_y = m_curve.get_1_rep(); - m_coord_z.clear(); + m_x.clear(); + m_y = group.monty().R1(); + m_z.clear(); return; } - m_curve.sqr(T2, T4, ws); + fe_sqr(group, T2, T4, ws); - m_curve.mul(T3, m_coord_x, T2, ws); + fe_mul(group, T3, m_x, T2, ws); - m_curve.mul(T1, T2, T4, ws); + fe_mul(group, T1, T2, T4, ws); - m_curve.sqr(m_coord_x, T0, ws); - m_coord_x.mod_sub(T1, p, sub_ws); + fe_sqr(group, m_x, T0, ws); + m_x.mod_sub(T1, p, sub_ws); - m_coord_x.mod_sub(T3, p, sub_ws); - m_coord_x.mod_sub(T3, p, sub_ws); + m_x.mod_sub(T3, p, sub_ws); + m_x.mod_sub(T3, p, sub_ws); - T3.mod_sub(m_coord_x, p, sub_ws); + T3.mod_sub(m_x, p, sub_ws); - m_curve.mul(T2, T0, T3, ws); - m_curve.mul(T0, m_coord_y, T1, ws); + fe_mul(group, T2, T0, T3, ws); + fe_mul(group, T0, m_y, T1, ws); T2.mod_sub(T0, p, sub_ws); - m_coord_y.swap(T2); + m_y.swap(T2); - m_curve.mul(T0, m_coord_z, T4, ws); - m_coord_z.swap(T0); + fe_mul(group, T0, m_z, T4, ws); + m_z.swap(T0); } void EC_Point::add(const word x_words[], @@ -159,14 +238,16 @@ void EC_Point::add(const word x_words[], return; } + const auto& group = m_curve.group(); + if(is_zero()) { - m_coord_x.set_words(x_words, x_size); - m_coord_y.set_words(y_words, y_size); - m_coord_z.set_words(z_words, z_size); + m_x.set_words(x_words, x_size); + m_y.set_words(y_words, y_size); + m_z.set_words(z_words, z_size); return; } - resize_ws(ws_bn, m_curve.get_ws_size()); + resize_ws(ws_bn, 2 * group.p_words()); secure_vector& ws = ws_bn[0].get_word_vector(); secure_vector& sub_ws = ws_bn[1].get_word_vector(); @@ -182,18 +263,18 @@ void EC_Point::add(const word x_words[], https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 */ - const BigInt& p = m_curve.get_p(); + const BigInt& p = group.p(); - m_curve.sqr(T0, z_words, z_size, ws); // z2^2 - m_curve.mul(T1, m_coord_x, T0, ws); // x1*z2^2 - m_curve.mul(T3, z_words, z_size, T0, ws); // z2^3 - m_curve.mul(T2, m_coord_y, T3, ws); // y1*z2^3 + fe_sqr(group, T0, z_words, z_size, ws); // z2^2 + fe_mul(group, T1, m_x, T0, ws); // x1*z2^2 + fe_mul(group, T3, z_words, z_size, T0, ws); // z2^3 + fe_mul(group, T2, m_y, T3, ws); // y1*z2^3 - m_curve.sqr(T3, m_coord_z, ws); // z1^2 - m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 + fe_sqr(group, T3, m_z, ws); // z1^2 + fe_mul(group, T4, x_words, x_size, T3, ws); // x2*z1^2 - m_curve.mul(T5, m_coord_z, T3, ws); // z1^3 - m_curve.mul(T0, y_words, y_size, T5, ws); // y2*z1^3 + fe_mul(group, T5, m_z, T3, ws); // z1^3 + fe_mul(group, T0, y_words, y_size, T5, ws); // y2*z1^3 T4.mod_sub(T1, p, sub_ws); // x2*z1^2 - x1*z2^2 @@ -206,32 +287,32 @@ void EC_Point::add(const word x_words[], } // setting to zero: - m_coord_x.clear(); - m_coord_y = m_curve.get_1_rep(); - m_coord_z.clear(); + m_x.clear(); + m_y = group.monty().R1(); + m_z.clear(); return; } - m_curve.sqr(T5, T4, ws); + fe_sqr(group, T5, T4, ws); - m_curve.mul(T3, T1, T5, ws); + fe_mul(group, T3, T1, T5, ws); - m_curve.mul(T1, T5, T4, ws); + fe_mul(group, T1, T5, T4, ws); - m_curve.sqr(m_coord_x, T0, ws); - m_coord_x.mod_sub(T1, p, sub_ws); - m_coord_x.mod_sub(T3, p, sub_ws); - m_coord_x.mod_sub(T3, p, sub_ws); + fe_sqr(group, m_x, T0, ws); + m_x.mod_sub(T1, p, sub_ws); + m_x.mod_sub(T3, p, sub_ws); + m_x.mod_sub(T3, p, sub_ws); - T3.mod_sub(m_coord_x, p, sub_ws); + T3.mod_sub(m_x, p, sub_ws); - m_curve.mul(m_coord_y, T0, T3, ws); - m_curve.mul(T3, T2, T1, ws); + fe_mul(group, m_y, T0, T3, ws); + fe_mul(group, T3, T2, T1, ws); - m_coord_y.mod_sub(T3, p, sub_ws); + m_y.mod_sub(T3, p, sub_ws); - m_curve.mul(T3, z_words, z_size, m_coord_z, ws); - m_curve.mul(m_coord_z, T3, T4, ws); + fe_mul(group, T3, z_words, z_size, m_z, ws); + fe_mul(group, m_z, T3, T4, ws); } void EC_Point::mult2i(size_t iterations, std::vector& ws_bn) { @@ -239,7 +320,7 @@ void EC_Point::mult2i(size_t iterations, std::vector& ws_bn) { return; } - if(m_coord_y.is_zero()) { + if(m_y.is_zero()) { *this = EC_Point(m_curve); // setting myself to zero return; } @@ -259,12 +340,14 @@ void EC_Point::mult2(std::vector& ws_bn) { return; } - if(m_coord_y.is_zero()) { + const auto& group = m_curve.group(); + + if(m_y.is_zero()) { *this = EC_Point(m_curve); // setting myself to zero return; } - resize_ws(ws_bn, m_curve.get_ws_size()); + resize_ws(ws_bn, 2 * group.p_words()); secure_vector& ws = ws_bn[0].get_word_vector(); secure_vector& sub_ws = ws_bn[1].get_word_vector(); @@ -278,63 +361,63 @@ void EC_Point::mult2(std::vector& ws_bn) { /* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc */ - const BigInt& p = m_curve.get_p(); + const BigInt& p = group.p(); - m_curve.sqr(T0, m_coord_y, ws); + fe_sqr(group, T0, m_y, ws); - m_curve.mul(T1, m_coord_x, T0, ws); + fe_mul(group, T1, m_x, T0, ws); T1.mod_mul(4, p, sub_ws); - if(m_curve.a_is_zero()) { + if(group.a_is_zero()) { // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2 - m_curve.sqr(T4, m_coord_x, ws); // x^2 - T4.mod_mul(3, p, sub_ws); // 3*x^2 - } else if(m_curve.a_is_minus_3()) { + fe_sqr(group, T4, m_x, ws); // x^2 + T4.mod_mul(3, p, sub_ws); // 3*x^2 + } else if(group.a_is_minus_3()) { /* if a == -3 then 3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2) */ - m_curve.sqr(T3, m_coord_z, ws); // z^2 + fe_sqr(group, T3, m_z, ws); // z^2 // (x-z^2) - T2 = m_coord_x; + T2 = m_x; T2.mod_sub(T3, p, sub_ws); // (x+z^2) - T3.mod_add(m_coord_x, p, sub_ws); + T3.mod_add(m_x, p, sub_ws); - m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2) + fe_mul(group, T4, T2, T3, ws); // (x-z^2)*(x+z^2) T4.mod_mul(3, p, sub_ws); // 3*(x-z^2)*(x+z^2) } else { - m_curve.sqr(T3, m_coord_z, ws); // z^2 - m_curve.sqr(T4, T3, ws); // z^4 - m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4 + fe_sqr(group, T3, m_z, ws); // z^2 + fe_sqr(group, T4, T3, ws); // z^4 + fe_mul(group, T3, group.monty_a(), T4, ws); // a*z^4 - m_curve.sqr(T4, m_coord_x, ws); // x^2 + fe_sqr(group, T4, m_x, ws); // x^2 T4.mod_mul(3, p, sub_ws); T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4 } - m_curve.sqr(T2, T4, ws); + fe_sqr(group, T2, T4, ws); T2.mod_sub(T1, p, sub_ws); T2.mod_sub(T1, p, sub_ws); - m_curve.sqr(T3, T0, ws); + fe_sqr(group, T3, T0, ws); T3.mod_mul(8, p, sub_ws); T1.mod_sub(T2, p, sub_ws); - m_curve.mul(T0, T4, T1, ws); + fe_mul(group, T0, T4, T1, ws); T0.mod_sub(T3, p, sub_ws); - m_coord_x.swap(T2); + m_x.swap(T2); - m_curve.mul(T2, m_coord_y, m_coord_z, ws); + fe_mul(group, T2, m_y, m_z, ws); T2.mod_mul(2, p, sub_ws); - m_coord_y.swap(T0); - m_coord_z.swap(T2); + m_y.swap(T0); + m_z.swap(T2); } // arithmetic operators @@ -407,43 +490,43 @@ void EC_Point::force_all_affine(std::span points, secure_vector& TODO is it really necessary to save all k points in c? */ - const CurveGFp& curve = points[0].m_curve; - const BigInt& rep_1 = curve.get_1_rep(); + const auto& group = points[0].m_curve.group(); + const BigInt& rep_1 = group.monty().R1(); - if(ws.size() < curve.get_ws_size()) { - ws.resize(curve.get_ws_size()); + if(ws.size() < 2 * group.p_words()) { + ws.resize(2 * group.p_words()); } std::vector c(points.size()); - c[0] = points[0].m_coord_z; + c[0] = points[0].m_z; for(size_t i = 1; i != points.size(); ++i) { - curve.mul(c[i], c[i - 1], points[i].m_coord_z, ws); + fe_mul(group, c[i], c[i - 1], points[i].m_z, ws); } - BigInt s_inv = curve.invert_element(c[c.size() - 1], ws); + BigInt s_inv = invert_element(group, c[c.size() - 1], ws); BigInt z_inv, z2_inv, z3_inv; for(size_t i = points.size() - 1; i != 0; i--) { EC_Point& point = points[i]; - curve.mul(z_inv, s_inv, c[i - 1], ws); + fe_mul(group, z_inv, s_inv, c[i - 1], ws); - s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws); + s_inv = fe_mul(group, s_inv, point.m_z, ws); - curve.sqr(z2_inv, z_inv, ws); - curve.mul(z3_inv, z2_inv, z_inv, ws); - point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws); - point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws); - point.m_coord_z = rep_1; + fe_sqr(group, z2_inv, z_inv, ws); + fe_mul(group, z3_inv, z2_inv, z_inv, ws); + point.m_x = fe_mul(group, point.m_x, z2_inv, ws); + point.m_y = fe_mul(group, point.m_y, z3_inv, ws); + point.m_z = rep_1; } - curve.sqr(z2_inv, s_inv, ws); - curve.mul(z3_inv, z2_inv, s_inv, ws); - points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws); - points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws); - points[0].m_coord_z = rep_1; + fe_sqr(group, z2_inv, s_inv, ws); + fe_mul(group, z3_inv, z2_inv, s_inv, ws); + points[0].m_x = fe_mul(group, points[0].m_x, z2_inv, ws); + points[0].m_y = fe_mul(group, points[0].m_y, z3_inv, ws); + points[0].m_z = rep_1; } void EC_Point::force_affine() { @@ -453,34 +536,40 @@ void EC_Point::force_affine() { secure_vector ws; - const BigInt z_inv = m_curve.invert_element(m_coord_z, ws); - const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws); - const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws); - m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws); - m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws); - m_coord_z = m_curve.get_1_rep(); + const auto& group = m_curve.group(); + + const BigInt z_inv = invert_element(group, m_z, ws); + const BigInt z2_inv = fe_sqr(group, z_inv, ws); + const BigInt z3_inv = fe_mul(group, z_inv, z2_inv, ws); + m_x = fe_mul(group, m_x, z2_inv, ws); + m_y = fe_mul(group, m_y, z3_inv, ws); + m_z = group.monty().R1(); } bool EC_Point::is_affine() const { - return m_curve.is_one(m_coord_z); + const auto& group = m_curve.group(); + return m_z == group.monty().R1(); } secure_vector EC_Point::x_bytes() const { - const size_t p_bytes = m_curve.get_p_bytes(); + const auto& group = m_curve.group(); + const size_t p_bytes = group.p_bytes(); secure_vector b(p_bytes); BigInt::encode_1363(b.data(), b.size(), this->get_affine_x()); return b; } secure_vector EC_Point::y_bytes() const { - const size_t p_bytes = m_curve.get_p_bytes(); + const auto& group = m_curve.group(); + const size_t p_bytes = group.p_bytes(); secure_vector b(p_bytes); BigInt::encode_1363(b.data(), b.size(), this->get_affine_y()); return b; } secure_vector EC_Point::xy_bytes() const { - const size_t p_bytes = m_curve.get_p_bytes(); + const auto& group = m_curve.group(); + const size_t p_bytes = group.p_bytes(); secure_vector b(2 * p_bytes); BigInt::encode_1363(&b[0], p_bytes, this->get_affine_x()); BigInt::encode_1363(&b[p_bytes], p_bytes, this->get_affine_y()); @@ -494,16 +583,18 @@ BigInt EC_Point::get_affine_x() const { secure_vector monty_ws; + const auto& group = m_curve.group(); + if(is_affine()) { - return m_curve.from_rep_to_tmp(m_coord_x, monty_ws); + return from_rep_to_tmp(group, m_x, monty_ws); } - BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); - z2 = m_curve.invert_element(z2, monty_ws); + BigInt z2 = fe_sqr(group, m_z, monty_ws); + z2 = invert_element(group, z2, monty_ws); BigInt r; - m_curve.mul(r, m_coord_x, z2, monty_ws); - m_curve.from_rep(r, monty_ws); + fe_mul(group, r, m_x, z2, monty_ws); + from_rep(group, r, monty_ws); return r; } @@ -512,19 +603,20 @@ BigInt EC_Point::get_affine_y() const { throw Invalid_State("Cannot convert zero point to affine"); } + const auto& group = m_curve.group(); secure_vector monty_ws; if(is_affine()) { - return m_curve.from_rep_to_tmp(m_coord_y, monty_ws); + return from_rep_to_tmp(group, m_y, monty_ws); } - const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); - const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); - const BigInt z3_inv = m_curve.invert_element(z3, monty_ws); + const BigInt z2 = fe_sqr(group, m_z, monty_ws); + const BigInt z3 = fe_mul(group, m_z, z2, monty_ws); + const BigInt z3_inv = invert_element(group, z3, monty_ws); BigInt r; - m_curve.mul(r, m_coord_y, z3_inv, monty_ws); - m_curve.from_rep(r, monty_ws); + fe_mul(group, r, m_y, z3_inv, monty_ws); + from_rep(group, r, monty_ws); return r; } @@ -539,37 +631,105 @@ bool EC_Point::on_the_curve() const { return true; } + const auto& group = m_curve.group(); secure_vector monty_ws; - const BigInt y2 = m_curve.from_rep_to_tmp(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws); - const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws); - const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws); - const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + const BigInt y2 = from_rep_to_tmp(group, fe_sqr(group, m_y, monty_ws), monty_ws); + const BigInt x3 = fe_mul(group, m_x, fe_sqr(group, m_x, monty_ws), monty_ws); + const BigInt ax = fe_mul(group, m_x, group.monty_a(), monty_ws); + const BigInt z2 = fe_sqr(group, m_z, monty_ws); + + const BigInt& monty_b = group.monty_b(); // Is z equal to 1 (in Montgomery form)? - if(m_coord_z == z2) { - if(y2 != m_curve.from_rep_to_tmp(x3 + ax + m_curve.get_b_rep(), monty_ws)) { + if(m_z == z2) { + if(y2 != from_rep_to_tmp(group, x3 + ax + monty_b, monty_ws)) { return false; } } - const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); - const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws); - const BigInt b_z6 = m_curve.mul_to_tmp(m_curve.get_b_rep(), m_curve.sqr_to_tmp(z3, monty_ws), monty_ws); + const BigInt z3 = fe_mul(group, m_z, z2, monty_ws); + const BigInt ax_z4 = fe_mul(group, ax, fe_sqr(group, z2, monty_ws), monty_ws); + const BigInt b_z6 = fe_mul(group, monty_b, fe_sqr(group, z3, monty_ws), monty_ws); - if(y2 != m_curve.from_rep_to_tmp(x3 + ax_z4 + b_z6, monty_ws)) { + if(y2 != from_rep_to_tmp(group, x3 + ax_z4 + b_z6, monty_ws)) { return false; } return true; } +bool EC_Point::_is_x_eq_to_v_mod_order(const BigInt& v) const { + if(this->is_zero()) { + return false; + } + + const auto& group = m_curve.group(); + + /* + * The trick used below doesn't work for curves with cofactors + */ + if(group.has_cofactor()) { + return group.mod_order(this->get_affine_x()) == v; + } + + /* + * Note we're working with the projective coordinate directly here! + * Nominally we're comparing v with the affine x coordinate. + * + * return group.mod_order(this->get_affine_x()) == v; + * + * However by instead projecting r to an identical z as the x + * coordinate, we can compare without having to perform an + * expensive inversion in the field. + * + * That is, given (x*z2) and r, instead of checking if + * (x*z2)*z2^-1 == r, + * we check if + * (x*z2) == (r*z2) + */ + secure_vector ws; + BigInt vr = v; + to_rep(group, vr, ws); + BigInt z2, v_z2; + fe_sqr(group, z2, this->get_z(), ws); + fe_mul(group, v_z2, vr, z2, ws); + + /* + * Since (typically) the group order is slightly less than the size + * of the field elements, its possible the signer had to reduce the + * r component. If they did not reduce r, then this value is correct. + * + * Due to the Hasse bound, this case occurs almost always; the + * probability that a reduction was actually required is + * approximately 1 in 2^(n/2) where n is the bit length of the curve. + */ + if(this->get_x() == v_z2) { + return true; + } + + if(group.order_is_less_than_p()) { + vr = v + group.order(); + if(vr < group.p()) { + to_rep(group, vr, ws); + fe_mul(group, v_z2, vr, z2, ws); + + if(this->get_x() == v_z2) { + return true; + } + } + } + + // Reject: + return false; +} + // swaps the states of *this and other void EC_Point::swap(EC_Point& other) noexcept { m_curve.swap(other.m_curve); - m_coord_x.swap(other.m_coord_x); - m_coord_y.swap(other.m_coord_y); - m_coord_z.swap(other.m_coord_z); + m_x.swap(other.m_x); + m_y.swap(other.m_y); + m_z.swap(other.m_z); } bool EC_Point::operator==(const EC_Point& other) const { @@ -591,7 +751,7 @@ std::vector EC_Point::encode(EC_Point_Format format) const { return std::vector(1); // single 0 byte } - const size_t p_bytes = m_curve.get_p().bytes(); + const size_t p_bytes = m_curve.group().p_bytes(); const BigInt x = get_affine_x(); const BigInt y = get_affine_y(); @@ -621,23 +781,17 @@ std::vector EC_Point::encode(EC_Point_Format format) const { namespace { -BigInt decompress_point( - bool yMod2, const BigInt& x, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) { - BigInt xpow3 = x * x * x; - - BigInt g = curve_a * x; - g += xpow3; - g += curve_b; - g = g % curve_p; +BigInt decompress_point(bool y_mod_2, const BigInt& x, const BigInt& p, const BigInt& a, const BigInt& b) { + const BigInt g = ((x * x + a) * x + b) % p; - BigInt z = sqrt_modulo_prime(g, curve_p); + BigInt z = sqrt_modulo_prime(g, p); if(z < 0) { throw Decoding_Error("Error during EC point decompression"); } - if(z.get_bit(0) != yMod2) { - z = curve_p - z; + if(z.get_bit(0) != y_mod_2) { + z = p - z; } return z; @@ -645,15 +799,19 @@ BigInt decompress_point( } // namespace +EC_Point OS2ECP(std::span data, const CurveGFp& curve) { + return OS2ECP(data.data(), data.size(), curve); +} + EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp& curve) { - // Should we really be doing this? - if(data_len <= 1) { - return EC_Point(curve); // return zero + if(data_len == 1 && data[0] == 0) { + // SEC1 standard representation of the point at infinity + return EC_Point(curve); } - std::pair xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b()); + const auto [g_x, g_y] = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b()); - EC_Point point(curve, xy.first, xy.second); + EC_Point point(curve, g_x, g_y); if(!point.on_the_curve()) { throw Decoding_Error("OS2ECP: Decoded point was not on the curve"); @@ -662,49 +820,53 @@ EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp& curve) { return point; } -std::pair OS2ECP( - const uint8_t data[], size_t data_len, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b) { - if(data_len <= 1) { - throw Decoding_Error("OS2ECP invalid point"); +std::pair OS2ECP(const uint8_t pt[], size_t pt_len, const BigInt& p, const BigInt& a, const BigInt& b) { + if(pt_len <= 1) { + throw Decoding_Error("OS2ECP invalid point encoding"); } - const uint8_t pc = data[0]; + const uint8_t pc = pt[0]; + const size_t p_bytes = p.bytes(); BigInt x, y; if(pc == 2 || pc == 3) { - //compressed form - x = BigInt::decode(&data[1], data_len - 1); + if(pt_len != 1 + p_bytes) { + throw Decoding_Error("OS2ECP invalid point encoding"); + } + x = BigInt::decode(&pt[1], pt_len - 1); const bool y_mod_2 = ((pc & 0x01) == 1); - y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b); + y = decompress_point(y_mod_2, x, p, a, b); } else if(pc == 4) { - const size_t l = (data_len - 1) / 2; + if(pt_len != 1 + 2 * p_bytes) { + throw Decoding_Error("OS2ECP invalid point encoding"); + } - // uncompressed form - x = BigInt::decode(&data[1], l); - y = BigInt::decode(&data[l + 1], l); + x = BigInt::decode(&pt[1], p_bytes); + y = BigInt::decode(&pt[p_bytes + 1], p_bytes); } else if(pc == 6 || pc == 7) { - const size_t l = (data_len - 1) / 2; + if(pt_len != 1 + 2 * p_bytes) { + throw Decoding_Error("OS2ECP invalid point encoding"); + } - // hybrid form - x = BigInt::decode(&data[1], l); - y = BigInt::decode(&data[l + 1], l); + x = BigInt::decode(&pt[1], p_bytes); + y = BigInt::decode(&pt[p_bytes + 1], p_bytes); const bool y_mod_2 = ((pc & 0x01) == 1); - if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y) { + if(decompress_point(y_mod_2, x, p, a, b) != y) { throw Decoding_Error("OS2ECP: Decoding error in hybrid format"); } } else { - throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc)); + throw Decoding_Error("OS2ECP: Unknown format type " + std::to_string(static_cast(pc))); } - return std::make_pair(x, y); -} + if(x >= p || y >= p) { + throw Decoding_Error("OS2ECP invalid point encoding"); + } -EC_Point OS2ECP(std::span data, const CurveGFp& curve) { - return OS2ECP(data.data(), data.size(), curve); + return std::make_pair(x, y); } } // namespace Botan diff --git a/src/lib/pubkey/ec_group/ec_point.h b/src/lib/pubkey/ec_group/ec_point.h index 2dfe6ca6920..6e7ca81aaa0 100644 --- a/src/lib/pubkey/ec_group/ec_point.h +++ b/src/lib/pubkey/ec_group/ec_point.h @@ -2,7 +2,7 @@ * Point arithmetic on elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke -* 2008-2011,2014,2015 Jack Lloyd +* 2008-2011,2014,2015,2024 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -54,7 +54,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { * Construct the zero point * @param curve The base curve */ - explicit EC_Point(const CurveGFp& curve); + BOTAN_DEPRECATED("Deprecated no replacement") explicit EC_Point(const CurveGFp& curve); /** * Copy constructor @@ -96,12 +96,11 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { /** * Construct a point from its affine coordinates - * Prefer EC_Group::point(x,y) for this operation. * @param curve the base curve * @param x affine x coordinate * @param y affine y coordinate */ - EC_Point(const CurveGFp& curve, BigInt x, BigInt y); + BOTAN_DEPRECATED("Use EC_AffinePoint::from_bigint_xy") EC_Point(const CurveGFp& curve, BigInt x, BigInt y); /** * EC2OSP - elliptic curve to octet string primitive @@ -136,7 +135,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { */ EC_Point& negate() { if(!is_zero()) { - m_coord_y = m_curve.get_p() - m_coord_y; + m_y = m_curve.get_p() - m_y; } return *this; } @@ -164,7 +163,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { * Is this the point at infinity? * @result true, if this point is at infinity, false otherwise. */ - bool is_zero() const { return m_coord_z.is_zero(); } + bool is_zero() const { return m_z.is_zero(); } /** * Checks whether the point is to be found on the underlying @@ -203,7 +202,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { /** * Return the zero (aka infinite) point associated with this curve */ - EC_Point zero() const { return EC_Point(m_curve); } + EC_Point zero() const; /** * Randomize the point representation @@ -224,10 +223,14 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { */ void swap(EC_Point& other) noexcept; + /** + * For internal use only + */ + bool _is_x_eq_to_v_mod_order(const BigInt& v) const; + #if defined(BOTAN_DISABLE_DEPRECATED_FEATURES) private: - friend class EC_Mul2Table_Data_BN; #endif /** @@ -235,28 +238,28 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { * * Note this may be in Montgomery form */ - BOTAN_DEPRECATED("Use affine coordinates only") const BigInt& get_x() const { return m_coord_x; } + BOTAN_DEPRECATED("Use affine coordinates only") const BigInt& get_x() const { return m_x; } /** * Return the internal y coordinate * * Note this may be in Montgomery form */ - BOTAN_DEPRECATED("Use affine coordinates only") const BigInt& get_y() const { return m_coord_y; } + BOTAN_DEPRECATED("Use affine coordinates only") const BigInt& get_y() const { return m_y; } /** * Return the internal z coordinate * * Note this may be in Montgomery form */ - BOTAN_DEPRECATED("Use affine coordinates only") const BigInt& get_z() const { return m_coord_z; } + BOTAN_DEPRECATED("Use affine coordinates only") const BigInt& get_z() const { return m_z; } BOTAN_DEPRECATED("Deprecated no replacement") void swap_coords(BigInt& new_x, BigInt& new_y, BigInt& new_z) { - m_coord_x.swap(new_x); - m_coord_y.swap(new_y); - m_coord_z.swap(new_z); + m_x.swap(new_x); + m_y.swap(new_y); + m_z.swap(new_z); } friend void swap(EC_Point& x, EC_Point& y) { x.swap(y); } @@ -277,12 +280,12 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { const size_t p_words = m_curve.get_p_words(); - add(other.m_coord_x._data(), - std::min(p_words, other.m_coord_x.size()), - other.m_coord_y._data(), - std::min(p_words, other.m_coord_y.size()), - other.m_coord_z._data(), - std::min(p_words, other.m_coord_z.size()), + add(other.m_x._data(), + std::min(p_words, other.m_x.size()), + other.m_y._data(), + std::min(p_words, other.m_y.size()), + other.m_z._data(), + std::min(p_words, other.m_z.size()), workspace); } @@ -319,10 +322,10 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { BOTAN_DEBUG_ASSERT(other.is_affine()); const size_t p_words = m_curve.get_p_words(); - add_affine(other.m_coord_x._data(), - std::min(p_words, other.m_coord_x.size()), - other.m_coord_y._data(), - std::min(p_words, other.m_coord_y.size()), + add_affine(other.m_x._data(), + std::min(p_words, other.m_x.size()), + other.m_y._data(), + std::min(p_words, other.m_y.size()), workspace); } @@ -380,11 +383,11 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { * * You should not need to use this */ - const CurveGFp& get_curve() const { return m_curve; } + BOTAN_DEPRECATED("Deprecated no replacement") const CurveGFp& get_curve() const { return m_curve; } private: CurveGFp m_curve; - BigInt m_coord_x, m_coord_y, m_coord_z; + BigInt m_x, m_y, m_z; }; /** @@ -395,8 +398,9 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { * @param z2 a scalar * @result (p1 * z1 + p2 * z2) */ -BOTAN_PUBLIC_API(2, 0) -EC_Point multi_exponentiate(const EC_Point& p1, const BigInt& z1, const EC_Point& p2, const BigInt& z2); +BOTAN_DEPRECATED("Use EC_Affinepoint::mul_px_qy") +EC_Point BOTAN_PUBLIC_API(2, 0) + multi_exponentiate(const EC_Point& p1, const BigInt& z1, const EC_Point& p2, const BigInt& z2); // arithmetic operators inline EC_Point operator-(const EC_Point& lhs) { @@ -430,7 +434,9 @@ EC_Point BOTAN_PUBLIC_API(2, 0) OS2ECP(const uint8_t data[], size_t data_len, co /** * Perform point decoding -* Use EC_Group::OS2ECP instead +* +* This is an internal function which was accidentally made public. +* Do not use it; it will be removed in Botan4. * * @param data the encoded point * @param data_len length of data in bytes