Botan 3.12.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.signum() >= 0);
24 BOTAN_ASSERT_NOMSG(mod.signum() > 0);
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 copy_mem(a_w, n._data(), std::min(n.size(), mod_words));
59 copy_mem(b_w, mod._data(), std::min(mod.size(), mod_words));
60 u_w[0] = 1;
61 // v_w = 0
62
63 // compute (mod + 1) / 2 which [because mod is odd] is equal to
64 // (mod / 2) + 1
65 copy_mem(mp1o2, mod._data(), std::min(mod.size(), mod_words));
66 bigint_shr1(mp1o2, mod_words, 1);
67 const word carry = bigint_add2(mp1o2, mod_words, u_w, 1);
69
70 CT::poison(tmp_mem.data(), tmp_mem.size());
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
266 BOTAN_ASSERT_NOMSG(c.signum() != 0);
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.signum() < 0;
272 h.mask_bits(mod_lz);
273 const bool h_nonzero = h.signum() != 0;
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(p.signum() > 0, "Modulus must be positive");
284 BOTAN_ARG_CHECK(x.signum() > 0, "Input must be positive");
285 BOTAN_ARG_CHECK(x < p, "Input must be less than modulus");
286 BOTAN_ARG_CHECK(p.is_odd() && p > 1, "Primes are odd integers greater than 1");
287
288 // TODO possibly use FLT, or the algorithm presented for this case in
289 // Handbook of Elliptic and Hyperelliptic Curve Cryptography
290
291 return inverse_mod_odd_modulus(x, p);
292}
293
295 BOTAN_ARG_CHECK(p.signum() > 0, "Modulus must be positive");
296 BOTAN_ARG_CHECK(x.signum() > 0, "Input must be positive");
297 BOTAN_ARG_CHECK(x < p, "Input must be less than modulus");
298 BOTAN_ARG_CHECK(p.is_odd() && p > 1, "Primes are odd integers greater than 1");
299
300 // TODO possibly use FLT, or the algorithm presented for this case in
301 // Handbook of Elliptic and Hyperelliptic Curve Cryptography
302
303 return inverse_mod_odd_modulus(x, p);
304}
305
307 BOTAN_ARG_CHECK(n.signum() > 0 && n.is_odd(), "RSA public modulus must be odd and positive");
308 BOTAN_ARG_CHECK(x.signum() > 0 && x < n, "Input must be positive and less than RSA modulus");
309 BigInt z = inverse_mod_odd_modulus(x, n);
310 BOTAN_ASSERT(z.signum() != 0, "Accidentally factored the public modulus"); // whoops
311 return z;
312}
313
314namespace {
315
316uint64_t barrett_mod_65537(uint64_t x) {
317 constexpr uint64_t mod = 65537;
318 constexpr size_t s = 32;
319 constexpr uint64_t c = (static_cast<uint64_t>(1) << s) / mod;
320
321 const uint64_t q = (x * c) >> s;
322 const uint64_t r = x - q * mod;
323
324 auto r_gt_mod = CT::Mask<uint64_t>::is_gte(r, mod);
325 return r - r_gt_mod.if_set_return(mod);
326}
327
328word inverse_mod_65537(word x) {
329 // Need 64-bit here as accum*accum exceeds 32-bit if accum=0x10000
330 uint64_t accum = 1;
331 // Basic square and multiply, with all bits of exponent set
332 for(size_t i = 0; i != 16; ++i) {
333 accum = barrett_mod_65537(accum * accum);
334 accum = barrett_mod_65537(accum * x);
335 }
336 return static_cast<word>(accum);
337}
338
339} // namespace
340
341BigInt compute_rsa_secret_exponent(const BigInt& e, const BigInt& phi_n, const BigInt& p, const BigInt& q) {
342 /*
343 * Both p - 1 and q - 1 are chosen to be relatively prime to e. Thus
344 * phi(n), the least common multiple of p - 1 and q - 1, is also
345 * relatively prime to e.
346 */
347 BOTAN_DEBUG_ASSERT(gcd(e, phi_n) == 1);
348
349 if(e == 65537) {
350 /*
351 Arazi's algorithm for inversion of prime x modulo a non-prime
352
353 "GCD-Free Algorithms for Computing Modular Inverses"
354 Marc Joye and Pascal Paillier, CHES 2003 (LNCS 2779)
355 https://marcjoye.github.io/papers/JP03gcdfree.pdf
356
357 This could be extended to cover other cases such as e=3 or e=17 but
358 these days 65537 is the standard RSA public exponent
359 */
360
361 constexpr word e_w = 65537;
362
363 const word phi_mod_e = ct_mod_word(phi_n, e_w);
364 const word inv_phi_mod_e = inverse_mod_65537(phi_mod_e);
365 BOTAN_DEBUG_ASSERT((inv_phi_mod_e * phi_mod_e) % e_w == 1);
366 const word neg_inv_phi_mod_e = (e_w - inv_phi_mod_e);
367 return ct_divide_word((phi_n * neg_inv_phi_mod_e) + 1, e_w);
368 } else {
369 // TODO possibly do something else taking advantage of the special structure here
370
371 BOTAN_UNUSED(p, q);
372 if(auto d = inverse_mod_general(e, phi_n)) {
373 return *d;
374 } else {
375 throw Internal_Error("Failed to compute RSA secret exponent");
376 }
377 }
378}
379
380BigInt inverse_mod(const BigInt& n, const BigInt& mod) {
381 BOTAN_ARG_CHECK(mod.signum() > 0, "Modulus must be positive");
382 BOTAN_ARG_CHECK(n.signum() >= 0, "Value cannot be negative");
383
384 if(n.is_zero() || (n.is_even() && mod.is_even())) {
385 return BigInt::zero();
386 }
387
388 if(n >= mod) {
389 return inverse_mod(ct_modulo(n, mod), mod);
390 }
391
392 return inverse_mod_general(n, mod).value_or(BigInt::zero());
393}
394
395} // 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:648
bool is_odd() const
Definition bigint.h:461
void ct_cond_assign(bool predicate, const BigInt &other)
Definition bigint.cpp:531
int signum() const
Definition bigint.h:467
static BigInt one()
Definition bigint.h:55
void mask_bits(size_t n)
Definition bigint.h:516
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:853
bool is_zero() const
Definition bigint.h:484
bool get_bit(size_t n) const
Definition bigint.h:523
void swap_reg(secure_vector< word > &reg)
Definition bigint.h:214
void set_sign(Sign sign)
Definition bigint.h:625
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 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
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
BigInt inverse_mod_public_prime(const BigInt &x, const BigInt &p)
Definition mod_inv.cpp:294
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:341
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:306
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:380
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118