Coverage Report

Created: 2023-12-08 07:00

/src/botan/src/lib/math/bigint/big_ops2.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 1999-2007,2018 Jack Lloyd
3
*     2016 Matthias Gierlings
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/bigint.h>
9
10
#include <botan/internal/bit_ops.h>
11
#include <botan/internal/mp_core.h>
12
#include <algorithm>
13
14
namespace Botan {
15
16
7.59M
BigInt& BigInt::add(const word y[], size_t y_words, Sign y_sign) {
17
7.59M
   const size_t x_sw = sig_words();
18
19
7.59M
   grow_to(std::max(x_sw, y_words) + 1);
20
21
7.59M
   if(sign() == y_sign) {
22
7.51M
      bigint_add2(mutable_data(), size() - 1, y, y_words);
23
7.51M
   } else {
24
78.0k
      const int32_t relative_size = bigint_cmp(data(), x_sw, y, y_words);
25
26
78.0k
      if(relative_size >= 0) {
27
         // *this >= y
28
66.0k
         bigint_sub2(mutable_data(), x_sw, y, y_words);
29
66.0k
      } else {
30
         // *this < y
31
11.9k
         bigint_sub2_rev(mutable_data(), y, y_words);
32
11.9k
      }
33
34
      //this->sign_fixup(relative_size, y_sign);
35
78.0k
      if(relative_size < 0) {
36
11.9k
         set_sign(y_sign);
37
66.0k
      } else if(relative_size == 0) {
38
150
         set_sign(Positive);
39
150
      }
40
78.0k
   }
41
42
7.59M
   return (*this);
43
7.59M
}
44
45
2.90k
BigInt& BigInt::mod_add(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) {
46
2.90k
   if(this->is_negative() || s.is_negative() || mod.is_negative()) {
47
0
      throw Invalid_Argument("BigInt::mod_add expects all arguments are positive");
48
0
   }
49
50
2.90k
   BOTAN_DEBUG_ASSERT(*this < mod);
51
2.90k
   BOTAN_DEBUG_ASSERT(s < mod);
52
53
   /*
54
   t + s or t + s - p == t - (p - s)
55
56
   So first compute ws = p - s
57
58
   Then compute t + s and t - ws
59
60
   If t - ws does not borrow, then that is the correct valued
61
   */
62
63
2.90k
   const size_t mod_sw = mod.sig_words();
64
2.90k
   BOTAN_ARG_CHECK(mod_sw > 0, "BigInt::mod_add modulus must be positive");
65
66
2.90k
   this->grow_to(mod_sw);
67
2.90k
   s.grow_to(mod_sw);
68
69
   // First mod_sw for p - s, 2*mod_sw for bigint_addsub workspace
70
2.90k
   if(ws.size() < 3 * mod_sw) {
71
868
      ws.resize(3 * mod_sw);
72
868
   }
73
74
2.90k
   word borrow = bigint_sub3(&ws[0], mod.data(), mod_sw, s.data(), mod_sw);
75
2.90k
   BOTAN_DEBUG_ASSERT(borrow == 0);
76
2.90k
   BOTAN_UNUSED(borrow);
77
78
   // Compute t - ws
79
2.90k
   borrow = bigint_sub3(&ws[mod_sw], this->data(), mod_sw, &ws[0], mod_sw);
80
81
   // Compute t + s
82
2.90k
   bigint_add3_nc(&ws[mod_sw * 2], this->data(), mod_sw, s.data(), mod_sw);
83
84
2.90k
   CT::conditional_copy_mem(borrow, &ws[0], &ws[mod_sw * 2], &ws[mod_sw], mod_sw);
85
2.90k
   set_words(&ws[0], mod_sw);
86
87
2.90k
   return (*this);
88
2.90k
}
89
90
40.1k
BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) {
91
40.1k
   if(this->is_negative() || s.is_negative() || mod.is_negative()) {
92
0
      throw Invalid_Argument("BigInt::mod_sub expects all arguments are positive");
93
0
   }
94
95
   // We are assuming in this function that *this and s are no more than mod_sw words long
96
40.1k
   BOTAN_DEBUG_ASSERT(*this < mod);
97
40.1k
   BOTAN_DEBUG_ASSERT(s < mod);
98
99
40.1k
   const size_t mod_sw = mod.sig_words();
100
101
40.1k
   this->grow_to(mod_sw);
102
40.1k
   s.grow_to(mod_sw);
103
104
40.1k
   if(ws.size() < mod_sw) {
105
0
      ws.resize(mod_sw);
106
0
   }
107
108
40.1k
   if(mod_sw == 4) {
109
0
      bigint_mod_sub_n<4>(mutable_data(), s.data(), mod.data(), ws.data());
110
40.1k
   } else if(mod_sw == 6) {
111
0
      bigint_mod_sub_n<6>(mutable_data(), s.data(), mod.data(), ws.data());
112
40.1k
   } else {
113
40.1k
      bigint_mod_sub(mutable_data(), s.data(), mod.data(), mod_sw, ws.data());
114
40.1k
   }
115
116
40.1k
   return (*this);
117
40.1k
}
118
119
11.6k
BigInt& BigInt::mod_mul(uint8_t y, const BigInt& mod, secure_vector<word>& ws) {
120
11.6k
   BOTAN_ARG_CHECK(this->is_negative() == false, "*this must be positive");
121
11.6k
   BOTAN_ARG_CHECK(y < 16, "y too large");
122
123
11.6k
   BOTAN_DEBUG_ASSERT(*this < mod);
124
125
11.6k
   *this *= static_cast<word>(y);
126
11.6k
   this->reduce_below(mod, ws);
127
11.6k
   return (*this);
128
11.6k
}
129
130
3.50M
BigInt& BigInt::rev_sub(const word y[], size_t y_sw, secure_vector<word>& ws) {
131
3.50M
   if(this->sign() != BigInt::Positive) {
132
0
      throw Invalid_State("BigInt::sub_rev requires this is positive");
133
0
   }
134
135
3.50M
   const size_t x_sw = this->sig_words();
136
137
3.50M
   ws.resize(std::max(x_sw, y_sw));
138
3.50M
   clear_mem(ws.data(), ws.size());
139
140
3.50M
   const int32_t relative_size = bigint_sub_abs(ws.data(), data(), x_sw, y, y_sw);
141
142
3.50M
   this->cond_flip_sign(relative_size > 0);
143
3.50M
   this->swap_reg(ws);
144
145
3.50M
   return (*this);
146
3.50M
}
147
148
/*
149
* Multiplication Operator
150
*/
151
104
BigInt& BigInt::operator*=(const BigInt& y) {
152
104
   secure_vector<word> ws;
153
104
   return this->mul(y, ws);
154
104
}
155
156
7.00M
BigInt& BigInt::mul(const BigInt& y, secure_vector<word>& ws) {
157
7.00M
   const size_t x_sw = sig_words();
158
7.00M
   const size_t y_sw = y.sig_words();
159
7.00M
   set_sign((sign() == y.sign()) ? Positive : Negative);
160
161
7.00M
   if(x_sw == 0 || y_sw == 0) {
162
1.12M
      clear();
163
1.12M
      set_sign(Positive);
164
5.88M
   } else if(x_sw == 1 && y_sw) {
165
2.92M
      grow_to(y_sw + 1);
166
2.92M
      bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0));
167
2.96M
   } else if(y_sw == 1 && x_sw) {
168
7
      word carry = bigint_linmul2(mutable_data(), x_sw, y.word_at(0));
169
7
      set_word_at(x_sw, carry);
170
2.96M
   } else {
171
2.96M
      const size_t new_size = x_sw + y_sw + 1;
172
2.96M
      ws.resize(new_size);
173
2.96M
      secure_vector<word> z_reg(new_size);
174
175
2.96M
      bigint_mul(z_reg.data(), z_reg.size(), data(), size(), x_sw, y.data(), y.size(), y_sw, ws.data(), ws.size());
176
177
2.96M
      this->swap_reg(z_reg);
178
2.96M
   }
179
180
7.00M
   return (*this);
181
7.00M
}
182
183
1.05M
BigInt& BigInt::square(secure_vector<word>& ws) {
184
1.05M
   const size_t sw = sig_words();
185
186
1.05M
   secure_vector<word> z(2 * sw);
187
1.05M
   ws.resize(z.size());
188
189
1.05M
   bigint_sqr(z.data(), z.size(), data(), size(), sw, ws.data(), ws.size());
190
191
1.05M
   swap_reg(z);
192
1.05M
   set_sign(BigInt::Positive);
193
194
1.05M
   return (*this);
195
1.05M
}
196
197
17.7M
BigInt& BigInt::operator*=(word y) {
198
17.7M
   if(y == 0) {
199
0
      clear();
200
0
      set_sign(Positive);
201
0
   }
202
203
17.7M
   const word carry = bigint_linmul2(mutable_data(), size(), y);
204
17.7M
   set_word_at(size(), carry);
205
206
17.7M
   return (*this);
207
17.7M
}
208
209
/*
210
* Division Operator
211
*/
212
0
BigInt& BigInt::operator/=(const BigInt& y) {
213
0
   if(y.sig_words() == 1 && is_power_of_2(y.word_at(0))) {
214
0
      (*this) >>= (y.bits() - 1);
215
0
   } else {
216
0
      (*this) = (*this) / y;
217
0
   }
218
0
   return (*this);
219
0
}
220
221
/*
222
* Modulo Operator
223
*/
224
68.2k
BigInt& BigInt::operator%=(const BigInt& mod) {
225
68.2k
   return (*this = (*this) % mod);
226
68.2k
}
227
228
/*
229
* Modulo Operator
230
*/
231
0
word BigInt::operator%=(word mod) {
232
0
   if(mod == 0) {
233
0
      throw Invalid_Argument("BigInt::operator%= divide by zero");
234
0
   }
235
236
0
   word remainder = 0;
237
238
0
   if(is_power_of_2(mod)) {
239
0
      remainder = (word_at(0) & (mod - 1));
240
0
   } else {
241
0
      const size_t sw = sig_words();
242
0
      for(size_t i = sw; i > 0; --i) {
243
0
         remainder = bigint_modop(remainder, word_at(i - 1), mod);
244
0
      }
245
0
   }
246
247
0
   if(remainder && sign() == BigInt::Negative) {
248
0
      remainder = mod - remainder;
249
0
   }
250
251
0
   m_data.set_to_zero();
252
0
   m_data.set_word_at(0, remainder);
253
0
   set_sign(BigInt::Positive);
254
0
   return remainder;
255
0
}
256
257
/*
258
* Left Shift Operator
259
*/
260
89.3k
BigInt& BigInt::operator<<=(size_t shift) {
261
89.3k
   const size_t shift_words = shift / BOTAN_MP_WORD_BITS;
262
89.3k
   const size_t shift_bits = shift % BOTAN_MP_WORD_BITS;
263
89.3k
   const size_t size = sig_words();
264
265
89.3k
   const size_t bits_free = top_bits_free();
266
267
89.3k
   const size_t new_size = size + shift_words + (bits_free < shift_bits);
268
269
89.3k
   m_data.grow_to(new_size);
270
271
89.3k
   bigint_shl1(m_data.mutable_data(), new_size, size, shift_words, shift_bits);
272
273
89.3k
   return (*this);
274
89.3k
}
275
276
/*
277
* Right Shift Operator
278
*/
279
9.74M
BigInt& BigInt::operator>>=(size_t shift) {
280
9.74M
   const size_t shift_words = shift / BOTAN_MP_WORD_BITS;
281
9.74M
   const size_t shift_bits = shift % BOTAN_MP_WORD_BITS;
282
283
9.74M
   bigint_shr1(m_data.mutable_data(), m_data.size(), shift_words, shift_bits);
284
285
9.74M
   if(is_negative() && is_zero()) {
286
0
      set_sign(Positive);
287
0
   }
288
289
9.74M
   return (*this);
290
9.74M
}
291
292
}  // namespace Botan