Coverage Report

Created: 2025-12-31 06:08

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