diff options
author | Jack Lloyd <[email protected]> | 2018-03-08 07:21:43 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-03-08 07:36:02 -0500 |
commit | 300cc7e5523396bae65f61485406a0bf392d8320 (patch) | |
tree | bd68ed9f7d5a6902247c9101544431b1e42dc75b /src/lib/pubkey | |
parent | 34aa3778a0f426fb7487c62049570d504e447c2f (diff) |
Add mixed (J+A) point addition, new scalar mul for base points
Adds PointGFp::force_affine(), ::add_affine(), and ::is_affine()
Use a (very simple) technique for base point precomputations.
Stick with fixed window for variable point inputs.
Scalar blinding is now always enabled
Diffstat (limited to 'src/lib/pubkey')
-rw-r--r-- | src/lib/pubkey/ec_group/curve_gfp.cpp | 42 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/curve_gfp.h | 11 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/ec_group.cpp | 24 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/ec_group.h | 13 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/info.txt | 10 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/point_gfp.cpp | 160 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/point_gfp.h | 77 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/point_mul.cpp | 131 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/point_mul.h | 47 | ||||
-rw-r--r-- | src/lib/pubkey/ecdh/ecdh.cpp | 5 | ||||
-rw-r--r-- | src/lib/pubkey/ecies/ecies.cpp | 5 | ||||
-rw-r--r-- | src/lib/pubkey/sm2/sm2_enc.cpp | 14 |
12 files changed, 403 insertions, 136 deletions
diff --git a/src/lib/pubkey/ec_group/curve_gfp.cpp b/src/lib/pubkey/ec_group/curve_gfp.cpp index 216f2a894..e17812ca4 100644 --- a/src/lib/pubkey/ec_group/curve_gfp.cpp +++ b/src/lib/pubkey/ec_group/curve_gfp.cpp @@ -25,13 +25,15 @@ class CurveGFp_Montgomery final : public CurveGFp_Repr m_p_words(m_p.sig_words()), m_p_dash(monty_inverse(m_p.word_at(0))) { - const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); - Modular_Reducer mod_p(m_p); - m_r2 = mod_p.square(r); - m_a_r = mod_p.multiply(r, m_a); - m_b_r = mod_p.multiply(r, m_b); + 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); } const BigInt& get_a() const override { return m_a; } @@ -44,8 +46,12 @@ class CurveGFp_Montgomery final : public CurveGFp_Repr const BigInt& get_b_rep() const override { return m_b_r; } + bool is_one(const BigInt& x) const override { return x == m_r; } + size_t get_p_words() const override { return m_p_words; } + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; + void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override; void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override; @@ -56,14 +62,25 @@ class CurveGFp_Montgomery final : public CurveGFp_Repr void curve_sqr(BigInt& z, const BigInt& x, secure_vector<word>& ws) const override; private: - BigInt m_p, m_a, m_b; + BigInt m_p; + BigInt m_a, m_b; + BigInt m_a_r, m_b_r; size_t m_p_words; // cache of m_p.sig_words() // Montgomery parameters - BigInt m_r2, m_a_r, m_b_r; + BigInt m_r, m_r2, m_r3; word m_p_dash; }; +BigInt CurveGFp_Montgomery::invert_element(const BigInt& x, secure_vector<word>& 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<word>& ws) const { const BigInt tx = x; @@ -149,12 +166,16 @@ class CurveGFp_NIST : public CurveGFp_Repr const BigInt& get_b_rep() const override { return m_b; } + bool is_one(const BigInt& x) const override { return x == 1; } + void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override { redc(x, ws); } void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override { redc(x, ws); } + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; + void curve_mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector<word>& ws) const override; @@ -168,6 +189,13 @@ class CurveGFp_NIST : public CurveGFp_Repr size_t m_p_words; // cache of m_p.sig_words() }; + +BigInt CurveGFp_NIST::invert_element(const BigInt& x, secure_vector<word>& ws) const + { + BOTAN_UNUSED(ws); + return inverse_mod(x, get_p()); + } + void CurveGFp_NIST::curve_mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector<word>& ws) const { diff --git a/src/lib/pubkey/ec_group/curve_gfp.h b/src/lib/pubkey/ec_group/curve_gfp.h index 60e1a485d..d9649474b 100644 --- a/src/lib/pubkey/ec_group/curve_gfp.h +++ b/src/lib/pubkey/ec_group/curve_gfp.h @@ -26,6 +26,8 @@ class BOTAN_UNSTABLE_API CurveGFp_Repr virtual size_t get_p_words() const = 0; + virtual bool is_one(const BigInt& x) const = 0; + /* * Returns to_curve_rep(get_a()) */ @@ -36,6 +38,8 @@ class BOTAN_UNSTABLE_API CurveGFp_Repr */ virtual const BigInt& get_b_rep() const = 0; + virtual BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const = 0; + virtual void to_curve_rep(BigInt& x, secure_vector<word>& ws) const = 0; virtual void from_curve_rep(BigInt& x, secure_vector<word>& ws) const = 0; @@ -96,6 +100,13 @@ class BOTAN_UNSTABLE_API CurveGFp final const BigInt& get_b_rep() const { return m_repr->get_b_rep(); } + bool is_one(const BigInt& x) const { return m_repr->is_one(x); } + + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const + { + return m_repr->invert_element(x, ws); + } + void to_rep(BigInt& x, secure_vector<word>& ws) const { m_repr->to_curve_rep(x, ws); diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp index 9da1cd81f..723a4148e 100644 --- a/src/lib/pubkey/ec_group/ec_group.cpp +++ b/src/lib/pubkey/ec_group/ec_group.cpp @@ -9,6 +9,7 @@ */ #include <botan/ec_group.h> +#include <botan/internal/point_mul.h> #include <botan/ber_dec.h> #include <botan/der_enc.h> #include <botan/oids.h> @@ -17,10 +18,6 @@ #include <botan/mutex.h> #include <vector> -#if defined(BOTAN_HAS_SYSTEM_RNG) - #include <botan/system_rng.h> -#endif - namespace Botan { class EC_Group_Data final @@ -42,15 +39,12 @@ class EC_Group_Data final m_order(order), m_cofactor(cofactor), m_mod_order(order), - m_base_mult(m_base_point, 5), + m_base_mult(m_base_point), m_oid(oid), m_p_bits(p.bits()), m_order_bits(order.bits()), m_a_is_minus_3(a == p - 3) { -#if defined(BOTAN_HAS_SYSTEM_RNG) - m_base_mult.randomize(system_rng()); -#endif } bool match(const BigInt& p, const BigInt& a, const BigInt& b, @@ -97,7 +91,7 @@ class EC_Group_Data final RandomNumberGenerator& rng, std::vector<BigInt>& ws) const { - return m_base_mult.mul(k, m_order, rng, ws); + return m_base_mult.mul(k, rng, m_order, ws); } private: @@ -109,7 +103,7 @@ class EC_Group_Data final BigInt m_order; BigInt m_cofactor; Modular_Reducer m_mod_order; - PointGFp_Blinded_Multiplier m_base_mult; + PointGFp_Base_Point_Precompute m_base_mult; OID m_oid; size_t m_p_bits; size_t m_order_bits; @@ -489,6 +483,16 @@ PointGFp EC_Group::blinded_base_point_multiply(const BigInt& k, return data().blinded_base_point_multiply(k, rng, ws); } +PointGFp EC_Group::blinded_var_point_multiply(const PointGFp& point, + const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const + { + PointGFp_Var_Point_Precompute mul(point); + mul.randomize_repr(rng); + return mul.mul(k, rng, get_order(), ws); + } + PointGFp EC_Group::zero_point() const { return PointGFp(data().curve()); diff --git a/src/lib/pubkey/ec_group/ec_group.h b/src/lib/pubkey/ec_group/ec_group.h index 938059fc4..8238c2902 100644 --- a/src/lib/pubkey/ec_group/ec_group.h +++ b/src/lib/pubkey/ec_group/ec_group.h @@ -247,6 +247,19 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final std::vector<BigInt>& ws) const; /** + * Blinded point multiplication, attempts resistance to side channels + * @param point input point + * @param k the scalar + * @param rng a random number generator + * @param ws a temp workspace + * @return point*k + */ + PointGFp blinded_var_point_multiply(const PointGFp& point, + const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const; + + /** * Return the zero (or infinite) point on this curve */ PointGFp zero_point() const; diff --git a/src/lib/pubkey/ec_group/info.txt b/src/lib/pubkey/ec_group/info.txt index a0d025379..e382e25a5 100644 --- a/src/lib/pubkey/ec_group/info.txt +++ b/src/lib/pubkey/ec_group/info.txt @@ -8,3 +8,13 @@ asn1 numbertheory pem </requires> + +<header:internal> +point_mul.h +</header:internal> + +<header:public> +curve_gfp.h +ec_group.h +point_gfp.h +</header:public> diff --git a/src/lib/pubkey/ec_group/point_gfp.cpp b/src/lib/pubkey/ec_group/point_gfp.cpp index da8b292f4..7968d2dcd 100644 --- a/src/lib/pubkey/ec_group/point_gfp.cpp +++ b/src/lib/pubkey/ec_group/point_gfp.cpp @@ -63,9 +63,113 @@ void PointGFp::randomize_repr(RandomNumberGenerator& rng) } } +void PointGFp::add_affine(const PointGFp& rhs, std::vector<BigInt>& ws_bn) + { + if(rhs.is_zero()) + return; + + if(is_zero()) + { + m_coord_x = rhs.m_coord_x; + m_coord_y = rhs.m_coord_y; + m_coord_z = rhs.m_coord_z; + return; + } + + BOTAN_ASSERT(rhs.is_affine(), "PointGFp::add_affine requires arg be affine point"); + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + simplified with Z2 = 1 + */ + + const BigInt& p = m_curve.get_p(); + + const size_t cap_size = 2*m_curve.get_p_words() + 2; + + BOTAN_ASSERT(ws_bn.size() >= WORKSPACE_SIZE, "Expected size for PointGFp::add workspace"); + + for(size_t i = 0; i != ws_bn.size(); ++i) + ws_bn[i].ensure_capacity(cap_size); + + secure_vector<word>& ws = ws_bn[0].get_word_vector(); + + BigInt& T0 = ws_bn[1]; + BigInt& T1 = ws_bn[2]; + BigInt& T2 = ws_bn[3]; + BigInt& T3 = ws_bn[4]; + BigInt& T4 = ws_bn[5]; + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + */ + + m_curve.sqr(T3, m_coord_z, ws); // z1^2 + m_curve.mul(T4, rhs.m_coord_x, T3, ws); // x2*z1^2 + + m_curve.mul(T2, m_coord_z, T3, ws); // z1^3 + m_curve.mul(T0, rhs.m_coord_y, T2, ws); // y2*z1^3 + + T4 -= m_coord_x; // x2*z1^2 - x1*z2^2 + if(T4.is_negative()) + T4 += p; + + T0 -= m_coord_y; + if(T0.is_negative()) + T0 += p; + + if(T4.is_zero()) + { + if(T0.is_zero()) + { + mult2(ws_bn); + return; + } + + // setting to zero: + m_coord_x = 0; + m_coord_y = 1; + m_coord_z = 0; + return; + } + + m_curve.sqr(T2, T4, ws); + + m_curve.mul(T3, m_coord_x, T2, ws); + + m_curve.mul(T1, T2, T4, ws); + + m_curve.sqr(m_coord_x, T0, ws); + m_coord_x -= T1; + m_coord_x -= T3; + m_coord_x -= T3; + while(m_coord_x.is_negative()) + m_coord_x += p; + + T3 -= m_coord_x; + if(T3.is_negative()) + T3 += p; + + T2 = m_coord_y; + m_curve.mul(m_coord_y, T0, T3, ws); + m_curve.mul(T3, T2, T1, ws); + m_coord_y -= T3; + if(m_coord_y.is_negative()) + m_coord_y += p; + + T3 = m_coord_z; + m_curve.mul(m_coord_z, T3, T4, ws); + } + // Point addition void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn) { + if(rhs.is_zero()) + return; + + if(rhs.is_affine()) + return this->add_affine(rhs, ws_bn); + if(is_zero()) { m_coord_x = rhs.m_coord_x; @@ -73,8 +177,6 @@ void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn) m_coord_z = rhs.m_coord_z; return; } - else if(rhs.is_zero()) - return; const BigInt& p = m_curve.get_p(); @@ -345,17 +447,48 @@ PointGFp operator*(const BigInt& scalar, const PointGFp& point) return R[0]; } +void PointGFp::force_affine() + { + if(is_zero()) + throw Invalid_State("Cannot convert zero ECC point to affine"); + + secure_vector<word> ws; + BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, ws); + BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, ws); + + const BigInt z5 = m_curve.mul_to_tmp(z2, z3, ws); + const BigInt z5_inv = m_curve.invert_element(z5, ws); + const BigInt z2_inv = m_curve.mul_to_tmp(z5_inv, z3, ws); + const BigInt z3_inv = m_curve.mul_to_tmp(z5_inv, z2, 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 = 1; + m_curve.to_rep(m_coord_z, ws); + } + +bool PointGFp::is_affine() const + { + return m_curve.is_one(m_coord_z); + } + BigInt PointGFp::get_affine_x() const { if(is_zero()) throw Illegal_Transformation("Cannot convert zero point to affine"); secure_vector<word> monty_ws; - BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); - m_curve.from_rep(z2, monty_ws); - z2 = inverse_mod(z2, m_curve.get_p()); - return m_curve.mul_to_tmp(z2, m_coord_x, monty_ws); + if(is_affine()) + return m_curve.from_rep(m_coord_x, monty_ws); + + const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + const BigInt z2_inv = m_curve.invert_element(z2, monty_ws); + + BigInt r; + m_curve.mul(r, m_coord_x, z2_inv, monty_ws); + m_curve.from_rep(r, monty_ws); + return r; } BigInt PointGFp::get_affine_y() const @@ -364,11 +497,18 @@ BigInt PointGFp::get_affine_y() const throw Illegal_Transformation("Cannot convert zero point to affine"); secure_vector<word> monty_ws; - BigInt z3 = m_curve.mul_to_tmp(m_coord_z, m_curve.sqr_to_tmp(m_coord_z, monty_ws), monty_ws); - z3 = inverse_mod(z3, m_curve.get_p()); - m_curve.to_rep(z3, monty_ws); - return m_curve.mul_to_tmp(z3, m_coord_y, monty_ws); + if(is_affine()) + return m_curve.from_rep(m_coord_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); + + BigInt r; + m_curve.mul(r, m_coord_y, z3_inv, monty_ws); + m_curve.from_rep(r, monty_ws); + return r; } bool PointGFp::on_the_curve() const diff --git a/src/lib/pubkey/ec_group/point_gfp.h b/src/lib/pubkey/ec_group/point_gfp.h index abcc9656e..71701d587 100644 --- a/src/lib/pubkey/ec_group/point_gfp.h +++ b/src/lib/pubkey/ec_group/point_gfp.h @@ -149,6 +149,13 @@ class BOTAN_PUBLIC_API(2,0) PointGFp final BigInt get_affine_y() const; /** + * Force this point to affine coordinates + */ + void force_affine(); + + bool is_affine() const; + + /** * Is this the point at infinity? * @result true, if this point is at infinity, false otherwise. */ @@ -186,6 +193,13 @@ class BOTAN_PUBLIC_API(2,0) PointGFp final void add(const PointGFp& other, std::vector<BigInt>& workspace); /** + * Point addition - mixed J+A + * @param other affine point to add + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add_affine(const PointGFp& other, std::vector<BigInt>& workspace); + + /** * Point doubling * @param workspace temp space, at least WORKSPACE_SIZE elements */ @@ -284,69 +298,22 @@ template<typename Alloc> PointGFp OS2ECP(const std::vector<uint8_t, Alloc>& data, const CurveGFp& curve) { return OS2ECP(data.data(), data.size(), curve); } +class PointGFp_Var_Point_Precompute; + /** -* Blinded ECC point multiplication +* Deprecated API for point multiplication +* Use EC_Group::blinded_base_point_multiply or EC_Group::blinded_var_point_multiply */ -class BOTAN_PUBLIC_API(2,5) PointGFp_Blinded_Multiplier final - { - public: - /** - * @param base_point the point that will be multiplied (eg, the base point of the curve) - * @param w the window bits (leave as zero to take a default value) - */ - PointGFp_Blinded_Multiplier(const PointGFp& base_point, - size_t w = 0); - - /** - * @param base_point the point that will be multiplied (eg, the base point of the curve) - * @param ws a temporary workspace - * @param w the window bits (leave as zero to take a default value) - */ - PointGFp_Blinded_Multiplier(const PointGFp& base_point, - std::vector<BigInt>& ws, - size_t w = 0); - - /** - * Randomize the internal state. Changing the values may provide - * some protection against side channel attacks. - * @param rng a random number generator - */ - void randomize(RandomNumberGenerator& rng); - - /** - * Perform blinded point multiplication - * @param k the scalar - * @param group_order the order of the group - * @param rng a random number generator - * @param ws a temporary workspace - * @return base_point*k - */ - PointGFp mul(const BigInt& k, - const BigInt& group_order, - RandomNumberGenerator& rng, - std::vector<BigInt>& ws) const; - private: - void init(const PointGFp& base_point, size_t w, std::vector<BigInt>& ws); - - std::vector<PointGFp> m_U; - size_t m_h; - }; - -class BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use PointGFp_Blinded_Multiplier") Blinded_Point_Multiply final +class BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("See comments") Blinded_Point_Multiply final { public: - Blinded_Point_Multiply(const PointGFp& base, const BigInt& order, size_t h = 0) : - m_ws(PointGFp::WORKSPACE_SIZE), m_order(order), m_point_mul(base, m_ws, h) {} + Blinded_Point_Multiply(const PointGFp& base, const BigInt& order, size_t h = 0); - PointGFp blinded_multiply(const BigInt& scalar, RandomNumberGenerator& rng) - { - m_point_mul.randomize(rng); - return m_point_mul.mul(scalar, m_order, rng, m_ws); - } + PointGFp blinded_multiply(const BigInt& scalar, RandomNumberGenerator& rng); private: std::vector<BigInt> m_ws; const BigInt& m_order; - PointGFp_Blinded_Multiplier m_point_mul; + std::unique_ptr<PointGFp_Var_Point_Precompute> m_point_mul; }; } diff --git a/src/lib/pubkey/ec_group/point_mul.cpp b/src/lib/pubkey/ec_group/point_mul.cpp index 314807166..556a05eb0 100644 --- a/src/lib/pubkey/ec_group/point_mul.cpp +++ b/src/lib/pubkey/ec_group/point_mul.cpp @@ -4,86 +4,137 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/point_gfp.h> +#include <botan/internal/point_mul.h> #include <botan/rng.h> #include <botan/internal/rounding.h> namespace Botan { -PointGFp_Blinded_Multiplier::PointGFp_Blinded_Multiplier(const PointGFp& base, - std::vector<BigInt>& ws, - size_t w) +Blinded_Point_Multiply::Blinded_Point_Multiply(const PointGFp& base, + const BigInt& order, + size_t h) : + m_ws(PointGFp::WORKSPACE_SIZE), + m_order(order) { - init(base, w, ws); + BOTAN_UNUSED(h); + m_point_mul.reset(new PointGFp_Var_Point_Precompute(base)); } -PointGFp_Blinded_Multiplier::PointGFp_Blinded_Multiplier(const PointGFp& base, - size_t w) +PointGFp Blinded_Point_Multiply::blinded_multiply(const BigInt& scalar, + RandomNumberGenerator& rng) + { + return m_point_mul->mul(scalar, rng, m_order, m_ws); + } + + +PointGFp_Base_Point_Precompute::PointGFp_Base_Point_Precompute(const PointGFp& base) { std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); - init(base, w, ws); + + const size_t p_bits = base.get_curve().get_p().bits(); + + /* + * Some of the curves (eg secp160k1) have an order slightly larger than + * the size of the prime modulus. In all cases they are at most 1 bit + * longer. The +1 compensates for this. + */ + const size_t T_bits = p_bits + PointGFp_SCALAR_BLINDING_BITS + 1; + + m_T.push_back(base); + + for(size_t i = 1; i != T_bits; ++i) + { + m_T.push_back(m_T[i-1]); + m_T[i].mult2(ws); + } + + for(size_t i = 0; i != m_T.size(); ++i) + m_T[i].force_affine(); } -void PointGFp_Blinded_Multiplier::init(const PointGFp& base, - size_t w, - std::vector<BigInt>& ws) +PointGFp PointGFp_Base_Point_Precompute::mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const { - m_h = (w == 0 ? 5 : w); + if(k.is_negative()) + throw Invalid_Argument("PointGFp_Base_Point_Precompute scalar must be positive"); + + // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) + const BigInt mask(rng, PointGFp_SCALAR_BLINDING_BITS, false); + const BigInt scalar = k + group_order * mask; + + const size_t scalar_bits = scalar.bits(); + + BOTAN_ASSERT(scalar_bits <= m_T.size(), + "Precomputed sufficient values for scalar mult"); + + PointGFp R = m_T[0].zero(); if(ws.size() < PointGFp::WORKSPACE_SIZE) ws.resize(PointGFp::WORKSPACE_SIZE); - // Upper bound is a sanity check rather than hard limit - if(m_h < 1 || m_h > 8) - throw Invalid_Argument("PointGFp_Blinded_Multiplier invalid w param"); + for(size_t i = 0; i != scalar_bits; ++i) + { + //if(i % 4 == 3) + if(i == 4) + { + R.randomize_repr(rng); + } + + if(scalar.get_bit(i)) + R.add(m_T[i], ws); + } + + return R; + } + +PointGFp_Var_Point_Precompute::PointGFp_Var_Point_Precompute(const PointGFp& point) + { + m_window_bits = 4; - m_U.resize(1 << m_h); - m_U[0] = base.zero(); - m_U[1] = base; + m_U.resize(1U << m_window_bits); + m_U[0] = point.zero(); + m_U[1] = point; + std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); for(size_t i = 2; i < m_U.size(); ++i) { m_U[i] = m_U[i-1]; - m_U[i].add(base, ws); + m_U[i].add(point, ws); } } -void PointGFp_Blinded_Multiplier::randomize(RandomNumberGenerator& rng) +void PointGFp_Var_Point_Precompute::randomize_repr(RandomNumberGenerator& rng) { - // Randomize each point representation (Coron's 3rd countermeasure) - for(size_t i = 0; i != m_U.size(); ++i) + for(size_t i = 1; i != m_U.size(); ++i) m_U[i].randomize_repr(rng); } -PointGFp PointGFp_Blinded_Multiplier::mul(const BigInt& k, - const BigInt& group_order, - RandomNumberGenerator& rng, - std::vector<BigInt>& ws) const +PointGFp PointGFp_Var_Point_Precompute::mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const { if(k.is_negative()) - throw Invalid_Argument("PointGFp_Blinded_Multiplier scalar must be positive"); + throw Invalid_Argument("PointGFp_Base_Point_Precompute scalar must be positive"); + if(ws.size() < PointGFp::WORKSPACE_SIZE) + ws.resize(PointGFp::WORKSPACE_SIZE); -#if BOTAN_POINTGFP_USE_SCALAR_BLINDING // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) - const BigInt mask(rng, group_order.bits() / 4, false); + const BigInt mask(rng, PointGFp_SCALAR_BLINDING_BITS, false); const BigInt scalar = k + group_order * mask; -#else - const BigInt& scalar = k; -#endif - - if(ws.size() < PointGFp::WORKSPACE_SIZE) - ws.resize(PointGFp::WORKSPACE_SIZE); const size_t scalar_bits = scalar.bits(); - size_t windows = round_up(scalar_bits, m_h) / m_h; + size_t windows = round_up(scalar_bits, m_window_bits) / m_window_bits; PointGFp R = m_U[0]; if(windows > 0) { windows--; - const uint32_t nibble = scalar.get_substring(windows*m_h, m_h); + const uint32_t nibble = scalar.get_substring(windows*m_window_bits, m_window_bits); R.add(m_U[nibble], ws); /* @@ -95,18 +146,16 @@ PointGFp PointGFp_Blinded_Multiplier::mul(const BigInt& k, while(windows) { - for(size_t i = 0; i != m_h; ++i) + for(size_t i = 0; i != m_window_bits; ++i) R.mult2(ws); - const uint32_t inner_nibble = scalar.get_substring((windows-1)*m_h, m_h); + const uint32_t inner_nibble = scalar.get_substring((windows-1)*m_window_bits, m_window_bits); // cache side channel here, we are relying on blinding... R.add(m_U[inner_nibble], ws); windows--; } } - //BOTAN_ASSERT(R.on_the_curve(), "Output is on the curve"); - return R; } diff --git a/src/lib/pubkey/ec_group/point_mul.h b/src/lib/pubkey/ec_group/point_mul.h new file mode 100644 index 000000000..97fd326a2 --- /dev/null +++ b/src/lib/pubkey/ec_group/point_mul.h @@ -0,0 +1,47 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POINT_MUL_H_ +#define BOTAN_POINT_MUL_H_ + +#include <botan/point_gfp.h> + +namespace Botan { + +static const size_t PointGFp_SCALAR_BLINDING_BITS = 80; + +class PointGFp_Base_Point_Precompute + { + public: + PointGFp_Base_Point_Precompute(const PointGFp& base_point); + + PointGFp mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const; + private: + std::vector<PointGFp> m_T; + }; + +class PointGFp_Var_Point_Precompute + { + public: + PointGFp_Var_Point_Precompute(const PointGFp& point); + + void randomize_repr(RandomNumberGenerator& rng); + + PointGFp mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const; + private: + size_t m_window_bits; + std::vector<PointGFp> m_U; + }; + +} + +#endif diff --git a/src/lib/pubkey/ecdh/ecdh.cpp b/src/lib/pubkey/ecdh/ecdh.cpp index 4989fa0a5..adadb2703 100644 --- a/src/lib/pubkey/ecdh/ecdh.cpp +++ b/src/lib/pubkey/ecdh/ecdh.cpp @@ -39,9 +39,8 @@ class ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF PointGFp input_point = m_group.get_cofactor() * m_group.OS2ECP(w, w_len); input_point.randomize_repr(m_rng); - PointGFp_Blinded_Multiplier blinder(input_point, m_ws); - - const PointGFp S = blinder.mul(m_l_times_priv, m_group.get_order(), m_rng, m_ws); + const PointGFp S = m_group.blinded_var_point_multiply( + input_point, m_l_times_priv, m_rng, m_ws); if(S.on_the_curve() == false) throw Internal_Error("ECDH agreed value was not on the curve"); diff --git a/src/lib/pubkey/ecies/ecies.cpp b/src/lib/pubkey/ecies/ecies.cpp index 1120a850a..06d5cfeee 100644 --- a/src/lib/pubkey/ecies/ecies.cpp +++ b/src/lib/pubkey/ecies/ecies.cpp @@ -71,9 +71,8 @@ class ECIES_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF PointGFp input_point = group.OS2ECP(w, w_len); input_point.randomize_repr(m_rng); - PointGFp_Blinded_Multiplier blinder(input_point, m_ws); - - const PointGFp S = blinder.mul(m_key.private_value(), group.get_order(), m_rng, m_ws); + const PointGFp S = group.blinded_var_point_multiply( + input_point, m_key.private_value(), m_rng, m_ws); if(S.on_the_curve() == false) throw Internal_Error("ECDH agreed value was not on the curve"); diff --git a/src/lib/pubkey/sm2/sm2_enc.cpp b/src/lib/pubkey/sm2/sm2_enc.cpp index b0d773635..4a6aa2b6e 100644 --- a/src/lib/pubkey/sm2/sm2_enc.cpp +++ b/src/lib/pubkey/sm2/sm2_enc.cpp @@ -6,6 +6,7 @@ */ #include <botan/sm2_enc.h> +#include <botan/internal/point_mul.h> #include <botan/pk_ops.h> #include <botan/keypair.h> #include <botan/der_enc.h> @@ -76,7 +77,7 @@ class SM2_Encryption_Operation final : public PK_Ops::Encryption BigInt::encode_1363(x1_bytes.data(), x1_bytes.size(), x1); BigInt::encode_1363(y1_bytes.data(), y1_bytes.size(), y1); - const PointGFp kPB = m_mul_public_point.mul(k, m_group.get_order(), rng, m_ws); + const PointGFp kPB = m_mul_public_point.mul(k, rng, m_group.get_order(), m_ws); const BigInt x2 = kPB.get_affine_x(); const BigInt y2 = kPB.get_affine_y(); @@ -113,7 +114,7 @@ class SM2_Encryption_Operation final : public PK_Ops::Encryption private: const EC_Group m_group; - PointGFp_Blinded_Multiplier m_mul_public_point; + PointGFp_Var_Point_Precompute m_mul_public_point; const std::string m_kdf_hash; std::vector<BigInt> m_ws; }; @@ -161,6 +162,8 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption .verify_end(); PointGFp C1 = group.point(x1, y1); + C1.randomize_repr(m_rng); + if(!C1.on_the_curve()) return secure_vector<uint8_t>(); @@ -169,11 +172,8 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption return secure_vector<uint8_t>(); } - C1.randomize_repr(m_rng); - - PointGFp_Blinded_Multiplier C1_mul(C1); - - const PointGFp dbC1 = C1_mul.mul(m_key.private_value(), group.get_order(), m_rng, m_ws); + const PointGFp dbC1 = group.blinded_var_point_multiply( + C1, m_key.private_value(), m_rng, m_ws); const BigInt x2 = dbC1.get_affine_x(); const BigInt y2 = dbC1.get_affine_y(); |