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(BigInt)* e) 34 { 35 m_exp = e.clone; 36 } 37 38 /* 39 * Set the base 40 */ 41 override void setBase(const(BigInt)* base) 42 { 43 m_window_bits = PowerMod.windowBits(m_exp.bits(), base.bits(), m_hints); 44 m_g.resize(1 << m_window_bits); 45 auto base_2 = base.clone; 46 m_g[0] = RefCounted!BigInt(1); 47 m_g[1] = RefCounted!BigInt(&base_2); 48 for (size_t i = 2; i != m_g.length; ++i) { 49 auto mg_0 = m_reducer.multiply(&*m_g[i-1], &*m_g[1]); 50 m_g[i] = RefCounted!BigInt(&mg_0); 51 } 52 } 53 54 /* 55 * Compute the result 56 */ 57 override BigInt execute() const 58 { 59 const size_t exp_nibbles = (m_exp.bits() + m_window_bits - 1) / m_window_bits; 60 61 BigInt x = BigInt(1); 62 63 for (size_t i = exp_nibbles; i > 0; --i) 64 { 65 foreach (size_t j; 0 .. m_window_bits) 66 x = m_reducer.square(&x); 67 68 const uint nibble = m_exp.getSubstring(m_window_bits*(i-1), m_window_bits); 69 70 x = m_reducer.multiply(&x, &* m_g[nibble]); 71 } 72 return x.move(); 73 } 74 75 override ModularExponentiator copy() const 76 { 77 FixedWindowExponentiator ret = new FixedWindowExponentiator; 78 ret.m_reducer = m_reducer.clone; 79 ret.m_exp = m_exp.clone; 80 ret.m_window_bits = m_window_bits; 81 ret.m_g = m_g.clone; 82 ret.m_hints = m_hints; 83 return ret; 84 } 85 86 this(const(BigInt)* n, PowerMod.UsageHints _hints) 87 { 88 m_reducer = ModularReducer(*n); 89 m_hints = _hints; 90 m_window_bits = 0; 91 } 92 private: 93 this() { } 94 ModularReducer m_reducer; 95 BigInt m_exp; 96 size_t m_window_bits; 97 Vector!(RefCounted!BigInt) m_g; 98 PowerMod.UsageHints m_hints; 99 } 100 101 /** 102 * Montgomery Exponentiator 103 */ 104 class MontgomeryExponentiator : ModularExponentiator 105 { 106 public: 107 /* 108 * Set the exponent 109 */ 110 override void setExponent(const(BigInt)* exp) 111 { 112 m_exp = exp.clone; 113 m_exp_bits = exp.bits(); 114 } 115 116 /* 117 * Set the base 118 */ 119 override void setBase(const(BigInt)* base) 120 { 121 m_window_bits = PowerMod.windowBits(m_exp.bits(), base.bits(), m_hints); 122 m_g.resize((1 << m_window_bits)); 123 124 BigInt z = BigInt(BigInt.Positive, 2 * (m_mod_words + 1)); 125 SecureVector!word workspace = SecureVector!word(z.length); 126 127 m_g[0] = RefCounted!BigInt(1); 128 129 bigint_monty_mul(z.mutablePtr(), z.length, m_g[0].ptr, m_g[0].length, m_g[0].sigWords(), m_R2_mod.ptr, 130 m_R2_mod.length, m_R2_mod.sigWords(), m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 131 132 auto z_0 = z.clone; 133 m_g[0] = RefCounted!BigInt(&z_0); 134 135 auto base_0 = (*base).clone; 136 if (base_0 >= &m_modulus) { 137 auto base_modulo = base_0 % &m_modulus; 138 m_g[1] = RefCounted!BigInt(&base_modulo); 139 } 140 else m_g[1] = RefCounted!BigInt(&base_0); 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 auto z_1 = z.clone; 146 m_g[1] = RefCounted!BigInt(&z_1); 147 148 const BigInt* x = &*(m_g[1]); 149 const size_t x_sig = x.sigWords(); 150 151 for (size_t i = 2; i != m_g.length; ++i) 152 { 153 const BigInt* y = &*(m_g[i-1]); 154 const size_t y_sig = y.sigWords(); 155 156 bigint_monty_mul(z.mutablePtr(), z.length, 157 x.ptr, x.length, x_sig, 158 y.ptr, y.length, y_sig, 159 m_modulus.ptr, m_mod_words, m_mod_prime, 160 workspace.ptr); 161 auto z_dup = z.clone; 162 m_g[i] = RefCounted!BigInt(&z_dup); 163 } 164 } 165 166 /* 167 * Compute the result 168 */ 169 override BigInt execute() const 170 { 171 const size_t exp_nibbles = (m_exp_bits + m_window_bits - 1) / m_window_bits; 172 173 BigInt x = m_R_mod.clone; 174 175 const size_t z_size = 2*(m_mod_words + 1); 176 177 BigInt z = BigInt(BigInt.Positive, z_size); 178 SecureVector!word workspace = SecureVector!word(z_size); 179 180 for (size_t i = exp_nibbles; i > 0; --i) 181 { 182 for (size_t k = 0; k != m_window_bits; ++k) 183 { 184 bigint_monty_sqr(z.mutablePtr(), z_size, x.ptr, x.length, x.sigWords(), 185 m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 186 187 x.growTo(z.length); 188 x.mutablePtr[0..x.length] = z.mutablePtr[0..z.length]; 189 } 190 191 const uint nibble = m_exp.getSubstring(m_window_bits*(i-1), m_window_bits); 192 193 const BigInt* y = &*m_g[nibble]; 194 195 196 bigint_monty_mul(z.mutablePtr(), z_size, x.ptr, x.length, x.sigWords(), y.ptr, y.length, y.sigWords(), 197 m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 198 x.growTo(z.length); 199 x.mutablePtr[0..x.length] = z.mutablePtr[0..z.length]; 200 } 201 202 x.growTo(2*m_mod_words + 1); 203 204 bigint_monty_redc(x.mutablePtr(), m_modulus.ptr, m_mod_words, m_mod_prime, workspace.ptr); 205 return x.move(); 206 } 207 208 override ModularExponentiator copy() const 209 { 210 MontgomeryExponentiator ret = new MontgomeryExponentiator; 211 ret.m_exp = m_exp.clone; 212 ret.m_modulus = m_modulus.clone; 213 ret.m_R_mod = m_R_mod.clone; 214 ret.m_R2_mod = m_R2_mod.clone; 215 ret.m_mod_prime = m_mod_prime; 216 ret.m_mod_words = m_mod_words; 217 ret.m_exp_bits = m_exp_bits; 218 ret.m_window_bits = m_window_bits; 219 ret.m_hints = m_hints; 220 ret.m_g = m_g.clone; 221 return ret; 222 } 223 224 /* 225 * Montgomery_Exponentiator Constructor 226 */ 227 this(const(BigInt)* mod, PowerMod.UsageHints hints) 228 { 229 m_modulus = mod.clone; 230 m_mod_words = m_modulus.sigWords(); 231 m_window_bits = 1; 232 m_hints = hints; 233 // Montgomery reduction only works for positive odd moduli 234 if (!m_modulus.isPositive() || m_modulus.isEven()) 235 throw new InvalidArgument("Montgomery_Exponentiator: invalid modulus"); 236 237 m_mod_prime = montyInverse(mod.wordAt(0)); 238 239 BigInt r = BigInt.powerOf2(m_mod_words * BOTAN_MP_WORD_BITS); 240 m_R_mod = r % m_modulus; 241 auto r_mod_temp = (m_R_mod * m_R_mod); 242 m_R2_mod = r_mod_temp % m_modulus; 243 } 244 245 private: 246 this() { } 247 BigInt m_exp, m_modulus, m_R_mod, m_R2_mod; 248 word m_mod_prime; 249 size_t m_mod_words, m_exp_bits, m_window_bits; 250 PowerMod.UsageHints m_hints; 251 Vector!(RefCounted!BigInt) m_g; 252 } 253