Coverage Report

Created: 2026-09-19 06:39

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
20.1k
void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) {
22
20.1k
   q.cond_flip_sign(x.sign() != y.sign());
23
24
20.1k
   if(x.is_negative() && r.is_nonzero()) {
25
766
      q -= 1;
26
766
      r = y.abs() - r;
27
766
   }
28
20.1k
}
29
30
78.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
78.5k
   word y3 = 0;
37
78.5k
   y1 = word_madd2(q, y1, &y3);
38
78.5k
   y2 = word_madd2(q, y2, &y3);
39
40
78.5k
   if(x3 != y3) {
41
27.0k
      return (y3 > x3);
42
27.0k
   }
43
51.4k
   if(x2 != y2) {
44
47.5k
      return (y2 > x2);
45
47.5k
   }
46
3.83k
   return (y1 > x1);
47
51.4k
}
48
49
}  // namespace
50
51
471
void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out) {
52
471
   if(y.is_zero()) {
53
0
      throw Invalid_Argument("ct_divide: cannot divide by zero");
54
0
   }
55
56
471
   const size_t x_words = x.sig_words();
57
471
   const size_t y_words = y.sig_words();
58
59
471
   const size_t x_bits = x.bits();
60
61
471
   BigInt q = BigInt::with_capacity(x_words);
62
471
   BigInt r = BigInt::with_capacity(y_words);
63
471
   BigInt t = BigInt::with_capacity(y_words);  // a temporary
64
65
2.03M
   for(size_t i = 0; i != x_bits; ++i) {
66
2.02M
      const size_t b = x_bits - 1 - i;
67
2.02M
      const bool x_b = x.get_bit(b);
68
69
2.02M
      r <<= 1;
70
2.02M
      r.conditionally_set_bit(0, x_b);
71
72
2.02M
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
73
74
2.02M
      q.conditionally_set_bit(b, r_gte_y);
75
2.02M
      r.ct_cond_swap(r_gte_y, t);
76
2.02M
   }
77
78
471
   sign_fixup(x, y, q, r);
79
471
   r_out = r;
80
471
   q_out = q;
81
471
}
82
83
9.20k
BigInt ct_divide_pow2k(size_t k, const BigInt& y) {
84
9.20k
   BOTAN_ARG_CHECK(!y.is_zero(), "Cannot divide by zero");
85
9.20k
   BOTAN_ARG_CHECK(!y.is_negative(), "Negative divisor not supported");
86
9.20k
   BOTAN_ARG_CHECK(k > 1, "Invalid k");
87
88
9.20k
   const size_t x_bits = k + 1;
89
9.20k
   const size_t y_bits = y.bits();
90
91
9.20k
   if(x_bits < y_bits) {
92
0
      return BigInt::zero();
93
0
   }
94
95
9.20k
   BOTAN_ASSERT_NOMSG(y_bits >= 1);
96
9.20k
   const size_t x_words = (x_bits + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
97
9.20k
   const size_t y_words = y.sig_words();
98
99
9.20k
   BigInt q = BigInt::with_capacity(x_words);
100
9.20k
   BigInt r = BigInt::with_capacity(y_words + 1);
101
9.20k
   BigInt t = BigInt::with_capacity(y_words + 1);  // a temporary
102
103
9.20k
   r.set_bit(y_bits - 1);
104
3.61M
   for(size_t i = y_bits - 1; i != x_bits; ++i) {
105
3.60M
      const size_t b = x_bits - 1 - i;
106
107
3.60M
      if(i >= y_bits) {
108
3.59M
         bigint_shl1(r.mutable_data(), r.size(), r.size(), 1);
109
3.59M
      }
110
111
3.60M
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
112
113
3.60M
      q.conditionally_set_bit(b, r_gte_y);
114
115
3.60M
      bigint_cnd_swap(static_cast<word>(r_gte_y), r.mutable_data(), t.mutable_data(), y_words + 1);
116
3.60M
   }
117
118
   // No need for sign fixup
119
120
9.20k
   return q;
121
9.20k
}
122
123
21.4k
void ct_divide_word(const BigInt& x, word y, BigInt& q_out, word& r_out) {
124
21.4k
   if(y == 0) {
125
0
      throw Invalid_Argument("ct_divide_word: cannot divide by zero");
126
0
   }
127
128
21.4k
   const size_t x_words = x.sig_words();
129
21.4k
   const size_t x_bits = x.bits();
130
131
21.4k
   BigInt q = BigInt::with_capacity(x_words);
132
21.4k
   word r = 0;
133
134
17.9M
   for(size_t i = 0; i != x_bits; ++i) {
135
17.9M
      const size_t b = x_bits - 1 - i;
136
17.9M
      const bool x_b = x.get_bit(b);
137
138
17.9M
      const auto r_carry = CT::Mask<word>::expand_top_bit(r);
139
140
17.9M
      r <<= 1;
141
17.9M
      r += x_b;
142
143
17.9M
      const auto r_gte_y = CT::Mask<word>::is_gte(r, y) | r_carry;
144
17.9M
      q.conditionally_set_bit(b, r_gte_y.as_bool());
145
17.9M
      r = r_gte_y.select(r - y, r);
146
17.9M
   }
147
148
21.4k
   if(x.is_negative()) {
149
157
      q.flip_sign();
150
157
      if(r != 0) {
151
149
         --q;
152
149
         r = y - r;
153
149
      }
154
157
   }
155
156
21.4k
   r_out = r;
157
21.4k
   q_out = q;
158
21.4k
}
159
160
0
BigInt ct_divide_word(const BigInt& x, word y) {
161
0
   BigInt q;
162
0
   word r;
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 += 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
2.22k
BigInt ct_modulo(const BigInt& x, const BigInt& y) {
193
2.22k
   if(y.is_negative() || y.is_zero()) {
194
22
      throw Invalid_Argument("ct_modulo requires y > 0");
195
22
   }
196
197
2.20k
   const size_t y_words = y.sig_words();
198
199
2.20k
   const size_t x_bits = x.bits();
200
201
2.20k
   BigInt r = BigInt::with_capacity(y_words);
202
2.20k
   BigInt t = BigInt::with_capacity(y_words);
203
204
656k
   for(size_t i = 0; i != x_bits; ++i) {
205
654k
      const size_t b = x_bits - 1 - i;
206
654k
      const bool x_b = x.get_bit(b);
207
208
654k
      r <<= 1;
209
654k
      r.conditionally_set_bit(0, x_b);
210
211
654k
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r._data(), r.size(), y._data(), y_words) == 0;
212
213
654k
      r.ct_cond_swap(r_gte_y, t);
214
654k
   }
215
216
2.20k
   if(x.is_negative()) {
217
637
      if(r.is_nonzero()) {
218
618
         r = y - r;
219
618
      }
220
637
   }
221
222
2.20k
   return r;
223
2.22k
}
224
225
/*
226
* Solve x = q * y + r
227
*
228
* See Handbook of Applied Cryptography section 14.2.5
229
*/
230
19.6k
void vartime_divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt& r_out) {
231
19.6k
   if(y_arg.is_zero()) {
232
0
      throw Invalid_Argument("vartime_divide: cannot divide by zero");
233
0
   }
234
235
19.6k
   const size_t y_words = y_arg.sig_words();
236
237
19.6k
   BOTAN_ASSERT_NOMSG(y_words > 0);
238
239
19.6k
   BigInt y = y_arg;
240
241
19.6k
   BigInt r = x;
242
19.6k
   BigInt q = BigInt::zero();
243
19.6k
   secure_vector<word> ws;
244
245
19.6k
   r.set_sign(BigInt::Positive);
246
19.6k
   y.set_sign(BigInt::Positive);
247
248
   // Calculate shifts needed to normalize y with high bit set
249
19.6k
   const size_t shifts = y.top_bits_free();
250
251
19.6k
   if(shifts > 0) {
252
19.3k
      y <<= shifts;
253
19.3k
      r <<= shifts;
254
19.3k
   }
255
256
   // we know y has not changed size, since we only shifted up to set high bit
257
19.6k
   const size_t t = y_words - 1;
258
19.6k
   const size_t n = std::max(y_words, r.sig_words()) - 1;  // r may have changed size however
259
260
19.6k
   BOTAN_ASSERT_NOMSG(n >= t);
261
262
19.6k
   q.grow_to(n - t + 1);
263
264
19.6k
   word* q_words = q.mutable_data();
265
266
19.6k
   BigInt shifted_y = y << (WordInfo<word>::bits * (n - t));
267
268
   // Set q_{n-t} to number of times r > shifted_y
269
19.6k
   q_words[n - t] = r.reduce_below(shifted_y, ws);
270
271
19.6k
   const word y_t0 = y.word_at(t);
272
19.6k
   const word y_t1 = y.word_at(t - 1);
273
19.6k
   BOTAN_DEBUG_ASSERT((y_t0 >> (WordInfo<word>::bits - 1)) == 1);
274
275
84.4k
   for(size_t j = n; j != t; --j) {
276
64.7k
      const word x_j0 = r.word_at(j);
277
64.7k
      const word x_j1 = r.word_at(j - 1);
278
64.7k
      const word x_j2 = r.word_at(j - 2);
279
280
64.7k
      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
79.3k
      for(size_t k = 0; k != 2; ++k) {
284
78.5k
         if(division_check_vartime(qjt, y_t0, y_t1, x_j0, x_j1, x_j2)) {
285
14.6k
            qjt--;
286
63.9k
         } else {
287
63.9k
            break;
288
63.9k
         }
289
78.5k
      }
290
291
64.7k
      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
64.7k
      r -= qjt * shifted_y;
296
64.7k
      if(r.is_negative()) {
297
352
         qjt--;
298
352
         r += shifted_y;
299
352
         BOTAN_DEBUG_ASSERT(r.is_positive());
300
352
      }
301
302
64.7k
      q_words[j - t - 1] = qjt;
303
64.7k
   }
304
305
19.6k
   if(shifts > 0) {
306
19.3k
      r >>= shifts;
307
19.3k
   }
308
309
19.6k
   sign_fixup(x, y_arg, q, r);
310
311
19.6k
   r_out = r;
312
19.6k
   q_out = q;
313
19.6k
}
314
315
}  // namespace Botan