Coverage Report

Created: 2026-10-28 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/math/bigint/big_ops2.cpp
Line
Count
Source
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
8.39M
BigInt& BigInt::add(const word y[], size_t y_words, Sign y_sign) {
17
8.39M
   const size_t x_sw = sig_words();
18
19
8.39M
   grow_to(std::max(x_sw, y_words) + 1);
20
21
8.39M
   if(sign() == y_sign) {
22
8.33M
      bigint_add2(mutable_data(), size() - 1, y, y_words);
23
8.33M
   } else {
24
61.1k
      const int32_t relative_size = bigint_cmp(_data(), x_sw, y, y_words);
25
26
61.1k
      if(relative_size >= 0) {
27
         // *this >= y
28
59.0k
         bigint_sub2(mutable_data(), x_sw, y, y_words);
29
59.0k
      } else {
30
         // *this < y
31
2.08k
         bigint_sub2_rev(mutable_data(), y, y_words);
32
2.08k
      }
33
34
      //this->sign_fixup(relative_size, y_sign);
35
61.1k
      if(relative_size < 0) {
36
2.08k
         set_sign(y_sign);
37
59.0k
      } else if(relative_size == 0) {
38
283
         set_sign(Positive);
39
283
      }
40
61.1k
   }
41
42
8.39M
   return (*this);
43
8.39M
}
44
45
1.04k
BigInt& BigInt::mod_add(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) {
46
1.04k
   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
1.04k
   BOTAN_DEBUG_ASSERT(*this < mod);
51
1.04k
   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
1.04k
   const size_t mod_sw = mod.sig_words();
64
1.04k
   BOTAN_ARG_CHECK(mod_sw > 0, "BigInt::mod_add modulus must be positive");
65
66
1.04k
   this->grow_to(mod_sw);
67
1.04k
   s.grow_to(mod_sw);
68
69
   // First mod_sw for p - s, 2*mod_sw for bigint_addsub workspace
70
1.04k
   if(ws.size() < 3 * mod_sw) {
71
320
      ws.resize(3 * mod_sw);
72
320
   }
73
74
1.04k
   word borrow = bigint_sub3(&ws[0], mod._data(), mod_sw, s._data(), mod_sw);
75
1.04k
   BOTAN_DEBUG_ASSERT(borrow == 0);
76
1.04k
   BOTAN_UNUSED(borrow);
77
78
   // Compute t - ws
79
1.04k
   borrow = bigint_sub3(&ws[mod_sw], this->_data(), mod_sw, &ws[0], mod_sw);
80
81
   // Compute t + s
82
1.04k
   bigint_add3_nc(&ws[mod_sw * 2], this->_data(), mod_sw, s._data(), mod_sw);
83
84
1.04k
   CT::conditional_copy_mem(borrow, &ws[0], &ws[mod_sw * 2], &ws[mod_sw], mod_sw);
85
1.04k
   set_words(&ws[0], mod_sw);
86
87
1.04k
   return (*this);
88
1.04k
}
89
90
14.2k
BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) {
91
14.2k
   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
14.2k
   BOTAN_DEBUG_ASSERT(*this < mod);
97
14.2k
   BOTAN_DEBUG_ASSERT(s < mod);
98
99
14.2k
   const size_t mod_sw = mod.sig_words();
100
101
14.2k
   this->grow_to(mod_sw);
102
14.2k
   s.grow_to(mod_sw);
103
104
14.2k
   if(ws.size() < mod_sw) {
105
0
      ws.resize(mod_sw);
106
0
   }
107
108
14.2k
   bigint_mod_sub(mutable_data(), s._data(), mod._data(), mod_sw, ws.data());
109
110
14.2k
   return (*this);
111
14.2k
}
112
113
4.17k
BigInt& BigInt::mod_mul(uint8_t y, const BigInt& mod, secure_vector<word>& ws) {
114
4.17k
   BOTAN_ARG_CHECK(this->is_negative() == false, "*this must be positive");
115
4.17k
   BOTAN_ARG_CHECK(y < 16, "y too large");
116
117
4.17k
   BOTAN_DEBUG_ASSERT(*this < mod);
118
119
4.17k
   *this *= static_cast<word>(y);
120
4.17k
   this->reduce_below(mod, ws);
121
4.17k
   return (*this);
122
4.17k
}
123
124
0
BigInt& BigInt::rev_sub(const word y[], size_t y_sw, secure_vector<word>& ws) {
125
0
   if(this->sign() != BigInt::Positive) {
126
0
      throw Invalid_State("BigInt::sub_rev requires this is positive");
127
0
   }
128
129
0
   const size_t x_sw = this->sig_words();
130
131
0
   ws.resize(std::max(x_sw, y_sw));
132
0
   clear_mem(ws.data(), ws.size());
133
134
0
   const int32_t relative_size = bigint_sub_abs(ws.data(), _data(), x_sw, y, y_sw);
135
136
0
   this->cond_flip_sign(relative_size > 0);
137
0
   this->swap_reg(ws);
138
139
0
   return (*this);
140
0
}
141
142
/*
143
* Multiplication Operator
144
*/
145
163
BigInt& BigInt::operator*=(const BigInt& y) {
146
163
   secure_vector<word> ws;
147
163
   return this->mul(y, ws);
148
163
}
149
150
163
BigInt& BigInt::mul(const BigInt& y, secure_vector<word>& ws) {
151
163
   const size_t x_sw = sig_words();
152
163
   const size_t y_sw = y.sig_words();
153
163
   set_sign((sign() == y.sign()) ? Positive : Negative);
154
155
163
   if(x_sw == 0 || y_sw == 0) {
156
21
      clear();
157
21
      set_sign(Positive);
158
142
   } else if(x_sw == 1 && y_sw) {
159
106
      grow_to(y_sw + 1);
160
106
      bigint_linmul3(mutable_data(), y._data(), y_sw, word_at(0));
161
106
   } else if(y_sw == 1 && x_sw) {
162
10
      word carry = bigint_linmul2(mutable_data(), x_sw, y.word_at(0));
163
10
      set_word_at(x_sw, carry);
164
26
   } else {
165
26
      const size_t new_size = x_sw + y_sw + 1;
166
26
      if(ws.size() < new_size) {
167
26
         ws.resize(new_size);
168
26
      }
169
26
      secure_vector<word> z_reg(new_size);
170
171
26
      bigint_mul(z_reg.data(), z_reg.size(), _data(), size(), x_sw, y._data(), y.size(), y_sw, ws.data(), ws.size());
172
173
26
      this->swap_reg(z_reg);
174
26
   }
175
176
163
   return (*this);
177
163
}
178
179
82
BigInt& BigInt::square(secure_vector<word>& ws) {
180
82
   const size_t sw = sig_words();
181
182
82
   secure_vector<word> z(2 * sw);
183
82
   ws.resize(z.size());
184
185
82
   bigint_sqr(z.data(), z.size(), _data(), size(), sw, ws.data(), ws.size());
186
187
82
   swap_reg(z);
188
82
   set_sign(BigInt::Positive);
189
190
82
   return (*this);
191
82
}
192
193
7.92M
BigInt& BigInt::operator*=(word y) {
194
7.92M
   if(y == 0) {
195
0
      clear();
196
0
      set_sign(Positive);
197
0
   }
198
199
7.92M
   const word carry = bigint_linmul2(mutable_data(), size(), y);
200
7.92M
   set_word_at(size(), carry);
201
202
7.92M
   return (*this);
203
7.92M
}
204
205
/*
206
* Division Operator
207
*/
208
0
BigInt& BigInt::operator/=(const BigInt& y) {
209
0
   if(y.sig_words() == 1 && is_power_of_2(y.word_at(0))) {
210
0
      (*this) >>= (y.bits() - 1);
211
0
   } else {
212
0
      (*this) = (*this) / y;
213
0
   }
214
0
   return (*this);
215
0
}
216
217
/*
218
* Modulo Operator
219
*/
220
21.5k
BigInt& BigInt::operator%=(const BigInt& mod) {
221
21.5k
   return (*this = (*this) % mod);
222
21.5k
}
223
224
/*
225
* Modulo Operator
226
*/
227
0
word BigInt::operator%=(word mod) {
228
0
   if(mod == 0) {
229
0
      throw Invalid_Argument("BigInt::operator%= divide by zero");
230
0
   }
231
232
0
   word remainder = 0;
233
234
0
   if(is_power_of_2(mod)) {
235
0
      remainder = (word_at(0) & (mod - 1));
236
0
   } else {
237
0
      const size_t sw = sig_words();
238
0
      for(size_t i = sw; i > 0; --i) {
239
0
         remainder = bigint_modop_vartime(remainder, word_at(i - 1), mod);
240
0
      }
241
0
   }
242
243
0
   if(remainder && sign() == BigInt::Negative) {
244
0
      remainder = mod - remainder;
245
0
   }
246
247
0
   m_data.set_to_zero();
248
0
   m_data.set_word_at(0, remainder);
249
0
   set_sign(BigInt::Positive);
250
0
   return remainder;
251
0
}
252
253
/*
254
* Left Shift Operator
255
*/
256
1.31M
BigInt& BigInt::operator<<=(size_t shift) {
257
1.31M
   const size_t sw = sig_words();
258
1.31M
   const size_t new_size = sw + (shift + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
259
260
1.31M
   m_data.grow_to(new_size);
261
262
1.31M
   bigint_shl1(m_data.mutable_data(), new_size, sw, shift);
263
264
1.31M
   return (*this);
265
1.31M
}
266
267
/*
268
* Right Shift Operator
269
*/
270
731k
BigInt& BigInt::operator>>=(size_t shift) {
271
731k
   bigint_shr1(m_data.mutable_data(), m_data.size(), shift);
272
273
731k
   if(is_negative() && is_zero()) {
274
0
      set_sign(Positive);
275
0
   }
276
277
731k
   return (*this);
278
731k
}
279
280
}  // namespace Botan