Coverage Report

Created: 2020-03-26 13:53

/src/botan/src/lib/math/numbertheory/mod_inv.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 1999-2011,2016,2018,2019,2020 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6
7
#include <botan/numthry.h>
8
#include <botan/divide.h>
9
#include <botan/internal/ct_utils.h>
10
#include <botan/internal/mp_core.h>
11
#include <botan/internal/rounding.h>
12
13
namespace Botan {
14
15
/*
16
Sets result to a^-1 * 2^k mod a
17
with n <= k <= 2n
18
Returns k
19
20
"The Montgomery Modular Inverse - Revisited" Çetin Koç, E. Savas
21
https://citeseerx.ist.psu.edu/viewdoc/citations?doi=10.1.1.75.8377
22
23
A const time implementation of this algorithm is described in
24
"Constant Time Modular Inversion" Joppe W. Bos
25
http://www.joppebos.com/files/CTInversion.pdf
26
*/
27
size_t almost_montgomery_inverse(BigInt& result,
28
                                 const BigInt& a,
29
                                 const BigInt& p)
30
0
   {
31
0
   size_t k = 0;
32
0
33
0
   BigInt u = p, v = a, r = 0, s = 1;
34
0
35
0
   while(v > 0)
36
0
      {
37
0
      if(u.is_even())
38
0
         {
39
0
         u >>= 1;
40
0
         s <<= 1;
41
0
         }
42
0
      else if(v.is_even())
43
0
         {
44
0
         v >>= 1;
45
0
         r <<= 1;
46
0
         }
47
0
      else if(u > v)
48
0
         {
49
0
         u -= v;
50
0
         u >>= 1;
51
0
         r += s;
52
0
         s <<= 1;
53
0
         }
54
0
      else
55
0
         {
56
0
         v -= u;
57
0
         v >>= 1;
58
0
         s += r;
59
0
         r <<= 1;
60
0
         }
61
0
62
0
      ++k;
63
0
      }
64
0
65
0
   if(r >= p)
66
0
      {
67
0
      r -= p;
68
0
      }
69
0
70
0
   result = p - r;
71
0
72
0
   return k;
73
0
   }
74
75
BigInt normalized_montgomery_inverse(const BigInt& a, const BigInt& p)
76
0
   {
77
0
   BigInt r;
78
0
   size_t k = almost_montgomery_inverse(r, a, p);
79
0
80
0
   for(size_t i = 0; i != k; ++i)
81
0
      {
82
0
      if(r.is_odd())
83
0
         r += p;
84
0
      r >>= 1;
85
0
      }
86
0
87
0
   return r;
88
0
   }
89
90
namespace {
91
92
BigInt inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod)
93
47.5k
   {
94
47.5k
   // Caller should assure these preconditions:
95
47.5k
   BOTAN_DEBUG_ASSERT(n.is_positive());
96
47.5k
   BOTAN_DEBUG_ASSERT(mod.is_positive());
97
47.5k
   BOTAN_DEBUG_ASSERT(n < mod);
98
47.5k
   BOTAN_DEBUG_ASSERT(mod >= 3 && mod.is_odd());
99
47.5k
100
47.5k
   /*
101
47.5k
   This uses a modular inversion algorithm designed by Niels Möller
102
47.5k
   and implemented in Nettle. The same algorithm was later also
103
47.5k
   adapted to GMP in mpn_sec_invert.
104
47.5k
105
47.5k
   It can be easily implemented in a way that does not depend on
106
47.5k
   secret branches or memory lookups, providing resistance against
107
47.5k
   some forms of side channel attack.
108
47.5k
109
47.5k
   There is also a description of the algorithm in Appendix 5 of "Fast
110
47.5k
   Software Polynomial Multiplication on ARM Processors using the NEON Engine"
111
47.5k
   by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo
112
47.5k
   Dahab in LNCS 8182
113
47.5k
      https://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf
114
47.5k
115
47.5k
   Thanks to Niels for creating the algorithm, explaining some things
116
47.5k
   about it, and the reference to the paper.
117
47.5k
   */
118
47.5k
119
47.5k
   const size_t mod_words = mod.sig_words();
120
47.5k
   BOTAN_ASSERT(mod_words > 0, "Not empty");
121
47.5k
122
47.5k
   secure_vector<word> tmp_mem(5*mod_words);
123
47.5k
124
47.5k
   word* v_w = &tmp_mem[0];
125
47.5k
   word* u_w = &tmp_mem[1*mod_words];
126
47.5k
   word* b_w = &tmp_mem[2*mod_words];
127
47.5k
   word* a_w = &tmp_mem[3*mod_words];
128
47.5k
   word* mp1o2 = &tmp_mem[4*mod_words];
129
47.5k
130
47.5k
   CT::poison(tmp_mem.data(), tmp_mem.size());
131
47.5k
132
47.5k
   copy_mem(a_w, n.data(), std::min(n.size(), mod_words));
133
47.5k
   copy_mem(b_w, mod.data(), std::min(mod.size(), mod_words));
134
47.5k
   u_w[0] = 1;
135
47.5k
   // v_w = 0
136
47.5k
137
47.5k
   // compute (mod + 1) / 2 which [because mod is odd] is equal to
138
47.5k
   // (mod / 2) + 1
139
47.5k
   copy_mem(mp1o2, mod.data(), std::min(mod.size(), mod_words));
140
47.5k
   bigint_shr1(mp1o2, mod_words, 0, 1);
141
47.5k
   word carry = bigint_add2_nc(mp1o2, mod_words, u_w, 1);
142
47.5k
   BOTAN_ASSERT_NOMSG(carry == 0);
143
47.5k
144
47.5k
   // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n
145
47.5k
   const size_t execs = 2 * mod.bits();
146
47.5k
147
41.7M
   for(size_t i = 0; i != execs; ++i)
148
41.6M
      {
149
41.6M
      const word odd_a = a_w[0] & 1;
150
41.6M
151
41.6M
      //if(odd_a) a -= b
152
41.6M
      word underflow = bigint_cnd_sub(odd_a, a_w, b_w, mod_words);
153
41.6M
154
41.6M
      //if(underflow) { b -= a; a = abs(a); swap(u, v); }
155
41.6M
      bigint_cnd_add(underflow, b_w, a_w, mod_words);
156
41.6M
      bigint_cnd_abs(underflow, a_w, mod_words);
157
41.6M
      bigint_cnd_swap(underflow, u_w, v_w, mod_words);
158
41.6M
159
41.6M
      // a >>= 1
160
41.6M
      bigint_shr1(a_w, mod_words, 0, 1);
161
41.6M
162
41.6M
      //if(odd_a) u -= v;
163
41.6M
      word borrow = bigint_cnd_sub(odd_a, u_w, v_w, mod_words);
164
41.6M
165
41.6M
      // if(borrow) u += p
166
41.6M
      bigint_cnd_add(borrow, u_w, mod.data(), mod_words);
167
41.6M
168
41.6M
      const word odd_u = u_w[0] & 1;
169
41.6M
170
41.6M
      // u >>= 1
171
41.6M
      bigint_shr1(u_w, mod_words, 0, 1);
172
41.6M
173
41.6M
      //if(odd_u) u += mp1o2;
174
41.6M
      bigint_cnd_add(odd_u, u_w, mp1o2, mod_words);
175
41.6M
      }
176
47.5k
177
47.5k
   auto a_is_0 = CT::Mask<word>::set();
178
378k
   for(size_t i = 0; i != mod_words; ++i)
179
330k
      a_is_0 &= CT::Mask<word>::is_zero(a_w[i]);
180
47.5k
181
47.5k
   auto b_is_1 = CT::Mask<word>::is_equal(b_w[0], 1);
182
330k
   for(size_t i = 1; i != mod_words; ++i)
183
283k
      b_is_1 &= CT::Mask<word>::is_zero(b_w[i]);
184
47.5k
185
47.5k
   BOTAN_ASSERT(a_is_0.is_set(), "A is zero");
186
47.5k
187
47.5k
   // if b != 1 then gcd(n,mod) > 1 and inverse does not exist
188
47.5k
   // in which case zero out the result to indicate this
189
47.5k
   (~b_is_1).if_set_zero_out(v_w, mod_words);
190
47.5k
191
47.5k
   /*
192
47.5k
   * We've placed the result in the lowest words of the temp buffer.
193
47.5k
   * So just clear out the other values and then give that buffer to a
194
47.5k
   * BigInt.
195
47.5k
   */
196
47.5k
   clear_mem(&tmp_mem[mod_words], 4*mod_words);
197
47.5k
198
47.5k
   CT::unpoison(tmp_mem.data(), tmp_mem.size());
199
47.5k
200
47.5k
   BigInt r;
201
47.5k
   r.swap_reg(tmp_mem);
202
47.5k
   return r;
203
47.5k
   }
204
205
BigInt inverse_mod_pow2(const BigInt& a1, size_t k)
206
1.13k
   {
207
1.13k
   /*
208
1.13k
   * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç
209
1.13k
   * https://eprint.iacr.org/2017/411.pdf sections 5 and 7.
210
1.13k
   */
211
1.13k
212
1.13k
   if(a1.is_even())
213
0
      return 0;
214
1.13k
215
1.13k
   BigInt a = a1;
216
1.13k
   a.mask_bits(k);
217
1.13k
218
1.13k
   BigInt b = 1;
219
1.13k
   BigInt X = 0;
220
1.13k
   BigInt newb;
221
1.13k
222
1.13k
   const size_t a_words = a.sig_words();
223
1.13k
224
1.13k
   X.grow_to(round_up(k, BOTAN_MP_WORD_BITS) / BOTAN_MP_WORD_BITS);
225
1.13k
   b.grow_to(a_words);
226
1.13k
227
1.13k
   /*
228
1.13k
   Hide the exact value of k. k is anyway known to word length
229
1.13k
   granularity because of the length of a, so no point in doing more
230
1.13k
   than this.
231
1.13k
   */
232
1.13k
   const size_t iter = round_up(k, BOTAN_MP_WORD_BITS);
233
1.13k
234
596k
   for(size_t i = 0; i != iter; ++i)
235
595k
      {
236
595k
      const bool b0 = b.get_bit(0);
237
595k
      X.conditionally_set_bit(i, b0);
238
595k
      newb = b - a;
239
595k
      b.ct_cond_assign(b0, newb);
240
595k
      b >>= 1;
241
595k
      }
242
1.13k
243
1.13k
   X.mask_bits(k);
244
1.13k
   X.const_time_unpoison();
245
1.13k
   return X;
246
1.13k
   }
247
248
}
249
250
BigInt inverse_mod(const BigInt& n, const BigInt& mod)
251
47.7k
   {
252
47.7k
   if(mod.is_zero())
253
0
      throw BigInt::DivideByZero();
254
47.7k
   if(mod.is_negative() || n.is_negative())
255
0
      throw Invalid_Argument("inverse_mod: arguments must be non-negative");
256
47.7k
   if(n.is_zero() || (n.is_even() && mod.is_even()))
257
182
      return 0;
258
47.6k
259
47.6k
   if(mod.is_odd())
260
46.9k
      {
261
46.9k
      /*
262
46.9k
      Fastpath for common case. This leaks information if n > mod
263
46.9k
      but we don't guarantee const time behavior in that case.
264
46.9k
      */
265
46.9k
      if(n < mod)
266
46.8k
         return inverse_mod_odd_modulus(n, mod);
267
70
      else
268
70
         return inverse_mod_odd_modulus(ct_modulo(n, mod), mod);
269
647
      }
270
647
271
647
   const size_t mod_lz = low_zero_bits(mod);
272
647
   BOTAN_ASSERT_NOMSG(mod_lz > 0);
273
647
   const size_t mod_bits = mod.bits();
274
647
   BOTAN_ASSERT_NOMSG(mod_bits > mod_lz);
275
647
276
647
   if(mod_lz == mod_bits - 1)
277
50
      {
278
50
      // In this case we are performing an inversion modulo 2^k
279
50
      return inverse_mod_pow2(n, mod_lz);
280
50
      }
281
597
282
597
   /*
283
597
   * In this case we are performing an inversion modulo 2^k*o for
284
597
   * some k > 1 and some odd (not necessarily prime) integer.
285
597
   * Compute the inversions modulo 2^k and modulo o, then combine them
286
597
   * using CRT, which is possible because 2^k and o are relatively prime.
287
597
   */
288
597
289
597
   const BigInt o = mod >> mod_lz;
290
597
   const BigInt n_redc = ct_modulo(n, o);
291
597
   const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
292
597
   const BigInt inv_2k = inverse_mod_pow2(n, mod_lz);
293
597
294
597
   // No modular inverse in this case:
295
597
   if(inv_o == 0 || inv_2k == 0)
296
105
      return 0;
297
492
298
492
   const BigInt m2k = BigInt::power_of_2(mod_lz);
299
492
   // Compute the CRT parameter
300
492
   const BigInt c = inverse_mod_pow2(o, mod_lz);
301
492
302
492
   // Compute h = c*(inv_2k-inv_o) mod 2^k
303
492
   BigInt h = c * (inv_2k - inv_o);
304
492
   const bool h_neg = h.is_negative();
305
492
   h.set_sign(BigInt::Positive);
306
492
   h.mask_bits(mod_lz);
307
492
   const bool h_nonzero = h.is_nonzero();
308
492
   h.ct_cond_assign(h_nonzero && h_neg, m2k - h);
309
492
310
492
   // Return result inv_o + h * o
311
492
   h *= o;
312
492
   h += inv_o;
313
492
   return h;
314
492
   }
315
316
// Deprecated forwarding functions:
317
BigInt inverse_euclid(const BigInt& x, const BigInt& modulus)
318
0
   {
319
0
   return inverse_mod(x, modulus);
320
0
   }
321
322
BigInt ct_inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod)
323
0
   {
324
0
   return inverse_mod_odd_modulus(n, mod);
325
0
   }
326
327
word monty_inverse(word a)
328
84.1k
   {
329
84.1k
   if(a % 2 == 0)
330
0
      throw Invalid_Argument("monty_inverse only valid for odd integers");
331
84.1k
332
84.1k
   /*
333
84.1k
   * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç
334
84.1k
   * https://eprint.iacr.org/2017/411.pdf sections 5 and 7.
335
84.1k
   */
336
84.1k
337
84.1k
   word b = 1;
338
84.1k
   word r = 0;
339
84.1k
340
5.46M
   for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i)
341
5.38M
      {
342
5.38M
      const word bi = b % 2;
343
5.38M
      r >>= 1;
344
5.38M
      r += bi << (BOTAN_MP_WORD_BITS - 1);
345
5.38M
346
5.38M
      b -= a * bi;
347
5.38M
      b >>= 1;
348
5.38M
      }
349
84.1k
350
84.1k
   // Now invert in addition space
351
84.1k
   r = (MP_WORD_MAX - r) + 1;
352
84.1k
353
84.1k
   return r;
354
84.1k
   }
355
356
}