Coverage Report

Created: 2020-10-17 06:46

/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
50.1k
   {
94
   // Caller should assure these preconditions:
95
50.1k
   BOTAN_DEBUG_ASSERT(n.is_positive());
96
50.1k
   BOTAN_DEBUG_ASSERT(mod.is_positive());
97
50.1k
   BOTAN_DEBUG_ASSERT(n < mod);
98
50.1k
   BOTAN_DEBUG_ASSERT(mod >= 3 && mod.is_odd());
99
50.1k
100
   /*
101
   This uses a modular inversion algorithm designed by Niels Möller
102
   and implemented in Nettle. The same algorithm was later also
103
   adapted to GMP in mpn_sec_invert.
104
105
   It can be easily implemented in a way that does not depend on
106
   secret branches or memory lookups, providing resistance against
107
   some forms of side channel attack.
108
109
   There is also a description of the algorithm in Appendix 5 of "Fast
110
   Software Polynomial Multiplication on ARM Processors using the NEON Engine"
111
   by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo
112
   Dahab in LNCS 8182
113
      https://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf
114
115
   Thanks to Niels for creating the algorithm, explaining some things
116
   about it, and the reference to the paper.
117
   */
118
50.1k
119
50.1k
   const size_t mod_words = mod.sig_words();
120
50.1k
   BOTAN_ASSERT(mod_words > 0, "Not empty");
121
50.1k
122
50.1k
   secure_vector<word> tmp_mem(5*mod_words);
123
50.1k
124
50.1k
   word* v_w = &tmp_mem[0];
125
50.1k
   word* u_w = &tmp_mem[1*mod_words];
126
50.1k
   word* b_w = &tmp_mem[2*mod_words];
127
50.1k
   word* a_w = &tmp_mem[3*mod_words];
128
50.1k
   word* mp1o2 = &tmp_mem[4*mod_words];
129
50.1k
130
50.1k
   CT::poison(tmp_mem.data(), tmp_mem.size());
131
50.1k
132
50.1k
   copy_mem(a_w, n.data(), std::min(n.size(), mod_words));
133
50.1k
   copy_mem(b_w, mod.data(), std::min(mod.size(), mod_words));
134
50.1k
   u_w[0] = 1;
135
   // v_w = 0
136
50.1k
137
   // compute (mod + 1) / 2 which [because mod is odd] is equal to
138
   // (mod / 2) + 1
139
50.1k
   copy_mem(mp1o2, mod.data(), std::min(mod.size(), mod_words));
140
50.1k
   bigint_shr1(mp1o2, mod_words, 0, 1);
141
50.1k
   word carry = bigint_add2_nc(mp1o2, mod_words, u_w, 1);
142
50.1k
   BOTAN_ASSERT_NOMSG(carry == 0);
143
50.1k
144
   // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n
145
50.1k
   const size_t execs = 2 * mod.bits();
146
50.1k
147
42.7M
   for(size_t i = 0; i != execs; ++i)
148
42.7M
      {
149
42.7M
      const word odd_a = a_w[0] & 1;
150
42.7M
151
      //if(odd_a) a -= b
152
42.7M
      word underflow = bigint_cnd_sub(odd_a, a_w, b_w, mod_words);
153
42.7M
154
      //if(underflow) { b -= a; a = abs(a); swap(u, v); }
155
42.7M
      bigint_cnd_add(underflow, b_w, a_w, mod_words);
156
42.7M
      bigint_cnd_abs(underflow, a_w, mod_words);
157
42.7M
      bigint_cnd_swap(underflow, u_w, v_w, mod_words);
158
42.7M
159
      // a >>= 1
160
42.7M
      bigint_shr1(a_w, mod_words, 0, 1);
161
42.7M
162
      //if(odd_a) u -= v;
163
42.7M
      word borrow = bigint_cnd_sub(odd_a, u_w, v_w, mod_words);
164
42.7M
165
      // if(borrow) u += p
166
42.7M
      bigint_cnd_add(borrow, u_w, mod.data(), mod_words);
167
42.7M
168
42.7M
      const word odd_u = u_w[0] & 1;
169
42.7M
170
      // u >>= 1
171
42.7M
      bigint_shr1(u_w, mod_words, 0, 1);
172
42.7M
173
      //if(odd_u) u += mp1o2;
174
42.7M
      bigint_cnd_add(odd_u, u_w, mp1o2, mod_words);
175
42.7M
      }
176
50.1k
177
50.1k
   auto a_is_0 = CT::Mask<word>::set();
178
389k
   for(size_t i = 0; i != mod_words; ++i)
179
339k
      a_is_0 &= CT::Mask<word>::is_zero(a_w[i]);
180
50.1k
181
50.1k
   auto b_is_1 = CT::Mask<word>::is_equal(b_w[0], 1);
182
339k
   for(size_t i = 1; i != mod_words; ++i)
183
289k
      b_is_1 &= CT::Mask<word>::is_zero(b_w[i]);
184
50.1k
185
50.1k
   BOTAN_ASSERT(a_is_0.is_set(), "A is zero");
186
50.1k
187
   // if b != 1 then gcd(n,mod) > 1 and inverse does not exist
188
   // in which case zero out the result to indicate this
189
50.1k
   (~b_is_1).if_set_zero_out(v_w, mod_words);
190
50.1k
191
   /*
192
   * We've placed the result in the lowest words of the temp buffer.
193
   * So just clear out the other values and then give that buffer to a
194
   * BigInt.
195
   */
196
50.1k
   clear_mem(&tmp_mem[mod_words], 4*mod_words);
197
50.1k
198
50.1k
   CT::unpoison(tmp_mem.data(), tmp_mem.size());
199
50.1k
200
50.1k
   BigInt r;
201
50.1k
   r.swap_reg(tmp_mem);
202
50.1k
   return r;
203
50.1k
   }
204
205
BigInt inverse_mod_pow2(const BigInt& a1, size_t k)
206
1.17k
   {
207
   /*
208
   * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç
209
   * https://eprint.iacr.org/2017/411.pdf sections 5 and 7.
210
   */
211
1.17k
212
1.17k
   if(a1.is_even())
213
0
      return 0;
214
1.17k
215
1.17k
   BigInt a = a1;
216
1.17k
   a.mask_bits(k);
217
1.17k
218
1.17k
   BigInt b = 1;
219
1.17k
   BigInt X = 0;
220
1.17k
   BigInt newb;
221
1.17k
222
1.17k
   const size_t a_words = a.sig_words();
223
1.17k
224
1.17k
   X.grow_to(round_up(k, BOTAN_MP_WORD_BITS) / BOTAN_MP_WORD_BITS);
225
1.17k
   b.grow_to(a_words);
226
1.17k
227
   /*
228
   Hide the exact value of k. k is anyway known to word length
229
   granularity because of the length of a, so no point in doing more
230
   than this.
231
   */
232
1.17k
   const size_t iter = round_up(k, BOTAN_MP_WORD_BITS);
233
1.17k
234
684k
   for(size_t i = 0; i != iter; ++i)
235
683k
      {
236
683k
      const bool b0 = b.get_bit(0);
237
683k
      X.conditionally_set_bit(i, b0);
238
683k
      newb = b - a;
239
683k
      b.ct_cond_assign(b0, newb);
240
683k
      b >>= 1;
241
683k
      }
242
1.17k
243
1.17k
   X.mask_bits(k);
244
1.17k
   X.const_time_unpoison();
245
1.17k
   return X;
246
1.17k
   }
247
248
}
249
250
BigInt inverse_mod(const BigInt& n, const BigInt& mod)
251
50.3k
   {
252
50.3k
   if(mod.is_zero())
253
0
      throw BigInt::DivideByZero();
254
50.3k
   if(mod.is_negative() || n.is_negative())
255
0
      throw Invalid_Argument("inverse_mod: arguments must be non-negative");
256
50.3k
   if(n.is_zero() || (n.is_even() && mod.is_even()))
257
178
      return 0;
258
50.2k
259
50.2k
   if(mod.is_odd())
260
49.5k
      {
261
      /*
262
      Fastpath for common case. This leaks information if n > mod
263
      but we don't guarantee const time behavior in that case.
264
      */
265
49.5k
      if(n < mod)
266
49.4k
         return inverse_mod_odd_modulus(n, mod);
267
73
      else
268
73
         return inverse_mod_odd_modulus(ct_modulo(n, mod), mod);
269
665
      }
270
665
271
665
   const size_t mod_lz = low_zero_bits(mod);
272
665
   BOTAN_ASSERT_NOMSG(mod_lz > 0);
273
665
   const size_t mod_bits = mod.bits();
274
665
   BOTAN_ASSERT_NOMSG(mod_bits > mod_lz);
275
665
276
665
   if(mod_lz == mod_bits - 1)
277
56
      {
278
      // In this case we are performing an inversion modulo 2^k
279
56
      return inverse_mod_pow2(n, mod_lz);
280
56
      }
281
609
282
   /*
283
   * In this case we are performing an inversion modulo 2^k*o for
284
   * some k > 1 and some odd (not necessarily prime) integer.
285
   * Compute the inversions modulo 2^k and modulo o, then combine them
286
   * using CRT, which is possible because 2^k and o are relatively prime.
287
   */
288
609
289
609
   const BigInt o = mod >> mod_lz;
290
609
   const BigInt n_redc = ct_modulo(n, o);
291
609
   const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
292
609
   const BigInt inv_2k = inverse_mod_pow2(n, mod_lz);
293
609
294
   // No modular inverse in this case:
295
609
   if(inv_o == 0 || inv_2k == 0)
296
98
      return 0;
297
511
298
511
   const BigInt m2k = BigInt::power_of_2(mod_lz);
299
   // Compute the CRT parameter
300
511
   const BigInt c = inverse_mod_pow2(o, mod_lz);
301
511
302
   // Compute h = c*(inv_2k-inv_o) mod 2^k
303
511
   BigInt h = c * (inv_2k - inv_o);
304
511
   const bool h_neg = h.is_negative();
305
511
   h.set_sign(BigInt::Positive);
306
511
   h.mask_bits(mod_lz);
307
511
   const bool h_nonzero = h.is_nonzero();
308
511
   h.ct_cond_assign(h_nonzero && h_neg, m2k - h);
309
511
310
   // Return result inv_o + h * o
311
511
   h *= o;
312
511
   h += inv_o;
313
511
   return h;
314
511
   }
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
87.9k
   {
329
87.9k
   if(a % 2 == 0)
330
0
      throw Invalid_Argument("monty_inverse only valid for odd integers");
331
87.9k
332
   /*
333
   * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç
334
   * https://eprint.iacr.org/2017/411.pdf sections 5 and 7.
335
   */
336
87.9k
337
87.9k
   word b = 1;
338
87.9k
   word r = 0;
339
87.9k
340
5.71M
   for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i)
341
5.62M
      {
342
5.62M
      const word bi = b % 2;
343
5.62M
      r >>= 1;
344
5.62M
      r += bi << (BOTAN_MP_WORD_BITS - 1);
345
5.62M
346
5.62M
      b -= a * bi;
347
5.62M
      b >>= 1;
348
5.62M
      }
349
87.9k
350
   // Now invert in addition space
351
87.9k
   r = (MP_WORD_MAX - r) + 1;
352
87.9k
353
87.9k
   return r;
354
87.9k
   }
355
356
}