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 }