1 /** 2 * Modular Exponentiation 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.math.numbertheory.def_powm; 12 13 import botan.constants; 14 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO): 15 16 import botan.math.mp.mp_core; 17 import botan.math.numbertheory.pow_mod; 18 import botan.math.numbertheory.reducer; 19 import botan.math.numbertheory.numthry; 20 import botan.math.bigint.bigint; 21 import botan.utils.types; 22 import botan.constants; 23 24 /** 25 * Fixed Window Exponentiator 26 */ 27 final class FixedWindowExponentiator : ModularExponentiator 28 { 29 public: 30 /* 31 * Set the exponent 32 */ 33 override void setExponent(const ref BigInt e) 34 { 35 m_exp = e.dup; 36 } 37 38 /* 39 * Set the base 40 */ 41 override void setBase(const ref BigInt base) 42 { 43 m_window_bits = PowerMod.windowBits(m_exp.bits(), base.bits(), m_hints); 44 auto base_2 = base.dup; 45 m_g.resize(1 << m_window_bits); 46 m_g[0] = RefCounted!BigInt(1); 47 m_g[1] = RefCounted!BigInt(base_2); 48 49 for (size_t i = 2; i != m_g.length; ++i) 50 m_g[i] = RefCounted!BigInt(m_reducer.multiply(*(m_g[i-1]), *(m_g[1]))); 51 } 52 53 /* 54 * Compute the result 55 */ 56 override BigInt execute() const 57 { 58 const size_t exp_nibbles = (m_exp.bits() + m_window_bits - 1) / m_window_bits; 59 60 BigInt x = BigInt(1); 61 62 for (size_t i = exp_nibbles; i > 0; --i) 63 { 64 foreach (size_t j; 0 .. m_window_bits) 65 x = m_reducer.square(x); 66 67 const uint nibble = m_exp.getSubstring(m_window_bits*(i-1), m_window_bits); 68 69 x = m_reducer.multiply(x, *(m_g[nibble])); 70 } 71 return x.move(); 72 } 73 74 override ModularExponentiator copy() const 75 { 76 FixedWindowExponentiator ret = new FixedWindowExponentiator; 77 ret.m_reducer = m_reducer.dup; 78 ret.m_exp = m_exp.dup; 79 ret.m_window_bits = m_window_bits; 80 ret.m_g = m_g.dup; 81 ret.m_hints = m_hints; 82 return ret; 83 } 84 85 this()(auto const ref BigInt n, PowerMod.UsageHints _hints) 86 { 87 m_reducer = ModularReducer(n); 88 m_hints = _hints; 89 m_window_bits = 0; 90 } 91 92 ~this() { 93 foreach (ref RefCounted!BigInt bi; m_g[]) { 94 (*bi).destroy(); 95 } 96 } 97 98 private: 99 this() { } 100 ModularReducer m_reducer; 101 BigInt m_exp; 102 size_t m_window_bits; 103 Vector!(RefCounted!BigInt) m_g; 104 PowerMod.UsageHints m_hints; 105 } 106 107 /** 108 * Montgomery Exponentiator 109 */ 110 class MontgomeryExponentiator : ModularExponentiator 111 { 112 public: 113 /* 114 * Set the exponent 115 */ 116 override void setExponent(const ref BigInt exp) 117 { 118 m_exp = exp.dup; 119 m_exp_bits = exp.bits(); 120 } 121 122 /* 123 * Set the base 124 */ 125 override void setBase(const ref BigInt base) 126 { 127 m_window_bits = PowerMod.windowBits(m_exp.bits(), base.bits(), m_hints); 128 m_g.resize((1 << m_window_bits)); 129 130 BigInt z = BigInt(BigInt.Positive, 2 * (m_mod_words + 1)); 131 SecureVector!word workspace = SecureVector!word(z.length); 132 133 m_g[0] = RefCounted!BigInt(1); 134 135 bigint_monty_mul(z.mutablePtr(), z.length, m_g[0].ptr, m_g[0].length, m_g[0].sigWords(), m_R2_mod.ptr, 136 m_R2_mod.length, m_R2_mod.sigWords(), m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 137 138 m_g[0] = RefCounted!BigInt(z.dup); 139 140 m_g[1] = (base >= m_modulus) ? RefCounted!BigInt(base % m_modulus) : RefCounted!BigInt(base.dup); 141 142 bigint_monty_mul(z.mutablePtr(), z.length, m_g[1].ptr, m_g[1].length, m_g[1].sigWords(), m_R2_mod.ptr, 143 m_R2_mod.length, m_R2_mod.sigWords(), m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 144 145 m_g[1] = RefCounted!BigInt(z.dup); 146 147 const BigInt* x = &*(m_g[1]); 148 const size_t x_sig = x.sigWords(); 149 150 for (size_t i = 2; i != m_g.length; ++i) 151 { 152 const BigInt* y = &*(m_g[i-1]); 153 const size_t y_sig = y.sigWords(); 154 155 bigint_monty_mul(z.mutablePtr(), z.length, 156 x.ptr, x.length, x_sig, 157 y.ptr, y.length, y_sig, 158 m_modulus.ptr, m_mod_words, m_mod_prime, 159 workspace.ptr); 160 161 m_g[i] = RefCounted!BigInt(z.dup); 162 } 163 } 164 165 /* 166 * Compute the result 167 */ 168 override BigInt execute() const 169 { 170 const size_t exp_nibbles = (m_exp_bits + m_window_bits - 1) / m_window_bits; 171 172 BigInt x = m_R_mod.dup; 173 174 const size_t z_size = 2*(m_mod_words + 1); 175 176 BigInt z = BigInt(BigInt.Positive, z_size); 177 SecureVector!word workspace = SecureVector!word(z_size); 178 179 for (size_t i = exp_nibbles; i > 0; --i) 180 { 181 for (size_t k = 0; k != m_window_bits; ++k) 182 { 183 bigint_monty_sqr(z.mutablePtr(), z_size, x.ptr, x.length, x.sigWords(), 184 m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 185 186 x.growTo(z.length); 187 x.mutablePtr[0..x.length] = z.mutablePtr[0..z.length]; 188 } 189 190 const uint nibble = m_exp.getSubstring(m_window_bits*(i-1), m_window_bits); 191 192 const BigInt* y = &*m_g[nibble]; 193 194 195 bigint_monty_mul(z.mutablePtr(), z_size, x.ptr, x.length, x.sigWords(), y.ptr, y.length, y.sigWords(), 196 m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 197 x.growTo(z.length); 198 x.mutablePtr[0..x.length] = z.mutablePtr[0..z.length]; 199 } 200 201 x.growTo(2*m_mod_words + 1); 202 203 bigint_monty_redc(x.mutablePtr(), m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 204 return x.move(); 205 } 206 207 override ModularExponentiator copy() const 208 { 209 MontgomeryExponentiator ret = new MontgomeryExponentiator; 210 ret.m_exp = m_exp.dup; 211 ret.m_modulus = m_modulus.dup; 212 ret.m_R_mod = m_R_mod.dup; 213 ret.m_R2_mod = m_R2_mod.dup; 214 ret.m_mod_prime = m_mod_prime; 215 ret.m_mod_words = m_mod_words; 216 ret.m_exp_bits = m_exp_bits; 217 ret.m_window_bits = m_window_bits; 218 ret.m_hints = m_hints; 219 ret.m_g = m_g.dup; 220 return ret; 221 } 222 223 /* 224 * Montgomery_Exponentiator Constructor 225 */ 226 this()(auto const ref BigInt mod, PowerMod.UsageHints hints) 227 { 228 m_modulus = mod.dup; 229 m_mod_words = m_modulus.sigWords(); 230 m_window_bits = 1; 231 m_hints = hints; 232 // Montgomery reduction only works for positive odd moduli 233 if (!m_modulus.isPositive() || m_modulus.isEven()) 234 throw new InvalidArgument("Montgomery_Exponentiator: invalid modulus"); 235 236 m_mod_prime = montyInverse(mod.wordAt(0)); 237 238 BigInt r = BigInt.powerOf2(m_mod_words * BOTAN_MP_WORD_BITS); 239 m_R_mod = r % m_modulus; 240 auto r_mod_temp = (m_R_mod * m_R_mod); 241 m_R2_mod = r_mod_temp % m_modulus; 242 } 243 244 ~this() { 245 foreach (ref RefCounted!BigInt bi; m_g[]) { 246 (*bi).destroy(); 247 } 248 } 249 250 private: 251 this() { } 252 BigInt m_exp, m_modulus, m_R_mod, m_R2_mod; 253 word m_mod_prime; 254 size_t m_mod_words, m_exp_bits, m_window_bits; 255 PowerMod.UsageHints m_hints; 256 Vector!(RefCounted!BigInt) m_g; 257 } 258