Coverage Report

Created: 2026-03-11 06:24

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