1 /** 2 * Modular Exponentiator 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.pow_mod; 12 13 import botan.constants; 14 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO): 15 16 import botan.constants; 17 import botan.math.bigint.bigint; 18 import botan.libstate.libstate; 19 import botan.engine.engine; 20 21 alias FixedExponentPowerMod = RefCounted!FixedExponentPowerModImpl; 22 alias FixedBasePowerMod = RefCounted!FixedBasePowerModImpl; 23 24 /** 25 * Modular Exponentiator Interface 26 */ 27 interface ModularExponentiator 28 { 29 public: 30 void setBase(const ref BigInt); 31 void setExponent(const ref BigInt); 32 BigInt execute() const; 33 ModularExponentiator copy() const; 34 } 35 36 /** 37 * Modular Exponentiator Proxy 38 */ 39 class PowerMod 40 { 41 public: 42 alias UsageHints = ushort; 43 enum : UsageHints { 44 NO_HINTS = 0x0000, 45 46 BASE_IS_FIXED = 0x0001, 47 BASE_IS_SMALL = 0x0002, 48 BASE_IS_LARGE = 0x0004, 49 BASE_IS_2 = 0x0008, 50 51 EXP_IS_FIXED = 0x0100, 52 EXP_IS_SMALL = 0x0200, 53 EXP_IS_LARGE = 0x0400 54 } 55 56 /* 57 * Try to choose a good window size 58 */ 59 static size_t windowBits(size_t exp_bits, size_t, 60 PowerMod.UsageHints hints) 61 { 62 __gshared immutable size_t[2][] wsize = [ 63 [ 1434, 7 ], 64 [ 539, 6 ], 65 [ 197, 4 ], 66 [ 70, 3 ], 67 [ 25, 2 ], 68 [ 0, 0 ] 69 ]; 70 71 size_t window_bits = 1; 72 73 if (exp_bits) 74 { 75 for (size_t j = 0; wsize[j][0]; ++j) 76 { 77 if (exp_bits >= wsize[j][0]) 78 { 79 window_bits += wsize[j][1]; 80 break; 81 } 82 } 83 } 84 85 if (hints & PowerMod.BASE_IS_FIXED) 86 window_bits += 2; 87 if (hints & PowerMod.EXP_IS_LARGE) 88 ++window_bits; 89 90 return window_bits; 91 } 92 93 /* 94 * Set the modulus 95 */ 96 void setModulus()(auto const ref BigInt n, UsageHints hints = NO_HINTS) 97 { 98 m_core.free(); 99 if (n != 0) 100 { 101 AlgorithmFactory af = globalState().algorithmFactory(); 102 103 foreach (Engine engine; af.engines[]) { 104 m_core = engine.modExp(n, hints); 105 106 if (m_core) 107 break; 108 } 109 if (!m_core) 110 throw new LookupError("PowerMod: Unable to find a working engine"); 111 } 112 } 113 114 /* 115 * Set the base 116 */ 117 void setBase()(auto const ref BigInt b) 118 { 119 120 if (b.isZero() || b.isNegative()) 121 throw new InvalidArgument("PowerMod.setBase: arg must be > 0"); 122 123 if (!m_core) 124 throw new InternalError("PowerMod.setBase: core was NULL"); 125 126 m_core.setBase(b); 127 } 128 129 /* 130 * Set the exponent 131 */ 132 void setExponent()(auto const ref BigInt e) 133 { 134 if (e.isNegative()) 135 throw new InvalidArgument("PowerMod.setExponent: arg must be > 0"); 136 137 if (!m_core) 138 throw new InternalError("PowerMod.setExponent: core was NULL"); 139 m_core.setExponent(e); 140 } 141 142 /* 143 * Compute the result 144 */ 145 BigInt execute() 146 { 147 if (!m_core) 148 throw new InternalError("PowerMod.execute: core was NULL"); 149 return m_core.execute(); 150 } 151 152 this()(auto const ref BigInt n, UsageHints hints = NO_HINTS) 153 { 154 setModulus(n, hints); 155 } 156 157 this(PowerMod other) 158 { 159 if (other.m_core) 160 m_core = other.m_core.release(); 161 } 162 163 private: 164 Unique!ModularExponentiator m_core; 165 } 166 167 /** 168 * Fixed Exponent Modular Exponentiator Proxy 169 */ 170 class FixedExponentPowerModImpl : PowerMod 171 { 172 public: 173 BigInt opCall()(auto const ref BigInt b) 174 { setBase(b); return execute(); } 175 176 /* 177 * FixedExponentPowerMod Constructor 178 */ 179 this()(auto const ref BigInt e, 180 auto const ref BigInt n, 181 UsageHints hints = NO_HINTS) 182 { 183 super(n, UsageHints(hints | EXP_IS_FIXED | chooseExpHints(e, n))); 184 setExponent(e); 185 } 186 187 188 } 189 190 /** 191 * Fixed Base Modular Exponentiator Proxy 192 */ 193 class FixedBasePowerModImpl : PowerMod 194 { 195 public: 196 BigInt opCall()(auto const ref BigInt e) 197 { setExponent(e); return execute(); } 198 199 /* 200 * FixedBasePowerMod Constructor 201 */ 202 this()(auto const ref BigInt b, auto const ref BigInt n, UsageHints hints = NO_HINTS) 203 { 204 super(n, UsageHints(hints | BASE_IS_FIXED | chooseBaseHints(b, n))); 205 setBase(b); 206 } 207 208 } 209 210 211 /* 212 * Choose potentially useful hints 213 */ 214 PowerMod.UsageHints chooseBaseHints()(auto const ref BigInt b, auto const ref BigInt n) 215 { 216 if (b == 2) 217 return cast(PowerMod.UsageHints)(PowerMod.BASE_IS_2 | PowerMod.BASE_IS_SMALL); 218 219 const size_t b_bits = b.bits(); 220 const size_t n_bits = n.bits(); 221 222 if (b_bits < n_bits / 32) 223 return PowerMod.BASE_IS_SMALL; 224 if (b_bits > n_bits / 4) 225 return PowerMod.BASE_IS_LARGE; 226 227 return PowerMod.NO_HINTS; 228 } 229 230 /* 231 * Choose potentially useful hints 232 */ 233 PowerMod.UsageHints chooseExpHints()(auto const ref BigInt e, auto const ref BigInt n) 234 { 235 const size_t e_bits = e.bits(); 236 const size_t n_bits = n.bits(); 237 238 if (e_bits < n_bits / 32) 239 return PowerMod.BASE_IS_SMALL; 240 if (e_bits > n_bits / 4) 241 return PowerMod.BASE_IS_LARGE; 242 return PowerMod.NO_HINTS; 243 }