Botan 3.11.0
Crypto and TLS for C&
divide.cpp
Go to the documentation of this file.
1/*
2* Division Algorithms
3* (C) 1999-2007,2012,2018,2021 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/divide.h>
9
10#include <botan/exceptn.h>
11#include <botan/internal/ct_utils.h>
12#include <botan/internal/mp_core.h>
13
14namespace Botan {
15
16namespace {
17
18/*
19* Handle signed operands, if necessary
20*/
21void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) {
22 q.cond_flip_sign(x.sign() != y.sign());
23
24 if(x.is_negative() && r.is_nonzero()) {
25 q -= 1;
26 r = y.abs() - r;
27 }
28}
29
30inline bool division_check_vartime(word q, word y2, word y1, word x3, word x2, word x1) {
31 /*
32 Compute (y3,y2,y1) = (y2,y1) * q
33 and return true if (y3,y2,y1) > (x3,x2,x1)
34 */
35
36 word y3 = 0;
37 y1 = word_madd2(q, y1, &y3);
38 y2 = word_madd2(q, y2, &y3);
39
40 if(x3 != y3) {
41 return (y3 > x3);
42 }
43 if(x2 != y2) {
44 return (y2 > x2);
45 }
46 return (y1 > x1);
47}
48
49} // namespace
50
51void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out) {
52 if(y.is_zero()) {
53 throw Invalid_Argument("ct_divide: cannot divide by zero");
54 }
55
56 const size_t x_words = x.sig_words();
57 const size_t y_words = y.sig_words();
58
59 const size_t x_bits = x.bits();
60
61 BigInt q = BigInt::with_capacity(x_words);
62 BigInt r = BigInt::with_capacity(y_words);
63 BigInt t = BigInt::with_capacity(y_words); // a temporary
64
65 for(size_t i = 0; i != x_bits; ++i) {
66 const size_t b = x_bits - 1 - i;
67 const bool x_b = x.get_bit(b);
68
69 r <<= 1;
70 r.conditionally_set_bit(0, x_b);
71
72 const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
73
74 q.conditionally_set_bit(b, r_gte_y);
75 r.ct_cond_swap(r_gte_y, t);
76 }
77
78 sign_fixup(x, y, q, r);
79 r_out = r;
80 q_out = q;
81}
82
83BigInt ct_divide_pow2k(size_t k, const BigInt& y) {
84 BOTAN_ARG_CHECK(!y.is_zero(), "Cannot divide by zero");
85 BOTAN_ARG_CHECK(!y.is_negative(), "Negative divisor not supported");
86 BOTAN_ARG_CHECK(k > 1, "Invalid k");
87
88 const size_t x_bits = k + 1;
89 const size_t y_bits = y.bits();
90
91 if(x_bits < y_bits) {
92 return BigInt::zero();
93 }
94
95 BOTAN_ASSERT_NOMSG(y_bits >= 1);
96 const size_t x_words = (x_bits + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
97 const size_t y_words = y.sig_words();
98
99 BigInt q = BigInt::with_capacity(x_words);
100 BigInt r = BigInt::with_capacity(y_words + 1);
101 BigInt t = BigInt::with_capacity(y_words + 1); // a temporary
102
103 r.set_bit(y_bits - 1);
104 for(size_t i = y_bits - 1; i != x_bits; ++i) {
105 const size_t b = x_bits - 1 - i;
106
107 if(i >= y_bits) {
108 bigint_shl1(r.mutable_data(), r.size(), r.size(), 1);
109 }
110
111 const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
112
113 q.conditionally_set_bit(b, r_gte_y);
114
115 bigint_cnd_swap(static_cast<word>(r_gte_y), r.mutable_data(), t.mutable_data(), y_words + 1);
116 }
117
118 // No need for sign fixup
119
120 return q;
121}
122
123void ct_divide_word(const BigInt& x, word y, BigInt& q_out, word& r_out) {
124 if(y == 0) {
125 throw Invalid_Argument("ct_divide_word: cannot divide by zero");
126 }
127
128 const size_t x_words = x.sig_words();
129 const size_t x_bits = x.bits();
130
131 BigInt q = BigInt::with_capacity(x_words);
132 word r = 0;
133
134 for(size_t i = 0; i != x_bits; ++i) {
135 const size_t b = x_bits - 1 - i;
136 const bool x_b = x.get_bit(b);
137
138 const auto r_carry = CT::Mask<word>::expand_top_bit(r);
139
140 r <<= 1;
141 r += static_cast<word>(x_b);
142
143 const auto r_gte_y = CT::Mask<word>::is_gte(r, y) | r_carry;
144 q.conditionally_set_bit(b, r_gte_y.as_bool());
145 r = r_gte_y.select(r - y, r);
146 }
147
148 if(x.is_negative()) {
149 q.flip_sign();
150 if(r != 0) {
151 --q;
152 r = y - r;
153 }
154 }
155
156 r_out = r;
157 q_out = q;
158}
159
161 BigInt q;
162 word r = 0;
163 ct_divide_word(x, y, q, r);
164 BOTAN_UNUSED(r);
165 return q;
166}
167
169 BOTAN_ARG_CHECK(x.is_positive(), "The argument x must be positive");
170 BOTAN_ARG_CHECK(y != 0, "Cannot divide by zero");
171
172 const size_t x_bits = x.bits();
173
174 word r = 0;
175
176 for(size_t i = 0; i != x_bits; ++i) {
177 const size_t b = x_bits - 1 - i;
178 const bool x_b = x.get_bit(b);
179
180 const auto r_carry = CT::Mask<word>::expand_top_bit(r);
181
182 r <<= 1;
183 r += static_cast<word>(x_b);
184
185 const auto r_gte_y = CT::Mask<word>::is_gte(r, y) | r_carry;
186 r = r_gte_y.select(r - y, r);
187 }
188
189 return r;
190}
191
192BigInt ct_modulo(const BigInt& x, const BigInt& y) {
193 if(y.is_negative() || y.is_zero()) {
194 throw Invalid_Argument("ct_modulo requires y > 0");
195 }
196
197 const size_t y_words = y.sig_words();
198
199 const size_t x_bits = x.bits();
200
201 BigInt r = BigInt::with_capacity(y_words);
202 BigInt t = BigInt::with_capacity(y_words);
203
204 for(size_t i = 0; i != x_bits; ++i) {
205 const size_t b = x_bits - 1 - i;
206 const bool x_b = x.get_bit(b);
207
208 r <<= 1;
209 r.conditionally_set_bit(0, x_b);
210
211 const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
212
213 r.ct_cond_swap(r_gte_y, t);
214 }
215
216 if(x.is_negative()) {
217 if(r.is_nonzero()) {
218 r = y - r;
219 }
220 }
221
222 return r;
223}
224
225BigInt vartime_divide_pow2k(size_t k, const BigInt& y_arg) {
226 constexpr size_t WB = WordInfo<word>::bits;
227
228 BOTAN_ARG_CHECK(!y_arg.is_zero(), "Cannot divide by zero");
229 BOTAN_ARG_CHECK(!y_arg.is_negative(), "Negative divisor not supported");
230 BOTAN_ARG_CHECK(k > 1, "Invalid k");
231
232 BigInt y = y_arg;
233
234 const size_t y_words = y.sig_words();
235
236 BOTAN_ASSERT_NOMSG(y_words > 0);
237
238 // Calculate shifts needed to normalize y with high bit set
239 const size_t shifts = y.top_bits_free();
240
241 if(shifts > 0) {
242 y <<= shifts;
243 }
244
245 BigInt r;
246 r.set_bit(k + shifts); // (2^k) << shifts
247
248 // we know y has not changed size, since we only shifted up to set high bit
249 const size_t t = y_words - 1;
250 const size_t n = std::max(y_words, r.sig_words()) - 1;
251
252 BOTAN_ASSERT_NOMSG(n >= t);
253
254 BigInt q = BigInt::zero();
255 q.grow_to(n - t + 1);
256
257 word* q_words = q.mutable_data();
258
259 BigInt shifted_y = y << (WB * (n - t));
260
261 // Set q_{n-t} to number of times r > shifted_y
263 q_words[n - t] = r.reduce_below(shifted_y, ws);
264
265 const word y_t0 = y.word_at(t);
266 const word y_t1 = y.word_at(t - 1);
267 BOTAN_DEBUG_ASSERT((y_t0 >> (WB - 1)) == 1);
268
269 const divide_precomp div_y_t0(y_t0);
270
271 for(size_t i = n; i != t; --i) {
272 const word x_i0 = r.word_at(i);
273 const word x_i1 = r.word_at(i - 1);
274 const word x_i2 = r.word_at(i - 2);
275
276 word qit = (x_i0 == y_t0) ? WordInfo<word>::max : div_y_t0.vartime_div_2to1(x_i0, x_i1);
277
278 // Per HAC 14.23, this operation is required at most twice
279 for(size_t j = 0; j != 2; ++j) {
280 if(division_check_vartime(qit, y_t0, y_t1, x_i0, x_i1, x_i2)) {
281 BOTAN_ASSERT_NOMSG(qit > 0);
282 qit--;
283 } else {
284 break;
285 }
286 }
287
288 shifted_y >>= WB;
289 // Now shifted_y == y << (WB * (i-t-1))
290
291 /*
292 * Special case qit == 0 and qit == 1 which occurs relatively often here due to a
293 * combination of the fixed 2^k and in many cases the typical structure of
294 * public moduli (as this function is called by Barrett_Reduction::for_public_modulus).
295 *
296 * Over the test suite, about 5% of loop iterations have qit == 1 and 10% have qit == 0
297 */
298
299 if(qit != 0) {
300 if(qit == 1) {
301 r -= shifted_y;
302 } else {
303 r -= qit * shifted_y;
304 }
305
306 if(r.is_negative()) {
307 BOTAN_ASSERT_NOMSG(qit > 0);
308 qit--;
309 r += shifted_y;
311 }
312 }
313
314 q_words[i - t - 1] = qit;
315 }
316
317 return q;
318}
319
320/*
321* Solve x = q * y + r
322*
323* See Handbook of Applied Cryptography algorithm 14.20
324*/
325void vartime_divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt& r_out) {
326 constexpr size_t WB = WordInfo<word>::bits;
327
328 if(y_arg.is_zero()) {
329 throw Invalid_Argument("vartime_divide: cannot divide by zero");
330 }
331
332 const size_t y_words = y_arg.sig_words();
333
334 BOTAN_ASSERT_NOMSG(y_words > 0);
335
336 BigInt y = y_arg;
337
338 BigInt r = x;
339 BigInt q = BigInt::zero();
341
344
345 // Calculate shifts needed to normalize y with high bit set
346 const size_t shifts = y.top_bits_free();
347
348 if(shifts > 0) {
349 y <<= shifts;
350 r <<= shifts;
351 }
352
353 // we know y has not changed size, since we only shifted up to set high bit
354 const size_t t = y_words - 1;
355 const size_t n = std::max(y_words, r.sig_words()) - 1; // r may have changed size however
356
357 BOTAN_ASSERT_NOMSG(n >= t);
358
359 q.grow_to(n - t + 1);
360
361 word* q_words = q.mutable_data();
362
363 BigInt shifted_y = y << (WB * (n - t));
364
365 // Set q_{n-t} to number of times r > shifted_y
366 q_words[n - t] = r.reduce_below(shifted_y, ws);
367
368 const word y_t0 = y.word_at(t);
369 const word y_t1 = y.word_at(t - 1);
370 BOTAN_DEBUG_ASSERT((y_t0 >> (WB - 1)) == 1);
371
372 const divide_precomp div_y_t0(y_t0);
373
374 for(size_t i = n; i != t; --i) {
375 const word x_i0 = r.word_at(i);
376 const word x_i1 = r.word_at(i - 1);
377 const word x_i2 = r.word_at(i - 2);
378
379 word qit = (x_i0 == y_t0) ? WordInfo<word>::max : div_y_t0.vartime_div_2to1(x_i0, x_i1);
380
381 // Per HAC 14.23, this operation is required at most twice
382 for(size_t j = 0; j != 2; ++j) {
383 if(division_check_vartime(qit, y_t0, y_t1, x_i0, x_i1, x_i2)) {
384 BOTAN_ASSERT_NOMSG(qit > 0);
385 qit--;
386 } else {
387 break;
388 }
389 }
390
391 shifted_y >>= WB;
392 // Now shifted_y == y << (WB * (i-t-1))
393
394 if(qit != 0) {
395 r -= qit * shifted_y;
396 if(r.is_negative()) {
397 BOTAN_ASSERT_NOMSG(qit > 0);
398 qit--;
399 r += shifted_y;
401 }
402 }
403
404 q_words[i - t - 1] = qit;
405 }
406
407 if(shifts > 0) {
408 r >>= shifts;
409 }
410
411 sign_fixup(x, y_arg, q, r);
412
413 r_out = r;
414 q_out = q;
415}
416
417} // 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
static BigInt zero()
Definition bigint.h:50
size_t sig_words() const
Definition bigint.h:631
void conditionally_set_bit(size_t n, bool set_it)
Definition bigint.h:489
word * mutable_data()
Definition bigint.h:656
size_t size() const
Definition bigint.h:625
void grow_to(size_t n) const
Definition bigint.h:682
void flip_sign()
Definition bigint.h:602
size_t top_bits_free() const
Definition bigint.cpp:298
word word_at(size_t n) const
Definition bigint.h:563
void set_bit(size_t n)
Definition bigint.h:479
size_t bits() const
Definition bigint.cpp:307
const word * _data() const
Definition bigint.h:952
void ct_cond_swap(bool predicate, BigInt &other)
Definition bigint.cpp:507
bool is_zero() const
Definition bigint.h:473
size_t reduce_below(const BigInt &mod, secure_vector< word > &ws)
Definition bigint.cpp:329
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
static BigInt with_capacity(size_t n)
Definition bigint.cpp:51
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 > expand_top_bit(T v)
Definition ct_utils.h:415
constexpr W vartime_div_2to1(W n1, W n0) const
Definition mp_core.h:568
constexpr void bigint_cnd_swap(W cnd, W x[], W y[], size_t size)
Definition mp_core.h:29
void vartime_divide(const BigInt &x, const BigInt &y_arg, BigInt &q_out, BigInt &r_out)
Definition divide.cpp:325
word ct_mod_word(const BigInt &x, word y)
Definition divide.cpp:168
constexpr auto word_madd2(W a, W b, W *c) -> W
Definition mp_asmi.h:90
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:192
constexpr void bigint_shl1(W x[], size_t x_size, size_t x_words, size_t shift)
Definition mp_core.h:307
BigInt ct_modulo(const BigInt &x, const BigInt &y)
Definition divide.cpp:192
BigInt vartime_divide_pow2k(size_t k, const BigInt &y_arg)
Definition divide.cpp:225
void ct_divide(const BigInt &x, const BigInt &y, BigInt &q_out, BigInt &r_out)
Definition divide.cpp:51
void ct_divide_word(const BigInt &x, word y, BigInt &q_out, word &r_out)
Definition divide.cpp:123
BigInt ct_divide_pow2k(size_t k, const BigInt &y)
Definition divide.cpp:83
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
Definition types.h:119