• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 17279736665

27 Aug 2025 06:26PM UTC coverage: 90.667% (+0.009%) from 90.658%
17279736665

push

github

web-flow
Merge pull request #5077 from randombit/jack/opt-word-div

Refactorings to support optimized word level division/modulus

100205 of 110520 relevant lines covered (90.67%)

12125331.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.3
/src/lib/math/bigint/big_ops2.cpp
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
BigInt& BigInt::add(const word y[], size_t y_words, Sign y_sign) {
5,492,263✔
17
   const size_t x_sw = sig_words();
5,492,263✔
18

19
   grow_to(std::max(x_sw, y_words) + 1);
5,562,609✔
20

21
   if(sign() == y_sign) {
5,492,263✔
22
      word carry = bigint_add2(mutable_data(), size() - 1, y, y_words);
1,884,091✔
23
      mutable_data()[size() - 1] += carry;
1,884,091✔
24
   } else {
25
      const int32_t relative_size = bigint_cmp(_data(), x_sw, y, y_words);
3,608,172✔
26

27
      if(relative_size >= 0) {
3,608,172✔
28
         // *this >= y
29
         bigint_sub2(mutable_data(), x_sw, y, y_words);
3,549,305✔
30
      } else {
31
         // *this < y: compute *this = y - *this
32
         bigint_sub2_rev(mutable_data(), y, y_words);
58,867✔
33
      }
34

35
      if(relative_size < 0) {
3,608,172✔
36
         set_sign(y_sign);
58,867✔
37
      } else if(relative_size == 0) {
3,549,305✔
38
         set_sign(Positive);
53,136✔
39
      }
40
   }
41

42
   return (*this);
5,492,263✔
43
}
44

45
BigInt& BigInt::mod_add(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) {
972,141✔
46
   if(this->is_negative() || s.is_negative() || mod.is_negative()) {
972,141✔
47
      throw Invalid_Argument("BigInt::mod_add expects all arguments are positive");
×
48
   }
49

50
   BOTAN_DEBUG_ASSERT(*this < mod);
972,141✔
51
   BOTAN_DEBUG_ASSERT(s < mod);
972,141✔
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
   const size_t mod_sw = mod.sig_words();
972,141✔
64
   BOTAN_ARG_CHECK(mod_sw > 0, "BigInt::mod_add modulus must be positive");
972,141✔
65

66
   this->grow_to(mod_sw);
972,141✔
67
   s.grow_to(mod_sw);
972,141✔
68

69
   // First mod_sw for p - s, 2*mod_sw for bigint_addsub workspace
70
   if(ws.size() < 3 * mod_sw) {
972,141✔
71
      ws.resize(3 * mod_sw);
615,603✔
72
   }
73

74
   // NOLINTBEGIN(readability-container-data-pointer)
75

76
   word borrow = bigint_sub3(&ws[0], mod._data(), mod_sw, s._data(), mod_sw);
972,141✔
77
   BOTAN_DEBUG_ASSERT(borrow == 0);
972,141✔
78
   BOTAN_UNUSED(borrow);
972,141✔
79

80
   // Compute t - ws
81
   borrow = bigint_sub3(&ws[mod_sw], this->_data(), mod_sw, &ws[0], mod_sw);
972,141✔
82

83
   // Compute t + s
84
   bigint_add3(&ws[mod_sw * 2], this->_data(), mod_sw, s._data(), mod_sw);
972,141✔
85

86
   CT::conditional_copy_mem(borrow, &ws[0], &ws[mod_sw * 2], &ws[mod_sw], mod_sw);
972,141✔
87
   set_words(&ws[0], mod_sw);
972,141✔
88

89
   // NOLINTEND(readability-container-data-pointer)
90

91
   return (*this);
972,141✔
92
}
93

94
BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) {
15,724,555✔
95
   if(this->is_negative() || s.is_negative() || mod.is_negative()) {
15,724,555✔
96
      throw Invalid_Argument("BigInt::mod_sub expects all arguments are positive");
×
97
   }
98

99
   // We are assuming in this function that *this and s are no more than mod_sw words long
100
   BOTAN_DEBUG_ASSERT(*this < mod);
15,724,555✔
101
   BOTAN_DEBUG_ASSERT(s < mod);
15,724,555✔
102

103
   const size_t mod_sw = mod.sig_words();
15,724,555✔
104

105
   this->grow_to(mod_sw);
15,724,555✔
106
   s.grow_to(mod_sw);
15,724,555✔
107

108
   if(ws.size() < mod_sw) {
15,724,555✔
109
      ws.resize(mod_sw);
×
110
   }
111

112
   const word borrow = bigint_sub3(ws.data(), mutable_data(), mod_sw, s._data(), mod_sw);
15,724,555✔
113

114
   // Conditionally add back the modulus
115
   bigint_cnd_add(borrow, ws.data(), mod._data(), mod_sw);
15,724,555✔
116

117
   copy_mem(mutable_data(), ws.data(), mod_sw);
15,724,555✔
118

119
   return (*this);
15,724,555✔
120
}
121

122
BigInt& BigInt::mod_mul(uint8_t y, const BigInt& mod, secure_vector<word>& ws) {
6,913,344✔
123
   BOTAN_ARG_CHECK(this->is_negative() == false, "*this must be positive");
6,913,344✔
124
   BOTAN_ARG_CHECK(y < 16, "y too large");
6,913,344✔
125

126
   BOTAN_DEBUG_ASSERT(*this < mod);
6,913,344✔
127

128
   *this *= static_cast<word>(y);
6,913,344✔
129
   this->reduce_below(mod, ws);
6,913,344✔
130
   return (*this);
6,913,344✔
131
}
132

133
BigInt& BigInt::rev_sub(const word y[], size_t y_sw, secure_vector<word>& ws) {
×
134
   BOTAN_UNUSED(ws);
×
135
   BigInt y_bn;
×
136
   y_bn.m_data.set_words(y, y_sw);
×
137
   *this = y_bn - *this;
×
138
   return (*this);
×
139
}
×
140

141
/*
142
* Multiplication Operator
143
*/
144
BigInt& BigInt::operator*=(const BigInt& y) {
525✔
145
   secure_vector<word> ws;
525✔
146
   return this->mul(y, ws);
525✔
147
}
525✔
148

149
BigInt& BigInt::mul(const BigInt& y, secure_vector<word>& ws) {
9,485✔
150
   const size_t x_sw = sig_words();
9,485✔
151
   const size_t y_sw = y.sig_words();
9,485✔
152
   set_sign((sign() == y.sign()) ? Positive : Negative);
9,555✔
153

154
   if(x_sw == 0 || y_sw == 0) {
9,485✔
155
      clear();
33✔
156
      set_sign(Positive);
33✔
157
   } else if(x_sw == 1 && y_sw > 0) {
9,452✔
158
      grow_to(y_sw + 1);
327✔
159
      bigint_linmul3(mutable_data(), y._data(), y_sw, word_at(0));
654✔
160
   } else {
161
      const size_t new_size = x_sw + y_sw + 1;
9,125✔
162
      if(ws.size() < new_size) {
9,125✔
163
         ws.resize(new_size);
9,125✔
164
      }
165
      secure_vector<word> z_reg(new_size);
9,125✔
166

167
      bigint_mul(z_reg.data(), z_reg.size(), _data(), size(), x_sw, y._data(), y.size(), y_sw, ws.data(), ws.size());
9,125✔
168

169
      this->swap_reg(z_reg);
9,125✔
170
   }
9,125✔
171

172
   return (*this);
9,485✔
173
}
174

175
BigInt& BigInt::square(secure_vector<word>& ws) {
9,981✔
176
   const size_t sw = sig_words();
9,981✔
177

178
   secure_vector<word> z(2 * sw);
9,981✔
179
   ws.resize(z.size());
9,981✔
180

181
   bigint_sqr(z.data(), z.size(), _data(), size(), sw, ws.data(), ws.size());
9,981✔
182

183
   swap_reg(z);
9,981✔
184
   set_sign(BigInt::Positive);
9,981✔
185

186
   return (*this);
9,981✔
187
}
9,981✔
188

189
BigInt& BigInt::operator*=(word y) {
7,292,271✔
190
   if(y == 0) {
7,292,271✔
191
      clear();
×
192
      set_sign(Positive);
×
193
   }
194

195
   const word carry = bigint_linmul2(mutable_data(), size(), y);
7,292,271✔
196
   set_word_at(size(), carry);
7,292,271✔
197

198
   return (*this);
7,292,271✔
199
}
200

201
/*
202
* Division Operator
203
*/
204
BigInt& BigInt::operator/=(const BigInt& y) {
932✔
205
   if(y.sig_words() == 1 && is_positive() && y.is_positive() && is_power_of_2(y.word_at(0))) {
1,622✔
206
      (*this) >>= (y.bits() - 1);
85✔
207
   } else {
208
      (*this) = (*this) / y;
847✔
209
   }
210
   return (*this);
932✔
211
}
212

213
/*
214
* Modulo Operator
215
*/
216
BigInt& BigInt::operator%=(const BigInt& mod) {
335,447✔
217
   return (*this = (*this) % mod);
335,447✔
218
}
219

220
/*
221
* Modulo Operator
222
*/
223
word BigInt::operator%=(word mod) {
34✔
224
   if(mod == 0) {
34✔
225
      throw Invalid_Argument("BigInt::operator%= divide by zero");
×
226
   }
227

228
   word remainder = 0;
34✔
229

230
   if(is_power_of_2(mod)) {
34✔
231
      remainder = (word_at(0) & (mod - 1));
10✔
232
   } else {
233
      divide_precomp redc_mod(mod);
29✔
234
      const size_t sw = sig_words();
29✔
235
      for(size_t i = sw; i > 0; --i) {
81✔
236
         remainder = redc_mod.vartime_mod_2to1(remainder, word_at(i - 1));
104✔
237
      }
238
   }
239

240
   if(remainder != 0 && sign() == BigInt::Negative) {
34✔
241
      remainder = mod - remainder;
13✔
242
   }
243

244
   m_data.set_to_zero();
34✔
245
   m_data.set_word_at(0, remainder);
34✔
246
   set_sign(BigInt::Positive);
34✔
247
   return remainder;
34✔
248
}
249

250
/*
251
* Left Shift Operator
252
*/
253
BigInt& BigInt::operator<<=(size_t shift) {
12,208,863✔
254
   const size_t sw = sig_words();
12,208,863✔
255
   const size_t new_size = sw + (shift + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
12,208,863✔
256

257
   m_data.grow_to(new_size);
12,208,863✔
258

259
   bigint_shl1(m_data.mutable_data(), new_size, sw, shift);
12,208,863✔
260

261
   return (*this);
12,208,863✔
262
}
263

264
/*
265
* Right Shift Operator
266
*/
267
BigInt& BigInt::operator>>=(size_t shift) {
7,557,133✔
268
   bigint_shr1(m_data.mutable_data(), m_data.size(), shift);
7,557,133✔
269

270
   if(is_negative() && is_zero()) {
7,651,763✔
271
      set_sign(Positive);
8✔
272
   }
273

274
   return (*this);
7,557,133✔
275
}
276

277
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc