Botan 3.4.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 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
14namespace Botan {
15
16namespace {
17
18BigInt inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) {
19 // Caller should assure these preconditions:
20 BOTAN_DEBUG_ASSERT(n.is_positive());
21 BOTAN_DEBUG_ASSERT(mod.is_positive());
22 BOTAN_DEBUG_ASSERT(n < mod);
23 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://inria.hal.science/hal-01506572/document
39
40 Thanks to Niels for creating the algorithm, explaining some things
41 about it, and the reference to the paper.
42 */
43
44 const size_t mod_words = mod.sig_words();
45 BOTAN_ASSERT(mod_words > 0, "Not empty");
46
47 secure_vector<word> tmp_mem(5 * mod_words);
48
49 word* v_w = &tmp_mem[0];
50 word* u_w = &tmp_mem[1 * mod_words];
51 word* b_w = &tmp_mem[2 * mod_words];
52 word* a_w = &tmp_mem[3 * mod_words];
53 word* mp1o2 = &tmp_mem[4 * mod_words];
54
55 CT::poison(tmp_mem.data(), tmp_mem.size());
56
57 copy_mem(a_w, n.data(), std::min(n.size(), mod_words));
58 copy_mem(b_w, mod.data(), std::min(mod.size(), mod_words));
59 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 copy_mem(mp1o2, mod.data(), std::min(mod.size(), mod_words));
65 bigint_shr1(mp1o2, mod_words, 1);
66 word carry = bigint_add2_nc(mp1o2, mod_words, u_w, 1);
68
69 // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n
70 const size_t execs = 2 * mod.bits();
71
72 for(size_t i = 0; i != execs; ++i) {
73 const word odd_a = a_w[0] & 1;
74
75 //if(odd_a) a -= b
76 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 bigint_cnd_add(underflow, b_w, a_w, mod_words);
80 bigint_cnd_abs(underflow, a_w, mod_words);
81 bigint_cnd_swap(underflow, u_w, v_w, mod_words);
82
83 // a >>= 1
84 bigint_shr1(a_w, mod_words, 1);
85
86 //if(odd_a) u -= v;
87 word borrow = bigint_cnd_sub(odd_a, u_w, v_w, mod_words);
88
89 // if(borrow) u += p
90 bigint_cnd_add(borrow, u_w, mod.data(), mod_words);
91
92 const word odd_u = u_w[0] & 1;
93
94 // u >>= 1
95 bigint_shr1(u_w, mod_words, 1);
96
97 //if(odd_u) u += mp1o2;
98 bigint_cnd_add(odd_u, u_w, mp1o2, mod_words);
99 }
100
101 auto a_is_0 = CT::Mask<word>::set();
102 for(size_t i = 0; i != mod_words; ++i) {
103 a_is_0 &= CT::Mask<word>::is_zero(a_w[i]);
104 }
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, BOTAN_MP_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 X.const_time_unpoison();
173 return X;
174}
175
176} // namespace
177
178BigInt inverse_mod(const BigInt& n, const BigInt& mod) {
179 if(mod.is_zero()) {
180 throw Invalid_Argument("inverse_mod modulus cannot be zero");
181 }
182 if(mod.is_negative() || n.is_negative()) {
183 throw Invalid_Argument("inverse_mod: arguments must be non-negative");
184 }
185 if(n.is_zero() || (n.is_even() && mod.is_even())) {
186 return BigInt::zero();
187 }
188
189 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 if(n < mod) {
195 return inverse_mod_odd_modulus(n, mod);
196 } else {
197 return inverse_mod_odd_modulus(ct_modulo(n, mod), mod);
198 }
199 }
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
204
205 const size_t mod_lz = low_zero_bits(mod);
206 BOTAN_ASSERT_NOMSG(mod_lz > 0);
207 const size_t mod_bits = mod.bits();
208 BOTAN_ASSERT_NOMSG(mod_bits > mod_lz);
209
210 if(mod_lz == mod_bits - 1) {
211 // In this case we are performing an inversion modulo 2^k
212 return inverse_mod_pow2(n, mod_lz);
213 }
214
215 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 const BigInt o = mod >> 1;
231 const BigInt n_redc = ct_modulo(n, o);
232 const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
233
234 // No modular inverse in this case:
235 if(inv_o == 0) {
236 return BigInt::zero();
237 }
238
239 BigInt h = inv_o;
240 h.ct_cond_add(!inv_o.get_bit(0), o);
241 return h;
242 }
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 const BigInt o = mod >> mod_lz;
252 const BigInt n_redc = ct_modulo(n, o);
253 const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
254 const BigInt inv_2k = inverse_mod_pow2(n, mod_lz);
255
256 // No modular inverse in this case:
257 if(inv_o == 0 || inv_2k == 0) {
258 return BigInt::zero();
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 // Compute h = c*(inv_2k-inv_o) mod 2^k
266 BigInt h = c * (inv_2k - inv_o);
267 const bool h_neg = h.is_negative();
269 h.mask_bits(mod_lz);
270 const bool h_nonzero = h.is_nonzero();
271 h.ct_cond_assign(h_nonzero && h_neg, m2k - h);
272
273 // Return result inv_o + h * o
274 h *= o;
275 h += inv_o;
276 return h;
277}
278
279} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
void ct_cond_add(bool predicate, const BigInt &value)
Definition bigint.cpp:424
static BigInt zero()
Definition bigint.h:46
bool is_odd() const
Definition bigint.h:416
void ct_cond_assign(bool predicate, const BigInt &other)
Definition bigint.cpp:487
static BigInt one()
Definition bigint.h:51
void mask_bits(size_t n)
Definition bigint.h:460
size_t bits() const
Definition bigint.cpp:290
bool is_even() const
Definition bigint.h:410
static BigInt power_of_2(size_t n)
Definition bigint.h:739
bool is_zero() const
Definition bigint.h:428
bool is_negative() const
Definition bigint.h:528
bool is_nonzero() const
Definition bigint.h:422
bool get_bit(size_t n) const
Definition bigint.h:467
void set_sign(Sign sign)
Definition bigint.h:561
static constexpr Mask< T > set()
Definition ct_utils.h:105
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:134
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:129
FE_25519 X
Definition ge.cpp:25
#define BOTAN_MP_WORD_BITS
Definition build.h:50
void poison(const T *p, size_t n)
Definition ct_utils.h:46
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:57
constexpr void bigint_cnd_abs(W cnd, W x[], size_t size)
Definition mp_core.h:197
constexpr void bigint_cnd_swap(W cnd, W x[], W y[], size_t size)
Definition mp_core.h:29
constexpr void bigint_shr1(W x[], size_t x_size, size_t shift)
Definition mp_core.h:475
size_t low_zero_bits(const BigInt &n)
Definition numthry.cpp:167
BigInt ct_modulo(const BigInt &x, const BigInt &y)
Definition divide.cpp:117
constexpr auto bigint_cnd_sub(W cnd, W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:83
constexpr W bigint_cnd_add(W cnd, W x[], size_t x_size, const W y[], size_t y_size)
Definition mp_core.h:41
void carry(int64_t &h0, int64_t &h1)
constexpr auto bigint_add2_nc(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:211
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition mod_inv.cpp:178
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:120
size_t round_up(size_t n, size_t align_to)
Definition rounding.h:21