Coverage Report

Created: 2023-06-07 07:00

/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
9
#include <botan/internal/ct_utils.h>
10
#include <botan/internal/divide.h>
11
#include <botan/internal/mp_core.h>
12
#include <botan/internal/rounding.h>
13
14
namespace Botan {
15
16
namespace {
17
18
0
BigInt inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) {
19
   // Caller should assure these preconditions:
20
0
   BOTAN_DEBUG_ASSERT(n.is_positive());
21
0
   BOTAN_DEBUG_ASSERT(mod.is_positive());
22
0
   BOTAN_DEBUG_ASSERT(n < mod);
23
0
   BOTAN_DEBUG_ASSERT(mod >= 3 && mod.is_odd());
24
25
   /*
26
   This uses a modular inversion algorithm designed by Niels Möller
27
   and implemented in Nettle. The same algorithm was later also
28
   adapted to GMP in mpn_sec_invert.
29
30
   It can be easily implemented in a way that does not depend on
31
   secret branches or memory lookups, providing resistance against
32
   some forms of side channel attack.
33
34
   There is also a description of the algorithm in Appendix 5 of "Fast
35
   Software Polynomial Multiplication on ARM Processors using the NEON Engine"
36
   by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo
37
   Dahab in LNCS 8182
38
      https://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf
39
40
   Thanks to Niels for creating the algorithm, explaining some things
41
   about it, and the reference to the paper.
42
   */
43
44
0
   const size_t mod_words = mod.sig_words();
45
0
   BOTAN_ASSERT(mod_words > 0, "Not empty");
46
47
0
   secure_vector<word> tmp_mem(5 * mod_words);
48
49
0
   word* v_w = &tmp_mem[0];
50
0
   word* u_w = &tmp_mem[1 * mod_words];
51
0
   word* b_w = &tmp_mem[2 * mod_words];
52
0
   word* a_w = &tmp_mem[3 * mod_words];
53
0
   word* mp1o2 = &tmp_mem[4 * mod_words];
54
55
0
   CT::poison(tmp_mem.data(), tmp_mem.size());
56
57
0
   copy_mem(a_w, n.data(), std::min(n.size(), mod_words));
58
0
   copy_mem(b_w, mod.data(), std::min(mod.size(), mod_words));
59
0
   u_w[0] = 1;
60
   // v_w = 0
61
62
   // compute (mod + 1) / 2 which [because mod is odd] is equal to
63
   // (mod / 2) + 1
64
0
   copy_mem(mp1o2, mod.data(), std::min(mod.size(), mod_words));
65
0
   bigint_shr1(mp1o2, mod_words, 0, 1);
66
0
   word carry = bigint_add2_nc(mp1o2, mod_words, u_w, 1);
67
0
   BOTAN_ASSERT_NOMSG(carry == 0);
68
69
   // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n
70
0
   const size_t execs = 2 * mod.bits();
71
72
0
   for(size_t i = 0; i != execs; ++i) {
73
0
      const word odd_a = a_w[0] & 1;
74
75
      //if(odd_a) a -= b
76
0
      word underflow = bigint_cnd_sub(odd_a, a_w, b_w, mod_words);
77
78
      //if(underflow) { b -= a; a = abs(a); swap(u, v); }
79
0
      bigint_cnd_add(underflow, b_w, a_w, mod_words);
80
0
      bigint_cnd_abs(underflow, a_w, mod_words);
81
0
      bigint_cnd_swap(underflow, u_w, v_w, mod_words);
82
83
      // a >>= 1
84
0
      bigint_shr1(a_w, mod_words, 0, 1);
85
86
      //if(odd_a) u -= v;
87
0
      word borrow = bigint_cnd_sub(odd_a, u_w, v_w, mod_words);
88
89
      // if(borrow) u += p
90
0
      bigint_cnd_add(borrow, u_w, mod.data(), mod_words);
91
92
0
      const word odd_u = u_w[0] & 1;
93
94
      // u >>= 1
95
0
      bigint_shr1(u_w, mod_words, 0, 1);
96
97
      //if(odd_u) u += mp1o2;
98
0
      bigint_cnd_add(odd_u, u_w, mp1o2, mod_words);
99
0
   }
100
101
0
   auto a_is_0 = CT::Mask<word>::set();
102
0
   for(size_t i = 0; i != mod_words; ++i) {
103
0
      a_is_0 &= CT::Mask<word>::is_zero(a_w[i]);
104
0
   }
105
106
0
   auto b_is_1 = CT::Mask<word>::is_equal(b_w[0], 1);
107
0
   for(size_t i = 1; i != mod_words; ++i) {
108
0
      b_is_1 &= CT::Mask<word>::is_zero(b_w[i]);
109
0
   }
110
111
0
   BOTAN_ASSERT(a_is_0.is_set(), "A is zero");
112
113
   // if b != 1 then gcd(n,mod) > 1 and inverse does not exist
114
   // in which case zero out the result to indicate this
115
0
   (~b_is_1).if_set_zero_out(v_w, mod_words);
116
117
   /*
118
   * We've placed the result in the lowest words of the temp buffer.
119
   * So just clear out the other values and then give that buffer to a
120
   * BigInt.
121
   */
122
0
   clear_mem(&tmp_mem[mod_words], 4 * mod_words);
123
124
0
   CT::unpoison(tmp_mem.data(), tmp_mem.size());
125
126
0
   BigInt r;
127
0
   r.swap_reg(tmp_mem);
128
0
   return r;
129
0
}
130
131
0
BigInt inverse_mod_pow2(const BigInt& a1, size_t k) {
132
   /*
133
   * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç
134
   * https://eprint.iacr.org/2017/411.pdf sections 5 and 7.
135
   */
136
137
0
   if(a1.is_even() || k == 0) {
138
0
      return BigInt::zero();
139
0
   }
140
0
   if(k == 1) {
141
0
      return BigInt::one();
142
0
   }
143
144
0
   BigInt a = a1;
145
0
   a.mask_bits(k);
146
147
0
   BigInt b = BigInt::one();
148
0
   BigInt X = BigInt::zero();
149
0
   BigInt newb;
150
151
0
   const size_t a_words = a.sig_words();
152
153
0
   X.grow_to(round_up(k, BOTAN_MP_WORD_BITS) / BOTAN_MP_WORD_BITS);
154
0
   b.grow_to(a_words);
155
156
   /*
157
   Hide the exact value of k. k is anyway known to word length
158
   granularity because of the length of a, so no point in doing more
159
   than this.
160
   */
161
0
   const size_t iter = round_up(k, BOTAN_MP_WORD_BITS);
162
163
0
   for(size_t i = 0; i != iter; ++i) {
164
0
      const bool b0 = b.get_bit(0);
165
0
      X.conditionally_set_bit(i, b0);
166
0
      newb = b - a;
167
0
      b.ct_cond_assign(b0, newb);
168
0
      b >>= 1;
169
0
   }
170
171
0
   X.mask_bits(k);
172
0
   X.const_time_unpoison();
173
0
   return X;
174
0
}
175
176
}  // namespace
177
178
0
BigInt inverse_mod(const BigInt& n, const BigInt& mod) {
179
0
   if(mod.is_zero()) {
180
0
      throw Invalid_Argument("inverse_mod modulus cannot be zero");
181
0
   }
182
0
   if(mod.is_negative() || n.is_negative()) {
183
0
      throw Invalid_Argument("inverse_mod: arguments must be non-negative");
184
0
   }
185
0
   if(n.is_zero() || (n.is_even() && mod.is_even())) {
186
0
      return BigInt::zero();
187
0
   }
188
189
0
   if(mod.is_odd()) {
190
      /*
191
      Fastpath for common case. This leaks if n is greater than mod or
192
      not, but we don't guarantee const time behavior in that case.
193
      */
194
0
      if(n < mod) {
195
0
         return inverse_mod_odd_modulus(n, mod);
196
0
      } else {
197
0
         return inverse_mod_odd_modulus(ct_modulo(n, mod), mod);
198
0
      }
199
0
   }
200
201
   // If n is even and mod is even we already returned 0
202
   // If n is even and mod is odd we jumped directly to odd-modulus algo
203
0
   BOTAN_DEBUG_ASSERT(n.is_odd());
204
205
0
   const size_t mod_lz = low_zero_bits(mod);
206
0
   BOTAN_ASSERT_NOMSG(mod_lz > 0);
207
0
   const size_t mod_bits = mod.bits();
208
0
   BOTAN_ASSERT_NOMSG(mod_bits > mod_lz);
209
210
0
   if(mod_lz == mod_bits - 1) {
211
      // In this case we are performing an inversion modulo 2^k
212
0
      return inverse_mod_pow2(n, mod_lz);
213
0
   }
214
215
0
   if(mod_lz == 1) {
216
      /*
217
      Inversion modulo 2*o is an easier special case of CRT
218
219
      This is exactly the main CRT flow below but taking advantage of
220
      the fact that any odd number ^-1 modulo 2 is 1. As a result both
221
      inv_2k and c can be taken to be 1, m2k is 2, and h is always
222
      either 0 or 1, and its value depends only on the low bit of inv_o.
223
224
      This is worth special casing because we generate RSA primes such
225
      that phi(n) is of this form. However this only works for keys
226
      that we generated in this way; pre-existing keys will typically
227
      fall back to the general algorithm below.
228
      */
229
230
0
      const BigInt o = mod >> 1;
231
0
      const BigInt n_redc = ct_modulo(n, o);
232
0
      const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
233
234
      // No modular inverse in this case:
235
0
      if(inv_o == 0) {
236
0
         return BigInt::zero();
237
0
      }
238
239
0
      BigInt h = inv_o;
240
0
      h.ct_cond_add(!inv_o.get_bit(0), o);
241
0
      return h;
242
0
   }
243
244
   /*
245
   * In this case we are performing an inversion modulo 2^k*o for
246
   * some k >= 2 and some odd (not necessarily prime) integer.
247
   * Compute the inversions modulo 2^k and modulo o, then combine them
248
   * using CRT, which is possible because 2^k and o are relatively prime.
249
   */
250
251
0
   const BigInt o = mod >> mod_lz;
252
0
   const BigInt n_redc = ct_modulo(n, o);
253
0
   const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
254
0
   const BigInt inv_2k = inverse_mod_pow2(n, mod_lz);
255
256
   // No modular inverse in this case:
257
0
   if(inv_o == 0 || inv_2k == 0) {
258
0
      return BigInt::zero();
259
0
   }
260
261
0
   const BigInt m2k = BigInt::power_of_2(mod_lz);
262
   // Compute the CRT parameter
263
0
   const BigInt c = inverse_mod_pow2(o, mod_lz);
264
265
   // Compute h = c*(inv_2k-inv_o) mod 2^k
266
0
   BigInt h = c * (inv_2k - inv_o);
267
0
   const bool h_neg = h.is_negative();
268
0
   h.set_sign(BigInt::Positive);
269
0
   h.mask_bits(mod_lz);
270
0
   const bool h_nonzero = h.is_nonzero();
271
0
   h.ct_cond_assign(h_nonzero && h_neg, m2k - h);
272
273
   // Return result inv_o + h * o
274
0
   h *= o;
275
0
   h += inv_o;
276
0
   return h;
277
0
}
278
279
}  // namespace Botan