Coverage Report

Created: 2026-08-14 07:11

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/bit_ops.h>
11
#include <botan/internal/ct_utils.h>
12
#include <botan/internal/mp_core.h>
13
14
namespace Botan {
15
16
namespace {
17
18
/*
19
* Handle signed operands, if necessary
20
*/
21
13.2k
void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) {
22
13.2k
   q.cond_flip_sign(x.sign() != y.sign());
23
24
13.2k
   if(x.is_negative() && r.is_nonzero()) {
25
185
      q -= 1;
26
185
      r = y.abs() - r;
27
185
   }
28
13.2k
}
29
30
50.5k
inline 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
50.5k
   word y3 = 0;
37
50.5k
   y1 = word_madd2(q, y1, &y3);
38
50.5k
   y2 = word_madd2(q, y2, &y3);
39
40
50.5k
   if(x3 != y3) {
41
18.6k
      return (y3 > x3);
42
18.6k
   }
43
31.8k
   if(x2 != y2) {
44
31.3k
      return (y2 > x2);
45
31.3k
   }
46
576
   return (y1 > x1);
47
31.8k
}
48
49
}  // namespace
50
51
0
void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out) {
52
0
   if(y.is_zero()) {
53
0
      throw Invalid_Argument("ct_divide: cannot divide by zero");
54
0
   }
55
56
0
   const size_t x_words = x.sig_words();
57
0
   const size_t y_words = y.sig_words();
58
59
0
   const size_t x_bits = x.bits();
60
61
0
   BigInt q = BigInt::with_capacity(x_words);
62
0
   BigInt r = BigInt::with_capacity(y_words);
63
0
   BigInt t = BigInt::with_capacity(y_words);  // a temporary
64
65
0
   for(size_t i = 0; i != x_bits; ++i) {
66
0
      const size_t b = x_bits - 1 - i;
67
0
      const bool x_b = x.get_bit(b);
68
69
0
      r <<= 1;
70
0
      r.conditionally_set_bit(0, x_b);
71
72
0
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
73
74
0
      q.conditionally_set_bit(b, r_gte_y);
75
0
      r.ct_cond_swap(r_gte_y, t);
76
0
   }
77
78
0
   sign_fixup(x, y, q, r);
79
0
   r_out = r;
80
0
   q_out = q;
81
0
}
82
83
40
BigInt ct_divide_pow2k(size_t k, const BigInt& y) {
84
40
   BOTAN_ARG_CHECK(!y.is_zero(), "Cannot divide by zero");
85
40
   BOTAN_ARG_CHECK(!y.is_negative(), "Negative divisor not supported");
86
40
   BOTAN_ARG_CHECK(k > 1, "Invalid k");
87
88
40
   const size_t x_bits = k + 1;
89
40
   const size_t y_bits = y.bits();
90
91
40
   if(x_bits < y_bits) {
92
0
      return BigInt::zero();
93
0
   }
94
95
40
   BOTAN_ASSERT_NOMSG(y_bits >= 1);
96
40
   const size_t x_words = (x_bits + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
97
40
   const size_t y_words = y.sig_words();
98
99
40
   BigInt q = BigInt::with_capacity(x_words);
100
40
   BigInt r = BigInt::with_capacity(y_words + 1);
101
40
   BigInt t = BigInt::with_capacity(y_words + 1);  // a temporary
102
103
40
   r.set_bit(y_bits - 1);
104
12.3k
   for(size_t i = y_bits - 1; i != x_bits; ++i) {
105
12.3k
      const size_t b = x_bits - 1 - i;
106
107
12.3k
      if(i >= y_bits) {
108
12.2k
         bigint_shl1(r.mutable_data(), r.size(), r.size(), 1);
109
12.2k
      }
110
111
12.3k
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
112
113
12.3k
      q.conditionally_set_bit(b, r_gte_y);
114
115
12.3k
      bigint_cnd_swap(static_cast<word>(r_gte_y), r.mutable_data(), t.mutable_data(), y_words + 1);
116
12.3k
   }
117
118
   // No need for sign fixup
119
120
40
   return q;
121
40
}
122
123
25.8k
void ct_divide_word(const BigInt& x, word y, BigInt& q_out, word& r_out) {
124
25.8k
   if(y == 0) {
125
0
      throw Invalid_Argument("ct_divide_word: cannot divide by zero");
126
0
   }
127
128
25.8k
   const size_t x_words = x.sig_words();
129
25.8k
   const size_t x_bits = x.bits();
130
131
25.8k
   BigInt q = BigInt::with_capacity(x_words);
132
25.8k
   word r = 0;
133
134
3.38M
   for(size_t i = 0; i != x_bits; ++i) {
135
3.36M
      const size_t b = x_bits - 1 - i;
136
3.36M
      const bool x_b = x.get_bit(b);
137
138
3.36M
      const auto r_carry = CT::Mask<word>::expand_top_bit(r);
139
140
3.36M
      r <<= 1;
141
3.36M
      r += static_cast<word>(x_b);
142
143
3.36M
      const auto r_gte_y = CT::Mask<word>::is_gte(r, y) | r_carry;
144
3.36M
      q.conditionally_set_bit(b, r_gte_y.as_bool());
145
3.36M
      r = r_gte_y.select(r - y, r);
146
3.36M
   }
147
148
25.8k
   if(x.is_negative()) {
149
0
      q.flip_sign();
150
0
      if(r != 0) {
151
0
         --q;
152
0
         r = y - r;
153
0
      }
154
0
   }
155
156
25.8k
   r_out = r;
157
25.8k
   q_out = q;
158
25.8k
}
159
160
0
BigInt ct_divide_word(const BigInt& x, word y) {
161
0
   BigInt q;
162
0
   word r = 0;
163
0
   ct_divide_word(x, y, q, r);
164
0
   BOTAN_UNUSED(r);
165
0
   return q;
166
0
}
167
168
0
word ct_mod_word(const BigInt& x, word y) {
169
0
   BOTAN_ARG_CHECK(x.is_positive(), "The argument x must be positive");
170
0
   BOTAN_ARG_CHECK(y != 0, "Cannot divide by zero");
171
172
0
   const size_t x_bits = x.bits();
173
174
0
   word r = 0;
175
176
0
   for(size_t i = 0; i != x_bits; ++i) {
177
0
      const size_t b = x_bits - 1 - i;
178
0
      const bool x_b = x.get_bit(b);
179
180
0
      const auto r_carry = CT::Mask<word>::expand_top_bit(r);
181
182
0
      r <<= 1;
183
0
      r += static_cast<word>(x_b);
184
185
0
      const auto r_gte_y = CT::Mask<word>::is_gte(r, y) | r_carry;
186
0
      r = r_gte_y.select(r - y, r);
187
0
   }
188
189
0
   return r;
190
0
}
191
192
52
BigInt ct_modulo(const BigInt& x, const BigInt& y) {
193
52
   if(y.is_negative() || y.is_zero()) {
194
0
      throw Invalid_Argument("ct_modulo requires y > 0");
195
0
   }
196
197
52
   const size_t y_words = y.sig_words();
198
199
52
   const size_t x_bits = x.bits();
200
201
52
   BigInt r = BigInt::with_capacity(y_words);
202
52
   BigInt t = BigInt::with_capacity(y_words);
203
204
27.4k
   for(size_t i = 0; i != x_bits; ++i) {
205
27.4k
      const size_t b = x_bits - 1 - i;
206
27.4k
      const bool x_b = x.get_bit(b);
207
208
27.4k
      r <<= 1;
209
27.4k
      r.conditionally_set_bit(0, x_b);
210
211
27.4k
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
212
213
27.4k
      r.ct_cond_swap(r_gte_y, t);
214
27.4k
   }
215
216
52
   if(x.is_negative()) {
217
0
      if(r.is_nonzero()) {
218
0
         r = y - r;
219
0
      }
220
0
   }
221
222
52
   return r;
223
52
}
224
225
/*
226
* Solve x = q * y + r
227
*
228
* See Handbook of Applied Cryptography section 14.2.5
229
*/
230
13.2k
void vartime_divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt& r_out) {
231
13.2k
   if(y_arg.is_zero()) {
232
0
      throw Invalid_Argument("vartime_divide: cannot divide by zero");
233
0
   }
234
235
13.2k
   const size_t y_words = y_arg.sig_words();
236
237
13.2k
   BOTAN_ASSERT_NOMSG(y_words > 0);
238
239
13.2k
   BigInt y = y_arg;
240
241
13.2k
   BigInt r = x;
242
13.2k
   BigInt q = BigInt::zero();
243
13.2k
   secure_vector<word> ws;
244
245
13.2k
   r.set_sign(BigInt::Positive);
246
13.2k
   y.set_sign(BigInt::Positive);
247
248
   // Calculate shifts needed to normalize y with high bit set
249
13.2k
   const size_t shifts = y.top_bits_free();
250
251
13.2k
   if(shifts > 0) {
252
13.1k
      y <<= shifts;
253
13.1k
      r <<= shifts;
254
13.1k
   }
255
256
   // we know y has not changed size, since we only shifted up to set high bit
257
13.2k
   const size_t t = y_words - 1;
258
13.2k
   const size_t n = std::max(y_words, r.sig_words()) - 1;  // r may have changed size however
259
260
13.2k
   BOTAN_ASSERT_NOMSG(n >= t);
261
262
13.2k
   q.grow_to(n - t + 1);
263
264
13.2k
   word* q_words = q.mutable_data();
265
266
13.2k
   BigInt shifted_y = y << (WordInfo<word>::bits * (n - t));
267
268
   // Set q_{n-t} to number of times r > shifted_y
269
13.2k
   q_words[n - t] = r.reduce_below(shifted_y, ws);
270
271
13.2k
   const word y_t0 = y.word_at(t);
272
13.2k
   const word y_t1 = y.word_at(t - 1);
273
13.2k
   BOTAN_DEBUG_ASSERT((y_t0 >> (WordInfo<word>::bits - 1)) == 1);
274
275
57.3k
   for(size_t j = n; j != t; --j) {
276
44.0k
      const word x_j0 = r.word_at(j);
277
44.0k
      const word x_j1 = r.word_at(j - 1);
278
44.0k
      const word x_j2 = r.word_at(j - 2);
279
280
44.0k
      word qjt = (x_j0 == y_t0) ? WordInfo<word>::max : bigint_divop_vartime(x_j0, x_j1, y_t0);
281
282
      // Per HAC 14.23, this operation is required at most twice
283
50.5k
      for(size_t k = 0; k != 2; ++k) {
284
50.5k
         if(division_check_vartime(qjt, y_t0, y_t1, x_j0, x_j1, x_j2)) {
285
6.52k
            qjt--;
286
44.0k
         } else {
287
44.0k
            break;
288
44.0k
         }
289
50.5k
      }
290
291
44.0k
      shifted_y >>= WordInfo<word>::bits;
292
      // Now shifted_y == y << (WordInfo<word>::bits * (j-t-1))
293
294
      // TODO this sequence could be better
295
44.0k
      r -= qjt * shifted_y;
296
44.0k
      if(r.is_negative()) {
297
52
         qjt--;
298
52
         r += shifted_y;
299
52
         BOTAN_ASSERT_NOMSG(r.is_positive());
300
52
      }
301
302
44.0k
      q_words[j - t - 1] = qjt;
303
44.0k
   }
304
305
13.2k
   if(shifts > 0) {
306
13.1k
      r >>= shifts;
307
13.1k
   }
308
309
13.2k
   sign_fixup(x, y_arg, q, r);
310
311
13.2k
   r_out = r;
312
13.2k
   q_out = q;
313
13.2k
}
314
315
}  // namespace Botan