Botan 3.6.1
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
174 return X;
175}
176
177} // namespace
178
179BigInt inverse_mod(const BigInt& n, const BigInt& mod) {
180 if(mod.is_zero()) {
181 throw Invalid_Argument("inverse_mod modulus cannot be zero");
182 }
183 if(mod.is_negative() || n.is_negative()) {
184 throw Invalid_Argument("inverse_mod: arguments must be non-negative");
185 }
186 if(n.is_zero() || (n.is_even() && mod.is_even())) {
187 return BigInt::zero();
188 }
189
190 if(mod.is_odd()) {
191 /*
192 Fastpath for common case. This leaks if n is greater than mod or
193 not, but we don't guarantee const time behavior in that case.
194 */
195 if(n < mod) {
196 return inverse_mod_odd_modulus(n, mod);
197 } else {
198 return inverse_mod_odd_modulus(ct_modulo(n, mod), mod);
199 }
200 }
201
202 // If n is even and mod is even we already returned 0
203 // If n is even and mod is odd we jumped directly to odd-modulus algo
205
206 const size_t mod_lz = low_zero_bits(mod);
207 BOTAN_ASSERT_NOMSG(mod_lz > 0);
208 const size_t mod_bits = mod.bits();
209 BOTAN_ASSERT_NOMSG(mod_bits > mod_lz);
210
211 if(mod_lz == mod_bits - 1) {
212 // In this case we are performing an inversion modulo 2^k
213 return inverse_mod_pow2(n, mod_lz);
214 }
215
216 if(mod_lz == 1) {
217 /*
218 Inversion modulo 2*o is an easier special case of CRT
219
220 This is exactly the main CRT flow below but taking advantage of
221 the fact that any odd number ^-1 modulo 2 is 1. As a result both
222 inv_2k and c can be taken to be 1, m2k is 2, and h is always
223 either 0 or 1, and its value depends only on the low bit of inv_o.
224
225 This is worth special casing because we generate RSA primes such
226 that phi(n) is of this form. However this only works for keys
227 that we generated in this way; pre-existing keys will typically
228 fall back to the general algorithm below.
229 */
230
231 const BigInt o = mod >> 1;
232 const BigInt n_redc = ct_modulo(n, o);
233 const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
234
235 // No modular inverse in this case:
236 if(inv_o == 0) {
237 return BigInt::zero();
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 n_redc = ct_modulo(n, o);
254 const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o);
255 const BigInt inv_2k = inverse_mod_pow2(n, mod_lz);
256
257 // No modular inverse in this case:
258 if(inv_o == 0 || inv_2k == 0) {
259 return BigInt::zero();
260 }
261
262 const BigInt m2k = BigInt::power_of_2(mod_lz);
263 // Compute the CRT parameter
264 const BigInt c = inverse_mod_pow2(o, mod_lz);
265
266 // Compute h = c*(inv_2k-inv_o) mod 2^k
267 BigInt h = c * (inv_2k - inv_o);
268 const bool h_neg = h.is_negative();
270 h.mask_bits(mod_lz);
271 const bool h_nonzero = h.is_nonzero();
272 h.ct_cond_assign(h_nonzero && h_neg, m2k - h);
273
274 // Return result inv_o + h * o
275 h *= o;
276 h += inv_o;
277 return h;
278}
279
280} // 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:437
static BigInt zero()
Definition bigint.h:50
bool is_odd() const
Definition bigint.h:446
void ct_cond_assign(bool predicate, const BigInt &other)
Definition bigint.cpp:500
static BigInt one()
Definition bigint.h:55
void mask_bits(size_t n)
Definition bigint.h:490
size_t bits() const
Definition bigint.cpp:295
bool is_even() const
Definition bigint.h:440
static BigInt power_of_2(size_t n)
Definition bigint.h:830
bool is_zero() const
Definition bigint.h:458
bool is_negative() const
Definition bigint.h:560
bool is_nonzero() const
Definition bigint.h:452
bool get_bit(size_t n) const
Definition bigint.h:497
void set_sign(Sign sign)
Definition bigint.h:593
static constexpr Mask< T > set()
Definition ct_utils.h:379
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:434
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:429
FE_25519 X
Definition ge.cpp:25
#define BOTAN_MP_WORD_BITS
Definition build.h:71
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:64
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:53
constexpr void bigint_cnd_abs(W cnd, W x[], size_t size)
Definition mp_core.h:192
constexpr void bigint_cnd_swap(W cnd, W x[], W y[], size_t size)
Definition mp_core.h:30
constexpr void bigint_shr1(W x[], size_t x_size, size_t shift)
Definition mp_core.h:486
size_t low_zero_bits(const BigInt &n)
Definition numthry.cpp:167
constexpr size_t round_up(size_t n, size_t align_to)
Definition rounding.h:25
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:84
constexpr W bigint_cnd_add(W cnd, W x[], size_t x_size, const W y[], size_t y_size)
Definition mp_core.h:42
void carry(int64_t &h0, int64_t &h1)
const SIMD_8x32 & b
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
constexpr auto bigint_add2_nc(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:206
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:179
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:120