Botan 1.10.17

numthry.cpp
Go to the documentation of this file.
1 /*
2 * Number Theory Functions
3 * (C) 1999-2011 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7
8 #include <botan/numthry.h>
9 #include <botan/reducer.h>
10 #include <botan/internal/mp_core.h>
11 #include <botan/internal/bit_ops.h>
12 #include <algorithm>
13
14 namespace Botan {
15
16 namespace {
17
18 /*
19 * Miller-Rabin Primality Tester
20 */
21 class MillerRabin_Test
22 {
23 public:
24 bool is_witness(const BigInt& nonce);
25 MillerRabin_Test(const BigInt& num);
26 private:
27 BigInt n, r, n_minus_1;
28 size_t s;
29 Fixed_Exponent_Power_Mod pow_mod;
30 Modular_Reducer reducer;
31 };
32
33 /*
34 * Miller-Rabin Test, as described in Handbook of Applied Cryptography
35 * section 4.24
36 */
37 bool MillerRabin_Test::is_witness(const BigInt& a)
38 {
39 if(a < 2 || a >= n_minus_1)
40 throw Invalid_Argument("Bad size for nonce in Miller-Rabin test");
41
42 BigInt y = pow_mod(a);
43 if(y == 1 || y == n_minus_1)
44 return false;
45
46 for(size_t i = 1; i != s; ++i)
47 {
48 y = reducer.square(y);
49
50 if(y == 1) // found a non-trivial square root
51 return true;
52
53 if(y == n_minus_1) // -1, trivial square root, so give up
54 return false;
55 }
56
57 // If we reached here then n fails the Fermat test
58 return true;
59 }
60
61 /*
62 * Miller-Rabin Constructor
63 */
64 MillerRabin_Test::MillerRabin_Test(const BigInt& num)
65 {
66 if(num.is_even() || num < 3)
67 throw Invalid_Argument("MillerRabin_Test: Invalid number for testing");
68
69 n = num;
70 n_minus_1 = n - 1;
71 s = low_zero_bits(n_minus_1);
72 r = n_minus_1 >> s;
73
74 pow_mod = Fixed_Exponent_Power_Mod(r, n);
75 reducer = Modular_Reducer(n);
76 }
77
78 /*
79 * Miller-Rabin Iterations
80 */
81 size_t miller_rabin_test_iterations(size_t bits, size_t level)
82 {
83 struct mapping { size_t bits; size_t verify_iter; size_t check_iter; };
84
85 static const mapping tests[] = {
86 { 50, 55, 25 },
87 { 100, 38, 22 },
88 { 160, 32, 18 },
89 { 163, 31, 17 },
90 { 168, 30, 16 },
91 { 177, 29, 16 },
92 { 181, 28, 15 },
93 { 185, 27, 15 },
94 { 190, 26, 15 },
95 { 195, 25, 14 },
96 { 201, 24, 14 },
97 { 208, 23, 14 },
98 { 215, 22, 13 },
99 { 222, 21, 13 },
100 { 231, 20, 13 },
101 { 241, 19, 12 },
102 { 252, 18, 12 },
103 { 264, 17, 12 },
104 { 278, 16, 11 },
105 { 294, 15, 10 },
106 { 313, 14, 9 },
107 { 334, 13, 8 },
108 { 360, 12, 8 },
109 { 392, 11, 7 },
110 { 430, 10, 7 },
111 { 479, 9, 6 },
112 { 542, 8, 6 },
113 { 626, 7, 5 },
114 { 746, 6, 4 },
115 { 926, 5, 3 },
116 { 1232, 4, 2 },
117 { 1853, 3, 2 },
118 { 0, 0, 0 }
119 };
120
121 for(size_t i = 0; tests[i].bits; ++i)
122 {
123 if(bits <= tests[i].bits)
124 {
125 if(level >= 2)
126 return tests[i].verify_iter;
127 else if(level == 1)
128 return tests[i].check_iter;
129 else if(level == 0)
130 return std::max<size_t>(tests[i].check_iter / 4, 1);
131 }
132 }
133
134 return level > 0 ? 2 : 1; // for large inputs
135 }
136
137 }
138
139 /*
140 * Return the number of 0 bits at the end of n
141 */
142 size_t low_zero_bits(const BigInt& n)
143 {
144 size_t low_zero = 0;
145
146 if(n.is_positive() && n.is_nonzero())
147 {
148 for(size_t i = 0; i != n.size(); ++i)
149 {
150 word x = n[i];
151
152 if(x)
153 {
154 low_zero += ctz(x);
155 break;
156 }
157 else
158 low_zero += BOTAN_MP_WORD_BITS;
159 }
160 }
161
162 return low_zero;
163 }
164
165 /*
166 * Calculate the GCD
167 */
168 BigInt gcd(const BigInt& a, const BigInt& b)
169 {
170 if(a.is_zero() || b.is_zero()) return 0;
171 if(a == 1 || b == 1) return 1;
172
173 BigInt x = a, y = b;
174 x.set_sign(BigInt::Positive);
175 y.set_sign(BigInt::Positive);
176 size_t shift = std::min(low_zero_bits(x), low_zero_bits(y));
177
178 x >>= shift;
179 y >>= shift;
180
181 while(x.is_nonzero())
182 {
183 x >>= low_zero_bits(x);
184 y >>= low_zero_bits(y);
185 if(x >= y) { x -= y; x >>= 1; }
186 else { y -= x; y >>= 1; }
187 }
188
189 return (y << shift);
190 }
191
192 /*
193 * Calculate the LCM
194 */
195 BigInt lcm(const BigInt& a, const BigInt& b)
196 {
197 return ((a * b) / gcd(a, b));
198 }
199
200 namespace {
201
202 BigInt ct_inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod)
203 {
204 if(n.is_negative() || mod.is_negative())
205 throw Invalid_Argument("ct_inverse_mod_odd_modulus: arguments must be non-negative");
206 if(mod < 3 || mod.is_even())
207 throw Invalid_Argument("Bad modulus to ct_inverse_mod_odd_modulus");
208
209 /*
210 This uses a modular inversion algorithm designed by Niels Möller
211 and implemented in Nettle. The same algorithm was later also
212 adapted to GMP in mpn_sec_invert.
213
214 It can be easily implemented in a way that does not depend on
215 secret branches or memory lookups, providing resistance against
216 some forms of side channel attack.
217
218 There is also a description of the algorithm in Appendix 5 of "Fast
219 Software Polynomial Multiplication on ARM Processors using the NEON Engine"
220 by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo
221 Dahab in LNCS 8182
222 http://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf
223
224 Thanks to Niels for creating the algorithm, explaining some things
225 about it, and the reference to the paper.
226 */
227
228 // todo allow this to be pre-calculated and passed in as arg
229 BigInt mp1o2 = (mod + 1) >> 1;
230
231 const size_t mod_words = mod.sig_words();
232
233 BigInt a = n;
234 BigInt b = mod;
235 BigInt u = 1, v = 0;
236
237 a.grow_to(mod_words);
238 u.grow_to(mod_words);
239 v.grow_to(mod_words);
240 mp1o2.grow_to(mod_words);
241
242 SecureVector<word>& a_w = a.get_reg();
243 SecureVector<word>& b_w = b.get_reg();
244 SecureVector<word>& u_w = u.get_reg();
245 SecureVector<word>& v_w = v.get_reg();
246
247 // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n
248 size_t bits = 2 * mod.bits();
249
250 while(bits--)
251 {
252 #if 1
253 const word odd = a.is_odd();
254 a -= odd * b;
255 const word underflow = a.is_negative();
256 b += a * underflow;
257 a.set_sign(BigInt::Positive);
258
259 a >>= 1;
260
261 if(underflow)
262 {
263 std::swap(u, v);
264 }
265
266 u -= odd * v;
267 u += u.is_negative() * mod;
268
269 const word odd_u = u.is_odd();
270
271 u >>= 1;
272 u += mp1o2 * odd_u;
273 #else
274 const word odd_a = a_w[0] & 1;
275
276 //if(odd_a) a -= b
277 word underflow = bigint_cnd_sub(odd_a, a_w.begin(), b_w.begin(), mod_words);
278
279 //if(underflow) { b -= a; a = abs(a); swap(u, v); }
280 bigint_cnd_add(underflow, b_w.begin(), a_w.begin(), mod_words);
281 bigint_cnd_abs(underflow, a_w.begin(), mod_words);
282 bigint_cnd_swap(underflow, u_w.begin(), v_w.begin(), mod_words);
283
284 // a >>= 1
285 bigint_shr1(a_w.begin(), mod_words, 0, 1);
286
287 //if(odd_a) u -= v;
288 word borrow = bigint_cnd_sub(odd_a, u_w.begin(), v_w.begin(), mod_words);
289
290 // if(borrow) u += p
291 bigint_cnd_add(borrow, u_w.begin(), mod.data(), mod_words);
292
293 const word odd_u = u_w[0] & 1;
294
295 // u >>= 1
296 bigint_shr1(u_w.begin(), mod_words, 0, 1);
297
298 //if(odd_u) u += mp1o2;
299 bigint_cnd_add(odd_u, u_w.begin(), mp1o2.data(), mod_words);
300 #endif
301 }
302
303 if(b != 1)
304 return 0;
305
306 return v;
307 }
308
309 }
310
311 /*
312 * Find the Modular Inverse
313 */
314 BigInt inverse_mod(const BigInt& n, const BigInt& mod)
315 {
316 if(mod.is_zero())
317 throw BigInt::DivideByZero();
318 if(mod.is_negative() || n.is_negative())
319 throw Invalid_Argument("inverse_mod: arguments must be non-negative");
320
321 if(n.is_zero() || (n.is_even() && mod.is_even()))
322 return 0;
323
324 if(mod.is_odd())
325 return ct_inverse_mod_odd_modulus(n % mod, mod);
326
327 BigInt x = mod, y = n, u = mod, v = n;
328 BigInt A = 1, B = 0, C = 0, D = 1;
329
330 while(u.is_nonzero())
331 {
332 size_t zero_bits = low_zero_bits(u);
333 u >>= zero_bits;
334 for(size_t i = 0; i != zero_bits; ++i)
335 {
336 if(A.is_odd() || B.is_odd())
337 { A += y; B -= x; }
338 A >>= 1; B >>= 1;
339 }
340
341 zero_bits = low_zero_bits(v);
342 v >>= zero_bits;
343 for(size_t i = 0; i != zero_bits; ++i)
344 {
345 if(C.is_odd() || D.is_odd())
346 { C += y; D -= x; }
347 C >>= 1; D >>= 1;
348 }
349
350 if(u >= v) { u -= v; A -= C; B -= D; }
351 else { v -= u; C -= A; D -= B; }
352 }
353
354 if(v != 1)
355 return 0;
356
357 while(D.is_negative()) D += mod;
358 while(D >= mod) D -= mod;
359
360 return D;
361 }
362
363 /*
364 * Modular Exponentiation
365 */
366 BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod)
367 {
368 Power_Mod pow_mod(mod);
369 pow_mod.set_base(base);
370 pow_mod.set_exponent(exp);
371 return pow_mod.execute();
372 }
373
374 /*
375 * Test for primaility using Miller-Rabin
376 */
377 bool primality_test(const BigInt& n,
378 RandomNumberGenerator& rng,
379 size_t level)
380 {
381 const size_t PREF_NONCE_BITS = 128;
382
383 if(n == 2)
384 return true;
385 if(n <= 1 || n.is_even())
386 return false;
387
388 // Fast path testing for small numbers (<= 65521)
389 if(n <= PRIMES[PRIME_TABLE_SIZE-1])
390 {
391 const word num = n.word_at(0);
392
393 for(size_t i = 0; PRIMES[i]; ++i)
394 {
395 if(num == PRIMES[i])
396 return true;
397 if(num < PRIMES[i])
398 return false;
399 }
400
401 return false;
402 }
403
404 if(level > 2)
405 level = 2;
406
407 const size_t NONCE_BITS = std::min(n.bits() - 2, PREF_NONCE_BITS);
408
409 MillerRabin_Test mr(n);
410
411 if(mr.is_witness(2))
412 return false;
413
414 const size_t tests = miller_rabin_test_iterations(n.bits(), level);
415
416 for(size_t i = 0; i != tests; ++i)
417 {
418 BigInt nonce;
419 while(nonce < 2 || nonce >= (n-1))
420 nonce.randomize(rng, NONCE_BITS);
421
422 if(mr.is_witness(nonce))
423 return false;
424 }
425
426 return true;
427 }
428
429 }
Botan::PRIME_TABLE_SIZE
const size_t PRIME_TABLE_SIZE
Definition: numthry.h:220
Botan::bigint_shr1
void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
Definition: mp_shift.cpp:42
Botan::ctz
size_t ctz(T n)
Definition: bit_ops.h:93
Botan::Power_Mod::set_exponent
void set_exponent(const BigInt &) const
Definition: pow_mod.cpp:96
Botan::BigInt::is_negative
bool is_negative() const
Definition: bigint.h:245
Botan::BigInt
Definition: bigint.h:22
Botan::BigInt::Positive
Definition: bigint.h:33
Botan::RandomNumberGenerator
Definition: rng.h:20
Botan::BigInt::bits
size_t bits() const
Definition: bigint.cpp:254
Botan::gcd
BigInt gcd(const BigInt &a, const BigInt &b)
Definition: numthry.cpp:168
Botan::BigInt::is_zero
bool is_zero() const
Definition: bigint.h:176
Botan::Invalid_Argument
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
Botan::BigInt::is_even
bool is_even() const
Definition: bigint.h:158
Botan::BigInt::is_nonzero
bool is_nonzero() const
Definition: bigint.h:170
Botan::BigInt::word_at
word word_at(size_t n) const
Definition: bigint.h:238
Botan::primality_test
bool primality_test(const BigInt &n, RandomNumberGenerator &rng, size_t level)
Definition: numthry.cpp:377
Botan::BigInt::randomize
void randomize(RandomNumberGenerator &rng, size_t bitsize=0)
Definition: big_rand.cpp:29
Botan::bigint_cnd_sub
word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size)
Definition: mp_asm.cpp:64
Botan::Power_Mod
Definition: pow_mod.h:31
Botan::bigint_cnd_swap
void bigint_cnd_swap(word cnd, word x[], word y[], size_t size)
Definition: mp_asm.cpp:25
Botan::BigInt::is_odd
bool is_odd() const
Definition: bigint.h:164
Botan::BigInt::size
size_t size() const
Definition: bigint.h:284
Botan
Definition: algo_base.h:14
Botan::low_zero_bits
size_t low_zero_bits(const BigInt &n)
Definition: numthry.cpp:142
Botan::Power_Mod::execute
BigInt execute() const
Definition: pow_mod.cpp:109
Botan::inverse_mod
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition: numthry.cpp:314
Botan::power_mod
BigInt power_mod(const BigInt &base, const BigInt &exp, const BigInt &mod)
Definition: numthry.cpp:366
Botan::bigint_cnd_add
word bigint_cnd_add(word cnd, word x[], const word y[], size_t size)
Definition: mp_asm.cpp:42
Botan::CT::min
T min(T a, T b)
Definition: ct_utils.h:127
Botan::Power_Mod::set_base
void set_base(const BigInt &) const
Definition: pow_mod.cpp:83
Botan::PRIMES
const u16bit BOTAN_DLL PRIMES[]
Definition: primes.cpp:12
std::swap
void swap(Botan::MemoryRegion< T > &x, Botan::MemoryRegion< T > &y)
Definition: secmem.h:438
Botan::bigint_cnd_abs
void bigint_cnd_abs(word cnd, word x[], size_t size)
Definition: mp_asm.cpp:78
Botan::BigInt::set_sign
void set_sign(Sign sign)
Definition: bigint.cpp:292
Botan::lcm
BigInt lcm(const BigInt &a, const BigInt &b)
Definition: numthry.cpp:195
Botan::Modular_Reducer::square
BigInt square(const BigInt &x) const
Definition: reducer.h:39
Botan::BigInt::DivideByZero
Definition: bigint.h:43
Botan::BigInt::is_positive
bool is_positive() const
Definition: bigint.h:251