Skip to content

Commit

Permalink
In Barrett reduction distinguish between public and secret moduli
Browse files Browse the repository at this point in the history
We can use a much faster variable time division if the modulus is
public already, which is the common case.

This also (mostly) eliminates the situation where Modular_Reducer can
be uninitialized via passing zero to the constructor; this is a
holdover from lacking std::optional

Also make some changes so Barrett computations can be shared over
time, for example by exposing it from DL_Group and accepting it
as an argument to Blinder
  • Loading branch information
randombit committed Jan 23, 2025
1 parent 343c120 commit d6c0271
Show file tree
Hide file tree
Showing 23 changed files with 147 additions and 88 deletions.
4 changes: 2 additions & 2 deletions src/cli/perf_math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class PerfTest_BnRedc final : public PerfTest {
auto barrett_timer = config.make_timer("Barrett-" + bit_str);
auto schoolbook_timer = config.make_timer("Schoolbook-" + bit_str);

Botan::Modular_Reducer mod_p(p);
auto mod_p = Botan::Modular_Reducer::for_public_modulus(p);

while(schoolbook_timer->under(runtime)) {
const Botan::BigInt x(config.rng(), p.bits() * 2 - 2);
Expand Down Expand Up @@ -226,7 +226,7 @@ class PerfTest_IsPrime final : public PerfTest {
Botan::BigInt n = Botan::random_prime(config.rng(), bits);

while(lucas_timer->under(runtime)) {
Botan::Modular_Reducer mod_n(n);
auto mod_n = Botan::Modular_Reducer::for_public_modulus(n);

mr_timer->run([&]() { return Botan::is_miller_rabin_probable_prime(n, mod_n, config.rng(), 2); });

Expand Down
2 changes: 1 addition & 1 deletion src/lib/ffi/ffi_mp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t m

int botan_mp_mod_mul(botan_mp_t out, const botan_mp_t x, const botan_mp_t y, const botan_mp_t modulus) {
return BOTAN_FFI_VISIT(out, [=](auto& o) {
Botan::Modular_Reducer reducer(safe_get(modulus));
auto reducer = Botan::Modular_Reducer::for_secret_modulus(safe_get(modulus));
o = reducer.multiply(safe_get(x), safe_get(y));
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/math/numbertheory/dsa_gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ bool generate_dsa_primes(RandomNumberGenerator& rng,
BigInt X;
std::vector<uint8_t> V(HASH_SIZE * (n + 1));

Modular_Reducer mod_2q(2 * q);
auto mod_2q = Modular_Reducer::for_public_modulus(2 * q);

for(size_t j = 0; j != 4 * pbits; ++j) {
for(size_t k = 0; k <= n; ++k) {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/math/numbertheory/make_prm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ BigInt random_prime(

BOTAN_DEBUG_ASSERT(no_small_multiples(p, sieve));

Modular_Reducer mod_p(p);
auto mod_p = Modular_Reducer::for_secret_modulus(p);

if(coprime > 1) {
/*
Expand Down Expand Up @@ -259,7 +259,7 @@ BigInt generate_rsa_prime(RandomNumberGenerator& keygen_rng,

BOTAN_DEBUG_ASSERT(no_small_multiples(p, sieve));

Modular_Reducer mod_p(p);
auto mod_p = Modular_Reducer::for_secret_modulus(p);

/*
* Do a single primality test first before checking coprimality, since
Expand Down
3 changes: 1 addition & 2 deletions src/lib/math/numbertheory/monty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ Montgomery_Params::Montgomery_Params(const BigInt& p) {

const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS);

// It might be faster to use ct_modulo here vs setting up Barrett reduction?
Modular_Reducer mod_p(p);
auto mod_p = Modular_Reducer::for_secret_modulus(p);

m_r1 = mod_p.reduce(r);
m_r2 = mod_p.square(m_r1);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/math/numbertheory/numthry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ BigInt sqrt_modulo_prime(const BigInt& a, const BigInt& p) {
return BigInt::from_s32(-1);
}

Modular_Reducer mod_p(p);
auto mod_p = Modular_Reducer::for_public_modulus(p);
auto monty_p = std::make_shared<Montgomery_Params>(p, mod_p);

// If p == 3 (mod 4) there is a simple solution
Expand Down Expand Up @@ -293,7 +293,7 @@ BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod) {
return BigInt::zero();
}

Modular_Reducer reduce_mod(mod);
auto reduce_mod = Modular_Reducer::for_secret_modulus(mod);

const size_t exp_bits = exp.bits();

Expand Down Expand Up @@ -369,7 +369,7 @@ bool is_prime(const BigInt& n, RandomNumberGenerator& rng, size_t prob, bool is_
return std::binary_search(PRIMES, PRIMES + PRIME_TABLE_SIZE, num);
}

Modular_Reducer mod_n(n);
auto mod_n = Modular_Reducer::for_secret_modulus(n);

if(rng.is_seeded()) {
const size_t t = miller_rabin_test_iterations(n_bits, prob, is_random);
Expand Down
5 changes: 0 additions & 5 deletions src/lib/math/numbertheory/primality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,6 @@ bool is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n)
return passes_miller_rabin_test(n, mod_n, monty_n, base) && is_lucas_probable_prime(n, mod_n);
}

bool is_bailie_psw_probable_prime(const BigInt& n) {
Modular_Reducer mod_n(n);
return is_bailie_psw_probable_prime(n, mod_n);
}

bool passes_miller_rabin_test(const BigInt& n,
const Modular_Reducer& mod_n,
const std::shared_ptr<Montgomery_Params>& monty_n,
Expand Down
12 changes: 0 additions & 12 deletions src/lib/math/numbertheory/primality.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,6 @@ bool BOTAN_TEST_API is_lucas_probable_prime(const BigInt& n, const Modular_Reduc
*/
bool BOTAN_TEST_API is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n);

/**
* Perform Bailie-PSW primality test
*
* This is a combination of Miller-Rabin with base 2 and a Lucas test. No known
* composite integer passes both tests, though it is conjectured that infinitely
* many composite counterexamples exist.
*
* @param n the positive integer to test
* @return true if n seems probably prime, false if n is composite
*/
bool is_bailie_psw_probable_prime(const BigInt& n);

/**
* Return required number of Miller-Rabin tests in order to
* reach the specified probability of error.
Expand Down
35 changes: 27 additions & 8 deletions src/lib/math/numbertheory/reducer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,36 @@ Modular_Reducer::Modular_Reducer(const BigInt& mod) {
m_mod_words = 0;

if(mod > 0) {
m_modulus = mod;
m_mod_words = m_modulus.sig_words();

// Compute mu = floor(2^{2k} / m)
const size_t mu_bits = 2 * BOTAN_MP_WORD_BITS * m_mod_words;
m_mu.set_bit(mu_bits);
m_mu = ct_divide_pow2k(mu_bits, m_modulus);
//m_mu = BigInt::power_of_2(mu_bits) / m_modulus;
*this = Modular_Reducer::for_secret_modulus(mod);
}
}

Modular_Reducer Modular_Reducer::for_secret_modulus(const BigInt& mod) {
BOTAN_ARG_CHECK(!mod.is_zero(), "Modulus cannot be zero");
BOTAN_ARG_CHECK(!mod.is_negative(), "Modulus cannot be negative");

// Left uninitialized if mod == 0
size_t mod_words = mod.sig_words();

// Compute mu = floor(2^{2k} / m)
const size_t mu_bits = 2 * BOTAN_MP_WORD_BITS * mod_words;
BigInt mu = ct_divide_pow2k(mu_bits, mod);
return Modular_Reducer(mod, mu, mod_words);
}

Modular_Reducer Modular_Reducer::for_public_modulus(const BigInt& mod) {
BOTAN_ARG_CHECK(!mod.is_zero(), "Modulus cannot be zero");
BOTAN_ARG_CHECK(!mod.is_negative(), "Modulus cannot be negative");

// Left uninitialized if mod == 0
size_t mod_words = mod.sig_words();

// Compute mu = floor(2^{2k} / m)
const size_t mu_bits = 2 * BOTAN_MP_WORD_BITS * mod_words;
BigInt mu = BigInt::power_of_2(mu_bits) / mod;
return Modular_Reducer(mod, mu, mod_words);
}

BigInt Modular_Reducer::reduce(const BigInt& x) const {
BigInt r;
secure_vector<word> ws;
Expand Down
19 changes: 17 additions & 2 deletions src/lib/math/numbertheory/reducer.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,26 @@ class BOTAN_PUBLIC_API(2, 0) Modular_Reducer final {

bool initialized() const { return (m_mod_words != 0); }

Modular_Reducer() { m_mod_words = 0; }
BOTAN_DEPRECATED("Use for_public_modulus or for_secret_modulus") Modular_Reducer() { m_mod_words = 0; }

explicit Modular_Reducer(const BigInt& mod);
/**
* Accepts m == 0 and leaves the Modular_Reducer in an uninitialized state
*/
BOTAN_DEPRECATED("Use for_public_modulus or for_secret_modulus") explicit Modular_Reducer(const BigInt& mod);

/**
* Requires that m > 0
*/
static Modular_Reducer for_public_modulus(const BigInt& m);

/**
* Requires that m > 0
*/
static Modular_Reducer for_secret_modulus(const BigInt& m);

private:
Modular_Reducer(const BigInt& m, const BigInt& mu, size_t mw) : m_modulus(m), m_mu(mu), m_mod_words(mw) {}

BigInt m_modulus, m_mu;
size_t m_mod_words;
};
Expand Down
4 changes: 3 additions & 1 deletion src/lib/misc/fpe_fe1/fpe_fe1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ FPE_FE1::FPE_FE1(const BigInt& n, size_t rounds, bool compat_mode, std::string_v
}
}

mod_a = std::make_unique<Modular_Reducer>(m_a);
// The modulus is usually a system parameter and anyway is easily deduced from
// the ciphertexts
mod_a = std::make_unique<Modular_Reducer>(Modular_Reducer::for_public_modulus(m_a));
}

FPE_FE1::~FPE_FE1() = default;
Expand Down
1 change: 1 addition & 0 deletions src/lib/prov/pkcs11/p11_rsa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class PKCS11_RSA_Decryption_Operation final : public PK_Ops::Decryption {
m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding)),
m_blinder(
m_key.get_n(),
Modular_Reducer::for_public_modulus(m_key.get_n()),
rng,
[this](const BigInt& k) { return power_mod(k, m_key.get_e(), m_key.get_n()); },
[this](const BigInt& k) { return inverse_mod_rsa_public_modulus(k, m_key.get_n()); }) {
Expand Down
11 changes: 2 additions & 9 deletions src/lib/pubkey/blinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
namespace Botan {

Blinder::Blinder(const BigInt& modulus,
const Modular_Reducer& reducer,
RandomNumberGenerator& rng,
std::function<BigInt(const BigInt&)> fwd,
std::function<BigInt(const BigInt&)> inv) :
m_reducer(modulus),
m_reducer(reducer),
m_rng(rng),
m_fwd_fn(std::move(fwd)),
m_inv_fn(std::move(inv)),
Expand All @@ -31,10 +32,6 @@ BigInt Blinder::blinding_nonce() const {
}

BigInt Blinder::blind(const BigInt& i) const {
if(!m_reducer.initialized()) {
throw Invalid_State("Blinder not initialized, cannot blind");
}

++m_counter;

if((BOTAN_BLINDING_REINIT_INTERVAL > 0) && (m_counter > BOTAN_BLINDING_REINIT_INTERVAL)) {
Expand All @@ -51,10 +48,6 @@ BigInt Blinder::blind(const BigInt& i) const {
}

BigInt Blinder::unblind(const BigInt& i) const {
if(!m_reducer.initialized()) {
throw Invalid_State("Blinder not initialized, cannot unblind");
}

return m_reducer.multiply(i, m_d);
}

Expand Down
1 change: 1 addition & 0 deletions src/lib/pubkey/blinding.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Blinder final {
* of the given value (the nonce)
*/
Blinder(const BigInt& modulus,
const Modular_Reducer& reducer,
RandomNumberGenerator& rng,
std::function<BigInt(const BigInt&)> fwd_func,
std::function<BigInt(const BigInt&)> inv_func);
Expand Down
1 change: 1 addition & 0 deletions src/lib/pubkey/dh/dh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class DH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF {
m_key_bits(m_key->private_key().bits()),
m_blinder(
m_key->group().get_p(),
m_key->group()._reducer_mod_p(),
rng,
[](const BigInt& k) { return k; },
[this](const BigInt& k) { return powermod_x_p(group().inverse_mod_p(k)); }) {}
Expand Down
Loading

0 comments on commit d6c0271

Please sign in to comment.