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