Botan 3.11.0
Crypto and TLS for C&
mod_inv.cpp
Go to the documentation of this file.
1/*
2* (C) 1999-2011,2016,2018,2019,2020,2025 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/mod_inv.h>
8
9#include <botan/exceptn.h>
10#include <botan/mem_ops.h>
11#include <botan/numthry.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/divide.h>
14#include <botan/internal/mp_core.h>
15#include <botan/internal/rounding.h>
16
17namespace Botan {
18
19namespace {
20
21BigInt inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) {
22 // Caller should assure these preconditions:
23 BOTAN_ASSERT_NOMSG(n.is_positive());
24 BOTAN_ASSERT_NOMSG(mod.is_positive());
25 BOTAN_ASSERT_NOMSG(n < mod);
26 BOTAN_ASSERT_NOMSG(mod >= 3 && mod.is_odd());
27
28 /*
29 This uses a modular inversion algorithm designed by Niels Möller
30 and implemented in Nettle. The same algorithm was later also
31 adapted to GMP in mpn_sec_invert.
32
33 It can be easily implemented in a way that does not depend on
34 secret branches or memory lookups, providing resistance against
35 some forms of side channel attack.
36
37 There is also a description of the algorithm in Appendix 5 of "Fast
38 Software Polynomial Multiplication on ARM Processors using the NEON Engine"
39 by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo
40 Dahab in LNCS 8182
41 https://inria.hal.science/hal-01506572/document
42
43 Thanks to Niels for creating the algorithm, explaining some things
44 about it, and the reference to the paper.
45 */
46
47 const size_t mod_words = mod.sig_words();
48 BOTAN_ASSERT(mod_words > 0, "Not empty");
49
50 secure_vector<word> tmp_mem(5 * mod_words);
51
52 word* v_w = &tmp_mem[0]; // NOLINT(readability-container-data-pointer)
53 word* u_w = &tmp_mem[1 * mod_words];
54 word* b_w = &tmp_mem[2 * mod_words];
55 word* a_w = &tmp_mem[3 * mod_words];
56 word* mp1o2 = &tmp_mem[4 * mod_words];
57
58 CT::poison(tmp_mem.data(), tmp_mem.size());
59
60 copy_mem(a_w, n._data(), std::min(n.size(), mod_words));
61 copy_mem(b_w, mod._data(), std::min(mod.size(), mod_words));
62 u_w[0] = 1;
63 // v_w = 0
64
65 // compute (mod + 1) / 2 which [because mod is odd] is equal to
66 // (mod / 2) + 1
67 copy_mem(mp1o2, mod._data(), std::min(mod.size(), mod_words));
68 bigint_shr1(mp1o2, mod_words, 1);
69 const word carry = bigint_add2(mp1o2, mod_words, u_w, 1);
71
72 // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n
73 const size_t execs = 2 * mod.bits();
74
75 for(size_t i = 0; i != execs; ++i) {
76 const word odd_a = a_w[0] & 1;
77
78 //if(odd_a) a -= b
79 const word underflow = bigint_cnd_sub(odd_a, a_w, b_w, mod_words);
80
81 //if(underflow) { b -= a; a = abs(a); swap(u, v); }
82 bigint_cnd_add(underflow, b_w, a_w, mod_words);
83 bigint_cnd_abs(underflow, a_w, mod_words);
84 bigint_cnd_swap(underflow, u_w, v_w, mod_words);
85
86 // a >>= 1
87 bigint_shr1(a_w, mod_words, 1);
88
89 //if(odd_a) u -= v;
90 const word borrow = bigint_cnd_sub(odd_a, u_w, v_w, mod_words);
91
92 // if(borrow) u += p
93 bigint_cnd_add(borrow, u_w, mod._data(), mod_words);
94
95 const word odd_u = u_w[0] & 1;
96
97 // u >>= 1
98 bigint_shr1(u_w, mod_words, 1);
99
100 //if(odd_u) u += mp1o2;
101 bigint_cnd_add(odd_u, u_w, mp1o2, mod_words);
102 }
103
104 const auto a_is_0 = CT::all_zeros(a_w, mod_words);
105
106 auto b_is_1 = CT::Mask<word>::is_equal(b_w[0], 1);
107 for(size_t i = 1; i != mod_words; ++i) {
108 b_is_1 &= CT::Mask<word>::is_zero(b_w[i]);
109 }
110
111 BOTAN_ASSERT(a_is_0.as_bool(), "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 (~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 clear_mem(&tmp_mem[mod_words], 4 * mod_words);
123
124 CT::unpoison(tmp_mem.data(), tmp_mem.size());
125
126 BigInt r;
127 r.swap_reg(tmp_mem);
128 return r;
129}
130
131BigInt 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 if(a1.is_even() || k == 0) {
138 return BigInt::zero();
139 }
140 if(k == 1) {
141 return BigInt::one();
142 }
143
144 BigInt a = a1;
145 a.mask_bits(k);
146
147 BigInt b = BigInt::one();
148 BigInt X = BigInt::zero();
149 BigInt newb;
150
151 const size_t a_words = a.sig_words();
152
154 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 const size_t iter = round_up(k, WordInfo<word>::bits);
162
163 for(size_t i = 0; i != iter; ++i) {
164 const bool b0 = b.get_bit(0);
165 X.conditionally_set_bit(i, b0);
166 newb = b - a;
167 b.ct_cond_assign(b0, newb);
168 b >>= 1;
169 }
170
171 X.mask_bits(k);
172
173 CT::unpoison(X);
174 return X;
175}
176
177} // namespace
178
179std::optional<BigInt> inverse_mod_general(const BigInt& x, const BigInt& mod) {
180 BOTAN_ARG_CHECK(x > 0, "x must be greater than zero");
181 BOTAN_ARG_CHECK(mod > 0, "mod must be greater than zero");
182 BOTAN_ARG_CHECK(x < mod, "x must be less than m");
183
184 // Easy case where gcd > 1 so no inverse exists
185 if(x.is_even() && mod.is_even()) {
186 return std::nullopt;
187 }
188
189 if(mod.is_odd()) {
190 BigInt z = inverse_mod_odd_modulus(x, mod);
191 if(z.is_zero()) {
192 return std::nullopt;
193 } else {
194 return z;
195 }
196 }
197
198 // If x is even and mod is even we already returned 0
199 // If x is even and mod is odd we jumped directly to odd-modulus algo
201
202 const size_t mod_lz = low_zero_bits(mod);
203 BOTAN_ASSERT_NOMSG(mod_lz > 0);
204 const size_t mod_bits = mod.bits();
205 BOTAN_ASSERT_NOMSG(mod_bits > mod_lz);
206
207 if(mod_lz == mod_bits - 1) {
208 // In this case we are performing an inversion modulo 2^k
209 auto z = inverse_mod_pow2(x, mod_lz);
210 if(z.is_zero()) {
211 return std::nullopt;
212 } else {
213 return z;
214 }
215 }
216
217 if(mod_lz == 1) {
218 /*
219 Inversion modulo 2*o is an easier special case of CRT
220
221 This is exactly the main CRT flow below but taking advantage of
222 the fact that any odd number ^-1 modulo 2 is 1. As a result both
223 inv_2k and c can be taken to be 1, m2k is 2, and h is always
224 either 0 or 1, and its value depends only on the low bit of inv_o.
225
226 This is worth special casing because we generate RSA primes such
227 that phi(n) is of this form. However this only works for keys
228 that we generated in this way; pre-existing keys will typically
229 fall back to the general algorithm below.
230 */
231
232 const BigInt o = mod >> 1;
233 const BigInt inv_o = inverse_mod_odd_modulus(ct_modulo(x, o), o);
234
235 // No modular inverse in this case:
236 if(inv_o == 0) {
237 return std::nullopt;
238 }
239
240 BigInt h = inv_o;
241 h.ct_cond_add(!inv_o.get_bit(0), o);
242 return h;
243 }
244
245 /*
246 * In this case we are performing an inversion modulo 2^k*o for
247 * some k >= 2 and some odd (not necessarily prime) integer.
248 * Compute the inversions modulo 2^k and modulo o, then combine them
249 * using CRT, which is possible because 2^k and o are relatively prime.
250 */
251
252 const BigInt o = mod >> mod_lz;
253 const BigInt inv_o = inverse_mod_odd_modulus(ct_modulo(x, o), o);
254 const BigInt inv_2k = inverse_mod_pow2(x, mod_lz);
255
256 // No modular inverse in this case:
257 if(inv_o == 0 || inv_2k == 0) {
258 return std::nullopt;
259 }
260
261 const BigInt m2k = BigInt::power_of_2(mod_lz);
262 // Compute the CRT parameter
263 const BigInt c = inverse_mod_pow2(o, mod_lz);
264
265 // This should never happen; o is odd so gcd is 1 and inverse mod 2^k exists
267
268 // Compute h = c*(inv_2k-inv_o) mod 2^k
269 BigInt h = c * (inv_2k - inv_o);
270 const bool h_neg = h.is_negative();
272 h.mask_bits(mod_lz);
273 const bool h_nonzero = h.is_nonzero();
274 h.ct_cond_assign(h_nonzero && h_neg, m2k - h);
275
276 // Return result inv_o + h * o
277 h *= o;
278 h += inv_o;
279 return h;
280}
281
283 BOTAN_ARG_CHECK(x.is_positive() && p.is_positive(), "Parameters must be positive");
284 BOTAN_ARG_CHECK(x < p, "x must be less than p");
285 BOTAN_ARG_CHECK(p.is_odd() && p > 1, "Primes are odd integers greater than 1");
286
287 // TODO possibly use FLT, or the algorithm presented for this case in
288 // Handbook of Elliptic and Hyperelliptic Curve Cryptography
289
290 return inverse_mod_odd_modulus(x, p);
291}
292
294 return inverse_mod_secret_prime(x, p);
295}
296
298 BOTAN_ARG_CHECK(n.is_positive() && n.is_odd(), "RSA public modulus must be odd and positive");
299 BOTAN_ARG_CHECK(x.is_positive() && x < n, "Input must be positive and less than RSA modulus");
300 BigInt z = inverse_mod_odd_modulus(x, n);
301 BOTAN_ASSERT(!z.is_zero(), "Accidentally factored the public modulus"); // whoops
302 return z;
303}
304
305namespace {
306
307uint64_t barrett_mod_65537(uint64_t x) {
308 constexpr uint64_t mod = 65537;
309 constexpr size_t s = 32;
310 constexpr uint64_t c = (static_cast<uint64_t>(1) << s) / mod;
311
312 const uint64_t q = (x * c) >> s;
313 const uint64_t r = x - q * mod;
314
315 auto r_gt_mod = CT::Mask<uint64_t>::is_gte(r, mod);
316 return r - r_gt_mod.if_set_return(mod);
317}
318
319word inverse_mod_65537(word x) {
320 // Need 64-bit here as accum*accum exceeds 32-bit if accum=0x10000
321 uint64_t accum = 1;
322 // Basic square and multiply, with all bits of exponent set
323 for(size_t i = 0; i != 16; ++i) {
324 accum = barrett_mod_65537(accum * accum);
325 accum = barrett_mod_65537(accum * x);
326 }
327 return static_cast<word>(accum);
328}
329
330} // namespace
331
332BigInt compute_rsa_secret_exponent(const BigInt& e, const BigInt& phi_n, const BigInt& p, const BigInt& q) {
333 /*
334 * Both p - 1 and q - 1 are chosen to be relatively prime to e. Thus
335 * phi(n), the least common multiple of p - 1 and q - 1, is also
336 * relatively prime to e.
337 */
338 BOTAN_DEBUG_ASSERT(gcd(e, phi_n) == 1);
339
340 if(e == 65537) {
341 /*
342 Arazi's algorithm for inversion of prime x modulo a non-prime
343
344 "GCD-Free Algorithms for Computing Modular Inverses"
345 Marc Joye and Pascal Paillier, CHES 2003 (LNCS 2779)
346 https://marcjoye.github.io/papers/JP03gcdfree.pdf
347
348 This could be extended to cover other cases such as e=3 or e=17 but
349 these days 65537 is the standard RSA public exponent
350 */
351
352 constexpr word e_w = 65537;
353
354 const word phi_mod_e = ct_mod_word(phi_n, e_w);
355 const word inv_phi_mod_e = inverse_mod_65537(phi_mod_e);
356 BOTAN_DEBUG_ASSERT((inv_phi_mod_e * phi_mod_e) % e_w == 1);
357 const word neg_inv_phi_mod_e = (e_w - inv_phi_mod_e);
358 return ct_divide_word((phi_n * neg_inv_phi_mod_e) + 1, e_w);
359 } else {
360 // TODO possibly do something else taking advantage of the special structure here
361
362 BOTAN_UNUSED(p, q);
363 if(auto d = inverse_mod_general(e, phi_n)) {
364 return *d;
365 } else {
366 throw Internal_Error("Failed to compute RSA secret exponent");
367 }
368 }
369}
370
371BigInt inverse_mod(const BigInt& n, const BigInt& mod) {
372 BOTAN_ARG_CHECK(!mod.is_zero(), "modulus cannot be zero");
373 BOTAN_ARG_CHECK(!mod.is_negative(), "modulus cannot be negative");
374 BOTAN_ARG_CHECK(!n.is_negative(), "value cannot be negative");
375
376 if(n.is_zero() || (n.is_even() && mod.is_even())) {
377 return BigInt::zero();
378 }
379
380 if(n >= mod) {
381 return inverse_mod(ct_modulo(n, mod), mod);
382 }
383
384 return inverse_mod_general(n, mod).value_or(BigInt::zero());
385}
386
387} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
void ct_cond_add(bool predicate, const BigInt &value)
Definition bigint.cpp:449
static BigInt zero()
Definition bigint.h:50
size_t sig_words() const
Definition bigint.h:631
bool is_odd() const
Definition bigint.h:461
void ct_cond_assign(bool predicate, const BigInt &other)
Definition bigint.cpp:527
static BigInt one()
Definition bigint.h:55
void mask_bits(size_t n)
Definition bigint.h:505
size_t bits() const
Definition bigint.cpp:307
bool is_even() const
Definition bigint.h:455
static BigInt power_of_2(size_t n)
Definition bigint.h:836
bool is_zero() const
Definition bigint.h:473
bool is_negative() const
Definition bigint.h:575
bool is_nonzero() const
Definition bigint.h:467
bool is_positive() const
Definition bigint.h:581
bool get_bit(size_t n) const
Definition bigint.h:512
void swap_reg(secure_vector< word > &reg)
Definition bigint.h:214
void set_sign(Sign sign)
Definition bigint.h:608
static constexpr Mask< T > is_gte(T x, T y)
Definition ct_utils.h:468
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:442
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:437
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Definition ct_utils.h:785
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:56
constexpr void bigint_cnd_abs(W cnd, W x[], size_t size)
Definition mp_core.h:80
BigInt inverse_mod_secret_prime(const BigInt &x, const BigInt &p)
Definition mod_inv.cpp:282
constexpr auto bigint_add2(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:94
constexpr auto bigint_cnd_sub(W cnd, W x[], const W y[], size_t size) -> W
Definition mp_core.h:62
constexpr void bigint_cnd_swap(W cnd, W x[], W y[], size_t size)
Definition mp_core.h:29
word ct_mod_word(const BigInt &x, word y)
Definition divide.cpp:168
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
constexpr void bigint_shr1(W x[], size_t x_size, size_t shift)
Definition mp_core.h:326
size_t low_zero_bits(const BigInt &n)
Definition numthry.cpp:194
constexpr size_t round_up(size_t n, size_t align_to)
Definition rounding.h:26
BigInt inverse_mod_public_prime(const BigInt &x, const BigInt &p)
Definition mod_inv.cpp:293
BigInt ct_modulo(const BigInt &x, const BigInt &y)
Definition divide.cpp:192
BigInt compute_rsa_secret_exponent(const BigInt &e, const BigInt &phi_n, const BigInt &p, const BigInt &q)
Definition mod_inv.cpp:332
constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size)
Definition mp_core.h:45
void ct_divide_word(const BigInt &x, word y, BigInt &q_out, word &r_out)
Definition divide.cpp:123
void carry(int64_t &h0, int64_t &h1)
std::optional< BigInt > inverse_mod_general(const BigInt &x, const BigInt &mod)
Definition mod_inv.cpp:179
BigInt gcd(const BigInt &a, const BigInt &b)
Definition numthry.cpp:220
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
BigInt inverse_mod_rsa_public_modulus(const BigInt &x, const BigInt &n)
Definition mod_inv.cpp:297
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
Definition types.h:119
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition mod_inv.cpp:371
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118