/* * Montgomery Exponentiation * (C) 1999-2010 Jack Lloyd * * Distributed under the terms of the Botan license */ #include #include #include namespace Botan { /* * Set the exponent */ void Montgomery_Exponentiator::set_exponent(const BigInt& exp) { this->exp = exp; exp_bits = exp.bits(); } /* * Set the base */ void Montgomery_Exponentiator::set_base(const BigInt& base) { window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints); g.resize((1 << window_bits) - 1); SecureVector z(2 * (mod_words + 1)); SecureVector workspace(z.size()); g[0] = (base >= modulus) ? (base % modulus) : base; bigint_mul(&z[0], z.size(), &workspace[0], g[0].data(), g[0].size(), g[0].sig_words(), R2.data(), R2.size(), R2.sig_words()); bigint_monty_redc(&z[0], z.size(), &workspace[0], modulus.data(), mod_words, mod_prime); g[0].assign(&z[0], mod_words + 1); const BigInt& x = g[0]; const size_t x_sig = x.sig_words(); for(size_t i = 1; i != g.size(); ++i) { const BigInt& y = g[i-1]; const size_t y_sig = y.sig_words(); zeroise(z); bigint_mul(&z[0], z.size(), &workspace[0], x.data(), x.size(), x_sig, y.data(), y.size(), y_sig); bigint_monty_redc(&z[0], z.size(), &workspace[0], modulus.data(), mod_words, mod_prime); g[i].assign(&z[0], mod_words + 1); } } /* * Compute the result */ BigInt Montgomery_Exponentiator::execute() const { const size_t exp_nibbles = (exp_bits + window_bits - 1) / window_bits; BigInt x = R_mod; SecureVector z(2 * (mod_words + 1)); SecureVector workspace(2 * (mod_words + 1)); for(size_t i = exp_nibbles; i > 0; --i) { for(size_t k = 0; k != window_bits; ++k) { zeroise(z); bigint_sqr(&z[0], z.size(), &workspace[0], x.data(), x.size(), x.sig_words()); bigint_monty_redc(&z[0], z.size(), &workspace[0], modulus.data(), mod_words, mod_prime); x.assign(&z[0], mod_words + 1); } if(u32bit nibble = exp.get_substring(window_bits*(i-1), window_bits)) { const BigInt& y = g[nibble-1]; zeroise(z); bigint_mul(&z[0], z.size(), &workspace[0], x.data(), x.size(), x.sig_words(), y.data(), y.size(), y.sig_words()); bigint_monty_redc(&z[0], z.size(), &workspace[0], modulus.data(), mod_words, mod_prime); x.assign(&z[0], mod_words + 1); } } x.get_reg().resize(2*mod_words+1); bigint_monty_redc(&x[0], x.size(), &workspace[0], modulus.data(), mod_words, mod_prime); x.get_reg().resize(mod_words+1); return x; } /* * Montgomery_Exponentiator Constructor */ Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, Power_Mod::Usage_Hints hints) { // Montgomery reduction only works for positive odd moduli if(!mod.is_positive() || mod.is_even()) throw Invalid_Argument("Montgomery_Exponentiator: invalid modulus"); window_bits = 0; this->hints = hints; modulus = mod; mod_words = modulus.sig_words(); BigInt mod_prime_bn(BigInt::Power2, MP_WORD_BITS); mod_prime = (mod_prime_bn - inverse_mod(modulus, mod_prime_bn)).word_at(0); R_mod = BigInt(BigInt::Power2, MP_WORD_BITS * mod_words); R_mod %= modulus; R2 = BigInt(BigInt::Power2, 2 * MP_WORD_BITS * mod_words); R2 %= modulus; } }