aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/math
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-02-25 13:24:25 -0500
committerJack Lloyd <[email protected]>2018-02-25 18:07:36 -0500
commit68e5aa78138e9e2de84aab58e1cdf0e7084fda87 (patch)
tree10b2308fd62eac2cfdd9d89af04470f7ac143324 /src/lib/math
parent8c3ce8fba6802b821ce1307e3ca10b06d82a04ce (diff)
Add Montgomery_Int type
Diffstat (limited to 'src/lib/math')
-rw-r--r--src/lib/math/numbertheory/def_powm.h5
-rw-r--r--src/lib/math/numbertheory/info.txt1
-rw-r--r--src/lib/math/numbertheory/monty.cpp254
-rw-r--r--src/lib/math/numbertheory/monty.h134
-rw-r--r--src/lib/math/numbertheory/monty_exp.cpp137
-rw-r--r--src/lib/math/numbertheory/monty_exp.h7
-rw-r--r--src/lib/math/numbertheory/powm_mnt.cpp5
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)
{
}