Coverage Report

Created: 2026-02-07 07:14

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