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 }