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(BigInt)*); 31 void setExponent(const(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(const(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(const(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(const(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(const(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(const(BigInt)* b) 174 { setBase(b); return execute(); } 175 BigInt opCall(const BigInt b) const 176 { (cast()this).setBase(&b); return (cast()this).execute(); } 177 BigInt opCall(shared(BigInt*) e) 178 { setBase(cast(BigInt*)e); return execute(); } 179 180 /* 181 * FixedExponentPowerMod Constructor 182 */ 183 this(const(BigInt)* e, 184 const(BigInt)* n, 185 UsageHints hints = NO_HINTS) 186 { 187 super(n, UsageHints(hints | EXP_IS_FIXED | chooseExpHints(e, n))); 188 setExponent(e); 189 } 190 191 192 } 193 194 /** 195 * Fixed Base Modular Exponentiator Proxy 196 */ 197 class FixedBasePowerModImpl : PowerMod 198 { 199 public: 200 BigInt opCall(const(BigInt)* e) 201 { setExponent(e); return execute(); } 202 BigInt opCall(const BigInt e) const 203 { (cast()this).setExponent(&e); return (cast()this).execute(); } 204 BigInt opCall(shared(BigInt*) e) 205 { setExponent(cast(BigInt*)e); return execute(); } 206 207 /* 208 * FixedBasePowerMod Constructor 209 */ 210 this(const(BigInt)* b, const(BigInt)* n, UsageHints hints = NO_HINTS) 211 { 212 super(n, UsageHints(hints | BASE_IS_FIXED | chooseBaseHints(b, n))); 213 setBase(b); 214 } 215 216 } 217 218 219 /* 220 * Choose potentially useful hints 221 */ 222 PowerMod.UsageHints chooseBaseHints(const(BigInt)* b, const(BigInt)* n) 223 { 224 if (*b == 2) 225 return cast(PowerMod.UsageHints)(PowerMod.BASE_IS_2 | PowerMod.BASE_IS_SMALL); 226 227 const size_t b_bits = b.bits(); 228 const size_t n_bits = n.bits(); 229 230 if (b_bits < n_bits / 32) 231 return PowerMod.BASE_IS_SMALL; 232 if (b_bits > n_bits / 4) 233 return PowerMod.BASE_IS_LARGE; 234 235 return PowerMod.NO_HINTS; 236 } 237 238 /* 239 * Choose potentially useful hints 240 */ 241 PowerMod.UsageHints chooseExpHints(const(BigInt)* e, const(BigInt)* n) 242 { 243 const size_t n_bits = n.bits(); 244 const size_t e_bits = e.bits(); 245 246 if (e_bits < n_bits / 32) 247 return PowerMod.BASE_IS_SMALL; 248 if (e_bits > n_bits / 4) 249 return PowerMod.BASE_IS_LARGE; 250 return PowerMod.NO_HINTS; 251 }