Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify Montgomery exponentiation to return results in Montgomery form #4558

Merged
merged 1 commit into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/deprecated.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ release, or where a backwards incompatible change is expected.
- All support for loading, generating or using RSA keys with a public
exponent larger than 2**64-1

- Currently RSA_PrivateKey will allow generating any key of bitlength
greater than or equal to 1024 bits. In a future major release the
allowed bitlengths of new RSA keys will be restricted to 2048 bits
or higher, and the bitlength must be a multiple of 1024 bits.

- Currently some public key padding mechanisms can be used with several
different names. This is deprecated.
"EMSA_PKCS1", "EMSA-PKCS1-v1_5", "EMSA3": Use "PKCS1v15"
Expand Down
28 changes: 23 additions & 5 deletions src/lib/math/numbertheory/monty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,18 @@ void Montgomery_Params::square_this(BigInt& x, secure_vector<word>& ws) const {
copy_mem(x.mutable_data(), z_data, output_size);
}

Montgomery_Int Montgomery_Int::one(const std::shared_ptr<const Montgomery_Params>& params) {
return Montgomery_Int(params, params->R1(), false);
}

Montgomery_Int Montgomery_Int::from_wide_int(const std::shared_ptr<const Montgomery_Params>& params, const BigInt& x) {
//BOTAN_ARG_CHECK(x < params->p() * params->p(), "Input too large");

secure_vector<word> ws;
auto redc_x = params->mul(params->redc(x, ws), params->R3(), ws);
return Montgomery_Int(params, redc_x, false);
}

Montgomery_Int::Montgomery_Int(const std::shared_ptr<const Montgomery_Params>& params,
const BigInt& v,
bool redc_needed) :
Expand Down Expand Up @@ -301,11 +313,7 @@ Montgomery_Int::Montgomery_Int(std::shared_ptr<const Montgomery_Params> params,

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");
}

BOTAN_DEBUG_ASSERT(m_v.sig_words() <= p_words);
m_v.grow_to(p_words);
}

Expand Down Expand Up @@ -335,49 +343,58 @@ BigInt Montgomery_Int::value() const {
}

Montgomery_Int Montgomery_Int::operator+(const Montgomery_Int& other) const {
BOTAN_STATE_CHECK(other.m_params == m_params);
secure_vector<word> ws;
BigInt z = m_v;
z.mod_add(other.m_v, m_params->p(), ws);
return Montgomery_Int(m_params, z, false);
}

Montgomery_Int Montgomery_Int::operator-(const Montgomery_Int& other) const {
BOTAN_STATE_CHECK(other.m_params == m_params);
secure_vector<word> ws;
BigInt z = m_v;
z.mod_sub(other.m_v, m_params->p(), ws);
return Montgomery_Int(m_params, z, false);
}

Montgomery_Int& Montgomery_Int::operator+=(const Montgomery_Int& other) {
BOTAN_STATE_CHECK(other.m_params == m_params);
secure_vector<word> ws;
return this->add(other, ws);
}

Montgomery_Int& Montgomery_Int::add(const Montgomery_Int& other, secure_vector<word>& ws) {
BOTAN_STATE_CHECK(other.m_params == m_params);
m_v.mod_add(other.m_v, m_params->p(), ws);
return (*this);
}

Montgomery_Int& Montgomery_Int::operator-=(const Montgomery_Int& other) {
BOTAN_STATE_CHECK(other.m_params == m_params);
secure_vector<word> ws;
return this->sub(other, ws);
}

Montgomery_Int& Montgomery_Int::sub(const Montgomery_Int& other, secure_vector<word>& ws) {
BOTAN_STATE_CHECK(other.m_params == m_params);
m_v.mod_sub(other.m_v, m_params->p(), ws);
return (*this);
}

Montgomery_Int Montgomery_Int::operator*(const Montgomery_Int& other) const {
BOTAN_STATE_CHECK(other.m_params == m_params);
secure_vector<word> ws;
return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false);
}

Montgomery_Int Montgomery_Int::mul(const Montgomery_Int& other, secure_vector<word>& ws) const {
BOTAN_STATE_CHECK(other.m_params == m_params);
return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false);
}

Montgomery_Int& Montgomery_Int::mul_by(const Montgomery_Int& other, secure_vector<word>& ws) {
BOTAN_STATE_CHECK(other.m_params == m_params);
m_params->mul_by(m_v, other.m_v, ws);
return (*this);
}
Expand All @@ -388,6 +405,7 @@ Montgomery_Int& Montgomery_Int::mul_by(const secure_vector<word>& other, secure_
}

Montgomery_Int& Montgomery_Int::operator*=(const Montgomery_Int& other) {
BOTAN_STATE_CHECK(other.m_params == m_params);
secure_vector<word> ws;
return mul_by(other, ws);
}
Expand Down
9 changes: 9 additions & 0 deletions src/lib/math/numbertheory/monty.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ class BOTAN_TEST_API Montgomery_Int final {
size_t len,
bool redc_needed = true);

static Montgomery_Int one(const std::shared_ptr<const Montgomery_Params>& params);

/**
* Wide reduction - input can be at most 2*bytes long
*/
static Montgomery_Int from_wide_int(const std::shared_ptr<const Montgomery_Params>& params, const BigInt& x);

bool operator==(const Montgomery_Int& other) const;

bool operator!=(const Montgomery_Int& other) const { return (m_v != other.m_v); }
Expand Down Expand Up @@ -118,6 +125,8 @@ class BOTAN_TEST_API Montgomery_Int final {

void _const_time_unpoison() const { CT::unpoison(m_v); }

const std::shared_ptr<const Montgomery_Params>& _params() const { return m_params; }

private:
std::shared_ptr<const Montgomery_Params> m_params;
BigInt m_v;
Expand Down
66 changes: 35 additions & 31 deletions src/lib/math/numbertheory/monty_exp.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Montgomery Exponentiation
* (C) 1999-2010,2012,2018 Jack Lloyd
* (C) 1999-2010,2012,2018,2025 Jack Lloyd
* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
Expand All @@ -18,28 +18,22 @@ namespace Botan {

class Montgomery_Exponentation_State final {
public:
Montgomery_Exponentation_State(const std::shared_ptr<const Montgomery_Params>& params,
const BigInt& g,
size_t window_bits,
bool const_time);
Montgomery_Exponentation_State(const Montgomery_Int& g, size_t window_bits, bool const_time);

BigInt exponentiation(const BigInt& k, size_t max_k_bits) const;
Montgomery_Int exponentiation(const BigInt& k, size_t max_k_bits) const;

BigInt exponentiation_vartime(const BigInt& k) const;
Montgomery_Int exponentiation_vartime(const BigInt& k) const;

private:
std::shared_ptr<const Montgomery_Params> m_params;
std::vector<Montgomery_Int> m_g;
size_t m_window_bits;
};

Montgomery_Exponentation_State::Montgomery_Exponentation_State(const std::shared_ptr<const Montgomery_Params>& params,
const BigInt& g,
Montgomery_Exponentation_State::Montgomery_Exponentation_State(const Montgomery_Int& g,
size_t window_bits,
bool const_time) :
m_params(params), m_window_bits(window_bits == 0 ? 4 : window_bits) {
BOTAN_ARG_CHECK(g < m_params->p(), "Montgomery base too big");

m_params(g._params()), m_window_bits(window_bits == 0 ? 4 : window_bits) {
if(m_window_bits < 1 || m_window_bits > 12) { // really even 8 is too large ...
throw Invalid_Argument("Invalid window bits for Montgomery exponentiation");
}
Expand All @@ -48,17 +42,17 @@ Montgomery_Exponentation_State::Montgomery_Exponentation_State(const std::shared

m_g.reserve(window_size);

m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false));
m_g.push_back(Montgomery_Int::one(m_params));

m_g.push_back(Montgomery_Int(m_params, g));
m_g.push_back(g);

for(size_t i = 2; i != window_size; ++i) {
m_g.push_back(m_g[1] * m_g[i - 1]);
}

// Resize each element to exactly p words
for(size_t i = 0; i != window_size; ++i) {
m_g[i].fix_size();
for(auto& x : m_g) {
x.fix_size();
}

if(const_time) {
Expand Down Expand Up @@ -93,14 +87,14 @@ void const_time_lookup(secure_vector<word>& output, const std::vector<Montgomery

} // namespace

BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const {
Montgomery_Int Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const {
BOTAN_DEBUG_ASSERT(scalar.bits() <= max_k_bits);
// TODO add a const-time implementation of above assert and use it in release builds

const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits;

if(exp_nibbles == 0) {
return BigInt::one();
return Montgomery_Int::one(m_params);
}

secure_vector<word> e_bits(m_params->p_words());
Expand All @@ -116,16 +110,16 @@ BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size
}

CT::unpoison(x);
return x.value();
return x;
}

BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const {
Montgomery_Int Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const {
const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits;

secure_vector<word> ws;

if(exp_nibbles == 0) {
return BigInt::one();
return Montgomery_Int::one(m_params);
}

Montgomery_Int x = m_g[scalar.get_substring(m_window_bits * (exp_nibbles - 1), m_window_bits)];
Expand All @@ -140,27 +134,37 @@ BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scal
}

CT::unpoison(x);
return x.value();
return x;
}

std::shared_ptr<const Montgomery_Exponentation_State> monty_precompute(const Montgomery_Int& g,
size_t window_bits,
bool const_time) {
return std::make_shared<const Montgomery_Exponentation_State>(g, window_bits, const_time);
}

std::shared_ptr<const Montgomery_Exponentation_State> monty_precompute(
const std::shared_ptr<const Montgomery_Params>& params, const BigInt& g, size_t window_bits, bool const_time) {
return std::make_shared<const Montgomery_Exponentation_State>(params, g, window_bits, const_time);
BOTAN_ARG_CHECK(g < params->p(), "Montgomery base too big");
Montgomery_Int monty_g(params, g);
return monty_precompute(monty_g, window_bits, const_time);
}

BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k, size_t max_k_bits) {
Montgomery_Int monty_execute(const Montgomery_Exponentation_State& precomputed_state,
const BigInt& k,
size_t max_k_bits) {
return precomputed_state.exponentiation(k, max_k_bits);
}

BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k) {
Montgomery_Int monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k) {
return precomputed_state.exponentiation_vartime(k);
}

BigInt monty_multi_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& x_bn,
const BigInt& z1,
const BigInt& y_bn,
const BigInt& z2) {
Montgomery_Int monty_multi_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& x_bn,
const BigInt& z1,
const BigInt& y_bn,
const BigInt& z2) {
if(z1.is_negative() || z2.is_negative()) {
throw Invalid_Argument("multi_exponentiate exponents must be positive");
}
Expand Down Expand Up @@ -225,7 +229,7 @@ BigInt monty_multi_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
H.mul_by(*M[z12], ws);
}

return H.value();
return H;
}

} // namespace Botan
45 changes: 26 additions & 19 deletions src/lib/math/numbertheory/monty_exp.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
/*
* (C) 2018 Jack Lloyd
* (C) 2018,2025 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_MONTY_EXP_H_
#define BOTAN_MONTY_EXP_H_

#include <botan/bigint.h>
#include <botan/internal/monty.h>
#include <memory>

namespace Botan {

class BigInt;
class Modular_Reducer;

class Montgomery_Params;

class Montgomery_Exponentation_State;

/*
Expand All @@ -27,40 +25,49 @@ std::shared_ptr<const Montgomery_Exponentation_State> monty_precompute(
size_t window_bits,
bool const_time = true);

/*
* Precompute for calculating values g^x mod p
*/
std::shared_ptr<const Montgomery_Exponentation_State> monty_precompute(const Montgomery_Int& g,
size_t window_bits,
bool const_time = true);

/*
* Return g^k mod p
*/
BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k, size_t max_k_bits);
Montgomery_Int monty_execute(const Montgomery_Exponentation_State& precomputed_state,
const BigInt& k,
size_t max_k_bits);

/*
* Return g^k mod p taking variable time depending on k
* @warning only use this if k is public
*/
BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k);
Montgomery_Int monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, const BigInt& k);

inline BigInt monty_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& g,
const BigInt& k,
size_t max_k_bits) {
inline Montgomery_Int monty_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& g,
const BigInt& k,
size_t max_k_bits) {
auto precomputed = monty_precompute(params_p, g, 4, true);
return monty_execute(*precomputed, k, max_k_bits);
}

inline BigInt monty_exp_vartime(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& g,
const BigInt& k) {
inline Montgomery_Int monty_exp_vartime(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& g,
const BigInt& k) {
auto precomputed = monty_precompute(params_p, g, 4, false);
return monty_execute_vartime(*precomputed, k);
}

/**
* Return (x^z1 * y^z2) % p
*/
BigInt monty_multi_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& x,
const BigInt& z1,
const BigInt& y,
const BigInt& z2);
Montgomery_Int monty_multi_exp(const std::shared_ptr<const Montgomery_Params>& params_p,
const BigInt& x,
const BigInt& z1,
const BigInt& y,
const BigInt& z2);

} // namespace Botan

Expand Down
Loading
Loading