Coverage Report

Created: 2020-05-23 13:54

/src/botan/src/lib/math/bigint/divide.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Division Algorithm
3
* (C) 1999-2007,2012,2018 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/divide.h>
9
#include <botan/internal/mp_core.h>
10
#include <botan/internal/mp_madd.h>
11
#include <botan/internal/ct_utils.h>
12
#include <botan/internal/bit_ops.h>
13
14
namespace Botan {
15
16
namespace {
17
18
/*
19
* Handle signed operands, if necessary
20
*/
21
void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r)
22
2.36M
   {
23
2.36M
   q.cond_flip_sign(x.sign() != y.sign());
24
2.36M
25
2.36M
   if(x.is_negative() && r.is_nonzero())
26
1.18k
      {
27
1.18k
      q -= 1;
28
1.18k
      r = y.abs() - r;
29
1.18k
      }
30
2.36M
   }
31
32
inline bool division_check(word q, word y2, word y1,
33
                           word x3, word x2, word x1)
34
5.30M
   {
35
5.30M
   /*
36
5.30M
   Compute (y3,y2,y1) = (y2,y1) * q
37
5.30M
   and return true if (y3,y2,y1) > (x3,x2,x1)
38
5.30M
   */
39
5.30M
40
5.30M
   word y3 = 0;
41
5.30M
   y1 = word_madd2(q, y1, &y3);
42
5.30M
   y2 = word_madd2(q, y2, &y3);
43
5.30M
44
5.30M
   const word x[3] = { x1, x2, x3 };
45
5.30M
   const word y[3] = { y1, y2, y3 };
46
5.30M
47
5.30M
   return bigint_ct_is_lt(x, 3, y, 3).is_set();
48
5.30M
   }
49
50
}
51
52
void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out)
53
90.6k
   {
54
90.6k
   const size_t x_words = x.sig_words();
55
90.6k
   const size_t y_words = y.sig_words();
56
90.6k
57
90.6k
   const size_t x_bits = x.bits();
58
90.6k
59
90.6k
   BigInt q(BigInt::Positive, x_words);
60
90.6k
   BigInt r(BigInt::Positive, y_words);
61
90.6k
   BigInt t(BigInt::Positive, y_words); // a temporary
62
90.6k
63
141M
   for(size_t i = 0; i != x_bits; ++i)
64
141M
      {
65
141M
      const size_t b = x_bits - 1 - i;
66
141M
      const bool x_b = x.get_bit(b);
67
141M
68
141M
      r *= 2;
69
141M
      r.conditionally_set_bit(0, x_b);
70
141M
71
141M
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0;
72
141M
73
141M
      q.conditionally_set_bit(b, r_gte_y);
74
141M
      r.ct_cond_swap(r_gte_y, t);
75
141M
      }
76
90.6k
77
90.6k
   sign_fixup(x, y, q, r);
78
90.6k
   r_out = r;
79
90.6k
   q_out = q;
80
90.6k
   }
81
82
void ct_divide_u8(const BigInt& x, uint8_t y, BigInt& q_out, uint8_t& r_out)
83
718
   {
84
718
   const size_t x_words = x.sig_words();
85
718
   const size_t x_bits = x.bits();
86
718
87
718
   BigInt q(BigInt::Positive, x_words);
88
718
   uint32_t r = 0;
89
718
90
635k
   for(size_t i = 0; i != x_bits; ++i)
91
634k
      {
92
634k
      const size_t b = x_bits - 1 - i;
93
634k
      const bool x_b = x.get_bit(b);
94
634k
95
634k
      r *= 2;
96
634k
      r += x_b;
97
634k
98
634k
      const auto r_gte_y = CT::Mask<uint32_t>::is_gte(r, y);
99
634k
100
634k
      q.conditionally_set_bit(b, r_gte_y.is_set());
101
634k
      r = r_gte_y.select(r - y, r);
102
634k
      }
103
718
104
718
   if(x.is_negative())
105
0
      {
106
0
      q.flip_sign();
107
0
      if(r != 0)
108
0
         {
109
0
         --q;
110
0
         r = y - r;
111
0
         }
112
0
      }
113
718
114
718
   r_out = static_cast<uint8_t>(r);
115
718
   q_out = q;
116
718
   }
117
118
BigInt ct_modulo(const BigInt& x, const BigInt& y)
119
1.71k
   {
120
1.71k
   if(y.is_negative() || y.is_zero())
121
0
      throw Invalid_Argument("ct_modulo requires y > 0");
122
1.71k
123
1.71k
   const size_t y_words = y.sig_words();
124
1.71k
125
1.71k
   const size_t x_bits = x.bits();
126
1.71k
127
1.71k
   BigInt r(BigInt::Positive, y_words);
128
1.71k
   BigInt t(BigInt::Positive, y_words);
129
1.71k
130
1.87M
   for(size_t i = 0; i != x_bits; ++i)
131
1.87M
      {
132
1.87M
      const size_t b = x_bits - 1 - i;
133
1.87M
      const bool x_b = x.get_bit(b);
134
1.87M
135
1.87M
      r *= 2;
136
1.87M
      r.conditionally_set_bit(0, x_b);
137
1.87M
138
1.87M
      const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0;
139
1.87M
140
1.87M
      r.ct_cond_swap(r_gte_y, t);
141
1.87M
      }
142
1.71k
143
1.71k
   if(x.is_negative())
144
397
      {
145
397
      if(r.is_nonzero())
146
292
         {
147
292
         r = y - r;
148
292
         }
149
397
      }
150
1.71k
151
1.71k
   return r;
152
1.71k
   }
153
154
/*
155
* Solve x = q * y + r
156
*
157
* See Handbook of Applied Cryptography section 14.2.5
158
*/
159
void divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt& r_out)
160
2.27M
   {
161
2.27M
   if(y_arg.is_zero())
162
0
      throw BigInt::DivideByZero();
163
2.27M
164
2.27M
   const size_t y_words = y_arg.sig_words();
165
2.27M
166
2.27M
   BOTAN_ASSERT_NOMSG(y_words > 0);
167
2.27M
168
2.27M
   BigInt y = y_arg;
169
2.27M
170
2.27M
   BigInt r = x;
171
2.27M
   BigInt q = 0;
172
2.27M
   secure_vector<word> ws;
173
2.27M
174
2.27M
   r.set_sign(BigInt::Positive);
175
2.27M
   y.set_sign(BigInt::Positive);
176
2.27M
177
2.27M
   // Calculate shifts needed to normalize y with high bit set
178
2.27M
   const size_t shifts = y.top_bits_free();
179
2.27M
180
2.27M
   y <<= shifts;
181
2.27M
   r <<= shifts;
182
2.27M
183
2.27M
   // we know y has not changed size, since we only shifted up to set high bit
184
2.27M
   const size_t t = y_words - 1;
185
2.27M
   const size_t n = std::max(y_words, r.sig_words()) - 1; // r may have changed size however
186
2.27M
187
2.27M
   BOTAN_ASSERT_NOMSG(n >= t);
188
2.27M
189
2.27M
   q.grow_to(n - t + 1);
190
2.27M
191
2.27M
   word* q_words = q.mutable_data();
192
2.27M
193
2.27M
   BigInt shifted_y = y << (BOTAN_MP_WORD_BITS * (n-t));
194
2.27M
195
2.27M
   // Set q_{n-t} to number of times r > shifted_y
196
2.27M
   q_words[n-t] = r.reduce_below(shifted_y, ws);
197
2.27M
198
2.27M
   const word y_t0  = y.word_at(t);
199
2.27M
   const word y_t1  = y.word_at(t-1);
200
2.27M
   BOTAN_DEBUG_ASSERT((y_t0 >> (BOTAN_MP_WORD_BITS-1)) == 1);
201
2.27M
202
4.92M
   for(size_t j = n; j != t; --j)
203
2.65M
      {
204
2.65M
      const word x_j0  = r.word_at(j);
205
2.65M
      const word x_j1 = r.word_at(j-1);
206
2.65M
      const word x_j2 = r.word_at(j-2);
207
2.65M
208
2.65M
      word qjt = bigint_divop(x_j0, x_j1, y_t0);
209
2.65M
210
2.65M
      qjt = CT::Mask<word>::is_equal(x_j0, y_t0).select(MP_WORD_MAX, qjt);
211
2.65M
212
2.65M
      // Per HAC 14.23, this operation is required at most twice
213
2.65M
      qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2);
214
2.65M
      qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2);
215
2.65M
      BOTAN_DEBUG_ASSERT(division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2) == false);
216
2.65M
217
2.65M
      shifted_y >>= BOTAN_MP_WORD_BITS;
218
2.65M
      // Now shifted_y == y << (BOTAN_MP_WORD_BITS * (j-t-1))
219
2.65M
220
2.65M
      // TODO this sequence could be better
221
2.65M
      r -= qjt * shifted_y;
222
2.65M
      qjt -= r.is_negative();
223
2.65M
      r += static_cast<word>(r.is_negative()) * shifted_y;
224
2.65M
225
2.65M
      q_words[j-t-1] = qjt;
226
2.65M
      }
227
2.27M
228
2.27M
   r >>= shifts;
229
2.27M
230
2.27M
   sign_fixup(x, y_arg, q, r);
231
2.27M
232
2.27M
   r_out = r;
233
2.27M
   q_out = q;
234
2.27M
   }
235
236
}