diff options
author | Jack Lloyd <[email protected]> | 2018-02-25 13:24:25 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-02-25 18:07:36 -0500 |
commit | 68e5aa78138e9e2de84aab58e1cdf0e7084fda87 (patch) | |
tree | 10b2308fd62eac2cfdd9d89af04470f7ac143324 /src/lib/math | |
parent | 8c3ce8fba6802b821ce1307e3ca10b06d82a04ce (diff) |
Add Montgomery_Int type
Diffstat (limited to 'src/lib/math')
-rw-r--r-- | src/lib/math/numbertheory/def_powm.h | 5 | ||||
-rw-r--r-- | src/lib/math/numbertheory/info.txt | 1 | ||||
-rw-r--r-- | src/lib/math/numbertheory/monty.cpp | 254 | ||||
-rw-r--r-- | src/lib/math/numbertheory/monty.h | 134 | ||||
-rw-r--r-- | src/lib/math/numbertheory/monty_exp.cpp | 137 | ||||
-rw-r--r-- | src/lib/math/numbertheory/monty_exp.h | 7 | ||||
-rw-r--r-- | src/lib/math/numbertheory/powm_mnt.cpp | 5 |
7 files changed, 456 insertions, 87 deletions
diff --git a/src/lib/math/numbertheory/def_powm.h b/src/lib/math/numbertheory/def_powm.h index fe705bf96..6b1f33835 100644 --- a/src/lib/math/numbertheory/def_powm.h +++ b/src/lib/math/numbertheory/def_powm.h @@ -36,6 +36,7 @@ class Fixed_Window_Exponentiator final : public Modular_Exponentiator Power_Mod::Usage_Hints m_hints; }; +class Montgomery_Params; class Montgomery_Exponentation_State; /** @@ -53,9 +54,11 @@ class Montgomery_Exponentiator final : public Modular_Exponentiator Montgomery_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); private: - std::shared_ptr<const Montgomery_Exponentation_State> m_monty; BigInt m_p; Modular_Reducer m_mod_p; + std::shared_ptr<const Montgomery_Params> m_monty_params; + std::shared_ptr<const Montgomery_Exponentation_State> m_monty; + BigInt m_e; Power_Mod::Usage_Hints m_hints; }; diff --git a/src/lib/math/numbertheory/info.txt b/src/lib/math/numbertheory/info.txt index 01adb7345..eb348b7ef 100644 --- a/src/lib/math/numbertheory/info.txt +++ b/src/lib/math/numbertheory/info.txt @@ -8,6 +8,7 @@ load_on auto numthry.h pow_mod.h reducer.h +monty.h </header:public> <header:internal> diff --git a/src/lib/math/numbertheory/monty.cpp b/src/lib/math/numbertheory/monty.cpp new file mode 100644 index 000000000..64646a61a --- /dev/null +++ b/src/lib/math/numbertheory/monty.cpp @@ -0,0 +1,254 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/monty.h> +#include <botan/reducer.h> +#include <botan/internal/mp_core.h> + +namespace Botan { + +Montgomery_Params::Montgomery_Params(const BigInt& p, + const Modular_Reducer& mod_p) + { + if(p.is_negative() || p.is_even()) + throw Invalid_Argument("Montgomery_Params invalid modulus"); + + m_p = p; + 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); + + m_r1 = mod_p.reduce(r); + m_r2 = mod_p.square(m_r1); + m_r3 = mod_p.multiply(m_r1, m_r2); + } + +BigInt Montgomery_Params::inv_mod_p(const BigInt& x) const + { + return ct_inverse_mod_odd_modulus(x, p()); + } + +BigInt Montgomery_Params::redc(const BigInt& x) const + { + const size_t output_size = 2*m_p_words + 2; + std::vector<word> ws(output_size); + BigInt z = x; + z.grow_to(output_size); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + secure_scrub_memory(ws.data(), ws.size() * sizeof(word)); + return z; + } + +BigInt Montgomery_Params::mul(const BigInt& x, const BigInt& y) const + { + const size_t output_size = 2*m_p_words + 2; + std::vector<word> ws(output_size); + BigInt z(BigInt::Positive, output_size); + bigint_monty_mul(z, x, y, + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + secure_scrub_memory(ws.data(), ws.size() * sizeof(word)); + return z; + } + +BigInt Montgomery_Params::mul(const BigInt& x, const secure_vector<word>& y) const + { + const size_t output_size = 2*m_p_words + 2; + std::vector<word> ws(output_size); + BigInt z(BigInt::Positive, output_size); + + bigint_mul(z.mutable_data(), z.size(), + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), 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()); + + secure_scrub_memory(ws.data(), ws.size() * sizeof(word)); + return z; + } + +BigInt Montgomery_Params::sqr(const BigInt& x) const + { + const size_t output_size = 2*m_p_words + 2; + std::vector<word> ws(output_size); + BigInt z(BigInt::Positive, output_size); + + bigint_sqr(z.mutable_data(), z.size(), + x.data(), x.size(), x.sig_words(), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + secure_scrub_memory(ws.data(), ws.size() * sizeof(word)); + return z; + } + +Montgomery_Int::Montgomery_Int(const std::shared_ptr<const Montgomery_Params> params, + const BigInt& v, + bool redc_needed) : + m_params(params), + m_v(redc_needed ? m_params->mul(v % m_params->p(), m_params->R2()) : v) + {} + +void Montgomery_Int::fix_size() + { + const size_t p_words = m_params->p_words(); + + if(m_v.sig_words() > p_words) + throw Internal_Error("Montgomery_Int::fix_size v too large"); + + secure_vector<word>& w = m_v.get_word_vector(); + + if(w.size() != p_words) + { + w.resize(p_words); + w.shrink_to_fit(); + } + } + +bool Montgomery_Int::operator==(const Montgomery_Int& other) const + { + return m_v == other.m_v && m_params->p() == other.m_params->p(); + } + +std::vector<uint8_t> Montgomery_Int::serialize() const + { + std::vector<uint8_t> v(size()); + BigInt::encode_1363(v.data(), v.size(), value()); + return v; + } + +size_t Montgomery_Int::size() const + { + return m_params->p().bytes(); + } + +bool Montgomery_Int::is_one() const + { + return m_v == m_params->R1(); + } + +bool Montgomery_Int::is_zero() const + { + return m_v.is_zero(); + } + +BigInt Montgomery_Int::value() const + { + return m_params->redc(m_v); + } + +Montgomery_Int Montgomery_Int::operator+(const Montgomery_Int& other) const + { + BigInt z = m_v + other.m_v; + secure_vector<word> ws; + z.reduce_below(m_params->p(), ws); + return Montgomery_Int(m_params, z, false); + } + +Montgomery_Int Montgomery_Int::operator-(const Montgomery_Int& other) const + { + BigInt z = m_v - other.m_v; + if(z.is_negative()) + z += m_params->p(); + return Montgomery_Int(m_params, z, false); + } + +Montgomery_Int& Montgomery_Int::operator+=(const Montgomery_Int& other) + { + m_v += other.m_v; + secure_vector<word> ws; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::operator-=(const Montgomery_Int& other) + { + m_v -= other.m_v; + if(m_v.is_negative()) + m_v += m_params->p(); + return (*this); + } + +Montgomery_Int Montgomery_Int::operator*(const Montgomery_Int& other) const + { + return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v), false); + } + +Montgomery_Int& Montgomery_Int::operator*=(const Montgomery_Int& other) + { + m_v = m_params->mul(m_v, other.m_v); + return (*this); + } + +Montgomery_Int& Montgomery_Int::operator*=(const secure_vector<word>& other) + { + m_v = m_params->mul(m_v, other); + return (*this); + } + +Montgomery_Int& Montgomery_Int::square_this() + { + m_v = m_params->sqr(m_v); + return (*this); + } + +Montgomery_Int Montgomery_Int::square() const + { + const BigInt v = m_params->sqr(m_v); + return Montgomery_Int(m_params, v, false); + } + +Montgomery_Int Montgomery_Int::multiplicative_inverse() const + { + const BigInt iv = m_params->mul(m_params->inv_mod_p(m_v), m_params->R3()); + return Montgomery_Int(m_params, iv, false); + } + +Montgomery_Int Montgomery_Int::additive_inverse() const + { + return Montgomery_Int(m_params, m_params->p()) - (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_2(secure_vector<word>& ws) + { + m_v <<= 1; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_3(secure_vector<word>& ws) + { + m_v *= 3; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_4(secure_vector<word>& ws) + { + m_v <<= 2; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_8(secure_vector<word>& ws) + { + m_v <<= 3; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +} diff --git a/src/lib/math/numbertheory/monty.h b/src/lib/math/numbertheory/monty.h new file mode 100644 index 000000000..ea08789e1 --- /dev/null +++ b/src/lib/math/numbertheory/monty.h @@ -0,0 +1,134 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MONTY_INT_H_ +#define BOTAN_MONTY_INT_H_ + +#include <botan/bigint.h> + +namespace Botan { + +class Modular_Reducer; + +class Montgomery_Params; + +/** +* The Montgomery representation of an integer +*/ +class Montgomery_Int final + { + public: + /** + * Create a zero-initialized Montgomery_Int + */ + Montgomery_Int(std::shared_ptr<const Montgomery_Params> params) : m_params(params) {} + + /** + * Create a Montgomery_Int + */ + Montgomery_Int(std::shared_ptr<const Montgomery_Params> params, + const BigInt& v, + bool redc_needed = true); + + bool operator==(const Montgomery_Int& other) const; + bool operator!=(const Montgomery_Int& other) const { return (m_v != other.m_v); } + + std::vector<uint8_t> serialize() const; + + size_t size() const; + bool is_one() const; + bool is_zero() const; + + void fix_size(); + + /** + * Return the value to normal mod-p space + */ + BigInt value() const; + + /** + * Return the Montgomery representation + */ + const BigInt& repr() const { return m_v; } + + Montgomery_Int operator+(const Montgomery_Int& other) const; + + Montgomery_Int operator-(const Montgomery_Int& other) const; + + Montgomery_Int& operator+=(const Montgomery_Int& other); + + Montgomery_Int& operator-=(const Montgomery_Int& other); + + Montgomery_Int operator*(const Montgomery_Int& other) const; + + Montgomery_Int& operator*=(const Montgomery_Int& other); + + Montgomery_Int& operator*=(const secure_vector<word>& other); + + Montgomery_Int square() const; + + Montgomery_Int& square_this(); + + Montgomery_Int multiplicative_inverse() const; + + Montgomery_Int additive_inverse() const; + + Montgomery_Int& mul_by_2(secure_vector<word>& ws); + + Montgomery_Int& mul_by_3(secure_vector<word>& ws); + + Montgomery_Int& mul_by_4(secure_vector<word>& ws); + + Montgomery_Int& mul_by_8(secure_vector<word>& ws); + + private: + std::shared_ptr<const Montgomery_Params> m_params; + BigInt m_v; + }; + +/** +* Parameters for Montgomery Reduction +*/ +class Montgomery_Params final + { + public: + /** + * Initialize a set of Montgomery reduction parameters. These values + * can be shared by all values in a specific Montgomery domain. + */ + Montgomery_Params(const BigInt& p, const Modular_Reducer& mod_p); + + const BigInt& p() const { return m_p; } + const BigInt& R1() const { return m_r1; } + const BigInt& R2() const { return m_r2; } + const BigInt& R3() const { return m_r3; } + + word p_dash() const { return m_p_dash; } + + size_t p_words() const { return m_p_words; } + + BigInt redc(const BigInt& x) const; + + BigInt mul(const BigInt& x, const BigInt& y) const; + + BigInt mul(const BigInt& x, const secure_vector<word>& y) const; + + BigInt sqr(const BigInt& x) const; + + BigInt inv_mod_p(const BigInt& x) const; + + private: + BigInt m_p; + BigInt m_r1; + BigInt m_r2; + BigInt m_r3; + word m_p_dash; + size_t m_p_words; + }; + +} + +#endif diff --git a/src/lib/math/numbertheory/monty_exp.cpp b/src/lib/math/numbertheory/monty_exp.cpp index bfb17a87c..6b7af3b09 100644 --- a/src/lib/math/numbertheory/monty_exp.cpp +++ b/src/lib/math/numbertheory/monty_exp.cpp @@ -7,140 +7,115 @@ */ #include <botan/internal/monty_exp.h> +#include <botan/internal/ct_utils.h> #include <botan/numthry.h> #include <botan/reducer.h> -#include <botan/internal/mp_core.h> +#include <botan/monty.h> namespace Botan { class Montgomery_Exponentation_State { public: - Montgomery_Exponentation_State(const BigInt& g, - const BigInt& p, - const Modular_Reducer& mod_p, + Montgomery_Exponentation_State(std::shared_ptr<const Montgomery_Params> params, + const BigInt& g, size_t window_bits); BigInt exponentiation(const BigInt& k) const; private: - BigInt m_p; - BigInt m_R_mod; - BigInt m_R2_mod; - word m_mod_prime; - size_t m_p_words; + std::shared_ptr<const Montgomery_Params> m_params; + std::vector<Montgomery_Int> m_g; size_t m_window_bits; - std::vector<BigInt> m_g; }; -Montgomery_Exponentation_State::Montgomery_Exponentation_State(const BigInt& g, - const BigInt& p, - const Modular_Reducer& mod_p, +Montgomery_Exponentation_State::Montgomery_Exponentation_State(std::shared_ptr<const Montgomery_Params> params, + const BigInt& g, size_t window_bits) : - m_p(p), - m_p_words(p.sig_words()), - m_window_bits(window_bits) + m_params(params), + m_window_bits(window_bits == 0 ? 4 : window_bits) { - if(p.is_positive() == false || p.is_even()) - throw Invalid_Argument("Cannot use Montgomery reduction on even or negative integer"); + if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ... + throw Invalid_Argument("Invalid window bits for Montgomery exponentiation"); - if(window_bits > 12) // really even 8 is too large ... - throw Invalid_Argument("Montgomery window bits too large"); + const size_t window_size = (1U << m_window_bits); - m_mod_prime = monty_inverse(m_p.word_at(0)); + m_g.reserve(window_size); - const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); - m_R_mod = mod_p.reduce(r); - m_R2_mod = mod_p.square(m_R_mod); + m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false));; - m_g.resize(1U << m_window_bits); + m_g.push_back(Montgomery_Int(m_params, g)); - BigInt z(BigInt::Positive, 2 * (m_p_words + 1)); - secure_vector<word> workspace(z.size()); + const Montgomery_Int& monty_g = m_g[1]; - m_g[0] = 1; - - bigint_monty_mul(z, m_g[0], m_R2_mod, - m_p.data(), m_p_words, m_mod_prime, - workspace.data(), workspace.size()); - m_g[0] = z; + for(size_t i = 2; i != window_size; ++i) + { + m_g.push_back(monty_g * m_g[i - 1]); + } - m_g[1] = mod_p.reduce(g); + // Resize each element to exactly p words + for(size_t i = 0; i != window_size; ++i) + { + m_g[i].fix_size(); + } + } - bigint_monty_mul(z, m_g[1], m_R2_mod, - m_p.data(), m_p_words, m_mod_prime, - workspace.data(), workspace.size()); +namespace { - m_g[1] = z; +void const_time_lookup(secure_vector<word>& output, + const std::vector<Montgomery_Int>& g, + size_t nibble) + { + const size_t words = output.size(); - const BigInt& x = m_g[1]; + clear_mem(output.data(), output.size()); - for(size_t i = 2; i != m_g.size(); ++i) + for(size_t i = 0; i != g.size(); ++i) { - const BigInt& y = m_g[i-1]; + const secure_vector<word>& vec = g[i].repr().get_word_vector(); + + BOTAN_ASSERT(vec.size() >= words, + "Word size as expected in const_time_lookup"); - bigint_monty_mul(z, x, y, m_p.data(), m_p_words, m_mod_prime, - workspace.data(), workspace.size()); + const word mask = CT::is_equal<word>(i, nibble); - m_g[i] = z; - m_g[i].shrink_to_fit(); - m_g[i].grow_to(m_p_words); + for(size_t w = 0; w != words; ++w) + output[w] |= (mask & vec[w]); } } -BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& k) const - { - const size_t exp_nibbles = (k.bits() + m_window_bits - 1) / m_window_bits; +} - BigInt x = m_R_mod; +BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar) const + { + const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits; - const size_t z_size = 2*(m_p_words + 1); + Montgomery_Int x(m_params, m_params->R1(), false); - BigInt z(BigInt::Positive, z_size); - secure_vector<word> workspace(z.size()); - secure_vector<word> e(m_p_words); + secure_vector<word> e_bits(m_params->p_words()); for(size_t i = exp_nibbles; i > 0; --i) { for(size_t j = 0; j != m_window_bits; ++j) { - bigint_monty_sqr(z, x, m_p.data(), m_p_words, m_mod_prime, - workspace.data(), workspace.size()); - - x = z; + x.square_this(); } - const uint32_t nibble = k.get_substring(m_window_bits*(i-1), m_window_bits); + const uint32_t nibble = scalar.get_substring(m_window_bits*(i-1), m_window_bits); - BigInt::const_time_lookup(e, m_g, nibble); + const_time_lookup(e_bits, m_g, nibble); - bigint_mul(z.mutable_data(), z.size(), - x.data(), x.size(), x.sig_words(), - e.data(), m_p_words, m_p_words, - workspace.data(), workspace.size()); - - bigint_monty_redc(z.mutable_data(), - m_p.data(), m_p_words, m_mod_prime, - workspace.data(), workspace.size()); - - x = z; + x *= e_bits; } - x.grow_to(2*m_p_words + 1); - - bigint_monty_redc(x.mutable_data(), - m_p.data(), m_p_words, m_mod_prime, - workspace.data(), workspace.size()); - - return x; + return x.value(); } std::shared_ptr<const Montgomery_Exponentation_State> -monty_precompute(const BigInt& g, - const BigInt& p, - const Modular_Reducer& mod_p, +monty_precompute(std::shared_ptr<const Montgomery_Params> params, + const BigInt& g, size_t window_bits) { - return std::make_shared<const Montgomery_Exponentation_State>(g, p, mod_p, window_bits); + return std::make_shared<const Montgomery_Exponentation_State>(params, g, window_bits); } BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, diff --git a/src/lib/math/numbertheory/monty_exp.h b/src/lib/math/numbertheory/monty_exp.h index 65fc9ce4b..8c644d221 100644 --- a/src/lib/math/numbertheory/monty_exp.h +++ b/src/lib/math/numbertheory/monty_exp.h @@ -14,15 +14,16 @@ namespace Botan { class BigInt; class Modular_Reducer; +class Montgomery_Params; + class Montgomery_Exponentation_State; /* * Precompute for calculating values g^x mod p */ std::shared_ptr<const Montgomery_Exponentation_State> -monty_precompute(const BigInt& g, - const BigInt& p, - const Modular_Reducer& mod_p, +monty_precompute(std::shared_ptr<const Montgomery_Params> params_p, + const BigInt& g, size_t window_bits); /* diff --git a/src/lib/math/numbertheory/powm_mnt.cpp b/src/lib/math/numbertheory/powm_mnt.cpp index 81102188b..5da91796f 100644 --- a/src/lib/math/numbertheory/powm_mnt.cpp +++ b/src/lib/math/numbertheory/powm_mnt.cpp @@ -8,7 +8,7 @@ #include <botan/internal/def_powm.h> #include <botan/numthry.h> -#include <botan/internal/mp_core.h> +#include <botan/monty.h> #include <botan/internal/monty_exp.h> namespace Botan { @@ -21,7 +21,7 @@ void Montgomery_Exponentiator::set_exponent(const BigInt& exp) void Montgomery_Exponentiator::set_base(const BigInt& base) { size_t window_bits = Power_Mod::window_bits(m_e.bits(), base.bits(), m_hints); - m_monty = monty_precompute(base, m_p, m_mod_p, window_bits); + m_monty = monty_precompute(m_monty_params, base, window_bits); } BigInt Montgomery_Exponentiator::execute() const @@ -33,6 +33,7 @@ Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, Power_Mod::Usage_Hints hints) : m_p(mod), m_mod_p(mod), + m_monty_params(std::make_shared<Montgomery_Params>(m_p, m_mod_p)), m_hints(hints) { } |