Coverage Report

Created: 2023-06-07 06:59

/src/botan/src/lib/math/bigint/bigint.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* BigInt Base
3
* (C) 1999-2011,2012,2014,2019 Jack Lloyd
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/ct_utils.h>
12
#include <botan/internal/loadstor.h>
13
#include <botan/internal/mp_core.h>
14
#include <botan/internal/rounding.h>
15
16
namespace Botan {
17
18
0
BigInt::BigInt(uint64_t n) {
19
0
#if BOTAN_MP_WORD_BITS == 64
20
0
   m_data.set_word_at(0, n);
21
#else
22
   m_data.set_word_at(1, static_cast<word>(n >> 32));
23
   m_data.set_word_at(0, static_cast<word>(n));
24
#endif
25
0
}
26
27
//static
28
0
BigInt BigInt::from_u64(uint64_t n) {
29
0
   BigInt bn;
30
31
0
#if BOTAN_MP_WORD_BITS == 64
32
0
   bn.set_word_at(0, n);
33
#else
34
   bn.set_word_at(1, static_cast<word>(n >> 32));
35
   bn.set_word_at(0, static_cast<word>(n));
36
#endif
37
38
0
   return bn;
39
0
}
40
41
//static
42
810
BigInt BigInt::from_word(word n) {
43
810
   BigInt bn;
44
810
   bn.set_word_at(0, n);
45
810
   return bn;
46
810
}
47
48
//static
49
0
BigInt BigInt::from_s32(int32_t n) {
50
0
   if(n >= 0) {
51
0
      return BigInt::from_u64(static_cast<uint64_t>(n));
52
0
   } else {
53
0
      return -BigInt::from_u64(static_cast<uint64_t>(-n));
54
0
   }
55
0
}
56
57
//static
58
28.8k
BigInt BigInt::with_capacity(size_t size) {
59
28.8k
   BigInt bn;
60
28.8k
   bn.grow_to(size);
61
28.8k
   return bn;
62
28.8k
}
63
64
/*
65
* Construct a BigInt from a string
66
*/
67
0
BigInt::BigInt(std::string_view str) {
68
0
   Base base = Decimal;
69
0
   size_t markers = 0;
70
0
   bool negative = false;
71
72
0
   if(str.length() > 0 && str[0] == '-') {
73
0
      markers += 1;
74
0
      negative = true;
75
0
   }
76
77
0
   if(str.length() > markers + 2 && str[markers] == '0' && str[markers + 1] == 'x') {
78
0
      markers += 2;
79
0
      base = Hexadecimal;
80
0
   }
81
82
0
   *this = decode(cast_char_ptr_to_uint8(str.data()) + markers, str.length() - markers, base);
83
84
0
   if(negative) {
85
0
      set_sign(Negative);
86
0
   } else {
87
0
      set_sign(Positive);
88
0
   }
89
0
}
90
91
3.69k
BigInt::BigInt(const uint8_t input[], size_t length) { binary_decode(input, length); }
92
93
/*
94
* Construct a BigInt from an encoded BigInt
95
*/
96
0
BigInt::BigInt(const uint8_t input[], size_t length, Base base) { *this = decode(input, length, base); }
97
98
//static
99
0
BigInt BigInt::from_bytes_with_max_bits(const uint8_t input[], size_t length, size_t max_bits) {
100
0
   const size_t input_bits = 8 * length;
101
102
0
   BigInt bn;
103
0
   bn.binary_decode(input, length);
104
105
0
   if(input_bits > max_bits) {
106
0
      const size_t bits_to_shift = input_bits - max_bits;
107
108
0
      bn >>= bits_to_shift;
109
0
   }
110
111
0
   return bn;
112
0
}
113
114
/*
115
* Construct a BigInt from an encoded BigInt
116
*/
117
0
BigInt::BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit) { randomize(rng, bits, set_high_bit); }
118
119
0
uint8_t BigInt::byte_at(size_t n) const {
120
0
   return get_byte_var(sizeof(word) - (n % sizeof(word)) - 1, word_at(n / sizeof(word)));
121
0
}
122
123
3.69k
int32_t BigInt::cmp_word(word other) const {
124
3.69k
   if(is_negative()) {
125
0
      return -1;  // other is positive ...
126
0
   }
127
128
3.69k
   const size_t sw = this->sig_words();
129
3.69k
   if(sw > 1) {
130
1.83k
      return 1;  // must be larger since other is just one word ...
131
1.83k
   }
132
133
1.85k
   return bigint_cmp(this->data(), sw, &other, 1);
134
3.69k
}
135
136
/*
137
* Comparison Function
138
*/
139
0
int32_t BigInt::cmp(const BigInt& other, bool check_signs) const {
140
0
   if(check_signs) {
141
0
      if(other.is_positive() && this->is_negative()) {
142
0
         return -1;
143
0
      }
144
145
0
      if(other.is_negative() && this->is_positive()) {
146
0
         return 1;
147
0
      }
148
149
0
      if(other.is_negative() && this->is_negative()) {
150
0
         return (-bigint_cmp(this->data(), this->size(), other.data(), other.size()));
151
0
      }
152
0
   }
153
154
0
   return bigint_cmp(this->data(), this->size(), other.data(), other.size());
155
0
}
156
157
3.69k
bool BigInt::is_equal(const BigInt& other) const {
158
3.69k
   if(this->sign() != other.sign()) {
159
0
      return false;
160
0
   }
161
162
3.69k
   return bigint_ct_is_eq(this->data(), this->sig_words(), other.data(), other.sig_words()).is_set();
163
3.69k
}
164
165
947
bool BigInt::is_less_than(const BigInt& other) const {
166
947
   if(this->is_negative() && other.is_positive()) {
167
0
      return true;
168
0
   }
169
170
947
   if(this->is_positive() && other.is_negative()) {
171
0
      return false;
172
0
   }
173
174
947
   if(other.is_negative() && this->is_negative()) {
175
0
      return bigint_ct_is_lt(other.data(), other.sig_words(), this->data(), this->sig_words()).is_set();
176
0
   }
177
178
947
   return bigint_ct_is_lt(this->data(), this->sig_words(), other.data(), other.sig_words()).is_set();
179
947
}
180
181
0
void BigInt::encode_words(word out[], size_t size) const {
182
0
   const size_t words = sig_words();
183
184
0
   if(words > size) {
185
0
      throw Encoding_Error("BigInt::encode_words value too large to encode");
186
0
   }
187
188
0
   clear_mem(out, size);
189
0
   copy_mem(out, data(), words);
190
0
}
191
192
66.7k
size_t BigInt::Data::calc_sig_words() const {
193
66.7k
   const size_t sz = m_reg.size();
194
66.7k
   size_t sig = sz;
195
196
66.7k
   word sub = 1;
197
198
2.22M
   for(size_t i = 0; i != sz; ++i) {
199
2.15M
      const word w = m_reg[sz - i - 1];
200
2.15M
      sub &= ct_is_zero(w);
201
2.15M
      sig -= sub;
202
2.15M
   }
203
204
   /*
205
   * This depends on the data so is poisoned, but unpoison it here as
206
   * later conditionals are made on the size.
207
   */
208
66.7k
   CT::unpoison(sig);
209
210
66.7k
   return sig;
211
66.7k
}
212
213
/*
214
* Return bits {offset...offset+length}
215
*/
216
0
uint32_t BigInt::get_substring(size_t offset, size_t length) const {
217
0
   if(length == 0 || length > 32) {
218
0
      throw Invalid_Argument("BigInt::get_substring invalid substring length");
219
0
   }
220
221
0
   const uint32_t mask = 0xFFFFFFFF >> (32 - length);
222
223
0
   const size_t word_offset = offset / BOTAN_MP_WORD_BITS;
224
0
   const size_t wshift = (offset % BOTAN_MP_WORD_BITS);
225
226
   /*
227
   * The substring is contained within one or at most two words. The
228
   * offset and length are not secret, so we can perform conditional
229
   * operations on those values.
230
   */
231
0
   const word w0 = word_at(word_offset);
232
233
0
   if(wshift == 0 || (offset + length) / BOTAN_MP_WORD_BITS == word_offset) {
234
0
      return static_cast<uint32_t>(w0 >> wshift) & mask;
235
0
   } else {
236
0
      const word w1 = word_at(word_offset + 1);
237
0
      return static_cast<uint32_t>((w0 >> wshift) | (w1 << (BOTAN_MP_WORD_BITS - wshift))) & mask;
238
0
   }
239
0
}
240
241
/*
242
* Convert this number to a uint32_t, if possible
243
*/
244
0
uint32_t BigInt::to_u32bit() const {
245
0
   if(is_negative()) {
246
0
      throw Encoding_Error("BigInt::to_u32bit: Number is negative");
247
0
   }
248
0
   if(bits() > 32) {
249
0
      throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert");
250
0
   }
251
252
0
   uint32_t out = 0;
253
0
   for(size_t i = 0; i != 4; ++i) {
254
0
      out = (out << 8) | byte_at(3 - i);
255
0
   }
256
0
   return out;
257
0
}
258
259
/*
260
* Clear bit number n
261
*/
262
0
void BigInt::clear_bit(size_t n) {
263
0
   const size_t which = n / BOTAN_MP_WORD_BITS;
264
265
0
   if(which < size()) {
266
0
      const word mask = ~(static_cast<word>(1) << (n % BOTAN_MP_WORD_BITS));
267
0
      m_data.set_word_at(which, word_at(which) & mask);
268
0
   }
269
0
}
270
271
0
size_t BigInt::bytes() const { return round_up(bits(), 8) / 8; }
272
273
8.19k
size_t BigInt::top_bits_free() const {
274
8.19k
   const size_t words = sig_words();
275
276
8.19k
   const word top_word = word_at(words - 1);
277
8.19k
   const size_t bits_used = high_bit(top_word);
278
8.19k
   CT::unpoison(bits_used);
279
8.19k
   return BOTAN_MP_WORD_BITS - bits_used;
280
8.19k
}
281
282
5.75k
size_t BigInt::bits() const {
283
5.75k
   const size_t words = sig_words();
284
285
5.75k
   if(words == 0) {
286
178
      return 0;
287
178
   }
288
289
5.57k
   const size_t full_words = (words - 1) * BOTAN_MP_WORD_BITS;
290
5.57k
   const size_t top_bits = BOTAN_MP_WORD_BITS - top_bits_free();
291
292
5.57k
   return full_words + top_bits;
293
5.75k
}
294
295
/*
296
* Return the negation of this number
297
*/
298
0
BigInt BigInt::operator-() const {
299
0
   BigInt x = (*this);
300
0
   x.flip_sign();
301
0
   return x;
302
0
}
303
304
872
size_t BigInt::reduce_below(const BigInt& p, secure_vector<word>& ws) {
305
872
   if(p.is_negative() || this->is_negative()) {
306
0
      throw Invalid_Argument("BigInt::reduce_below both values must be positive");
307
0
   }
308
309
872
   const size_t p_words = p.sig_words();
310
311
872
   if(size() < p_words + 1) {
312
59
      grow_to(p_words + 1);
313
59
   }
314
315
872
   if(ws.size() < p_words + 1) {
316
872
      ws.resize(p_words + 1);
317
872
   }
318
319
872
   clear_mem(ws.data(), ws.size());
320
321
872
   size_t reductions = 0;
322
323
984
   for(;;) {
324
984
      word borrow = bigint_sub3(ws.data(), data(), p_words + 1, p.data(), p_words);
325
984
      if(borrow) {
326
872
         break;
327
872
      }
328
329
112
      ++reductions;
330
112
      swap_reg(ws);
331
112
   }
332
333
872
   return reductions;
334
872
}
335
336
1.62k
void BigInt::ct_reduce_below(const BigInt& mod, secure_vector<word>& ws, size_t bound) {
337
1.62k
   if(mod.is_negative() || this->is_negative()) {
338
0
      throw Invalid_Argument("BigInt::ct_reduce_below both values must be positive");
339
0
   }
340
341
1.62k
   const size_t mod_words = mod.sig_words();
342
343
1.62k
   grow_to(mod_words);
344
345
1.62k
   const size_t sz = size();
346
347
1.62k
   ws.resize(sz);
348
349
1.62k
   clear_mem(ws.data(), sz);
350
351
4.88k
   for(size_t i = 0; i != bound; ++i) {
352
3.25k
      word borrow = bigint_sub3(ws.data(), data(), sz, mod.data(), mod_words);
353
354
3.25k
      CT::Mask<word>::is_zero(borrow).select_n(mutable_data(), ws.data(), data(), sz);
355
3.25k
   }
356
1.62k
}
357
358
/*
359
* Return the absolute value of this number
360
*/
361
507
BigInt BigInt::abs() const {
362
507
   BigInt x = (*this);
363
507
   x.set_sign(Positive);
364
507
   return x;
365
507
}
366
367
0
void BigInt::binary_encode(uint8_t buf[]) const { this->binary_encode(buf, bytes()); }
368
369
/*
370
* Encode this number into bytes
371
*/
372
0
void BigInt::binary_encode(uint8_t output[], size_t len) const {
373
0
   const size_t full_words = len / sizeof(word);
374
0
   const size_t extra_bytes = len % sizeof(word);
375
376
0
   for(size_t i = 0; i != full_words; ++i) {
377
0
      const word w = word_at(i);
378
0
      store_be(w, output + (len - (i + 1) * sizeof(word)));
379
0
   }
380
381
0
   if(extra_bytes > 0) {
382
0
      const word w = word_at(full_words);
383
384
0
      for(size_t i = 0; i != extra_bytes; ++i) {
385
0
         output[extra_bytes - i - 1] = get_byte_var(sizeof(word) - i - 1, w);
386
0
      }
387
0
   }
388
0
}
389
390
/*
391
* Set this number to the value in buf
392
*/
393
3.69k
void BigInt::binary_decode(const uint8_t buf[], size_t length) {
394
3.69k
   clear();
395
396
3.69k
   const size_t full_words = length / sizeof(word);
397
3.69k
   const size_t extra_bytes = length % sizeof(word);
398
399
3.69k
   secure_vector<word> reg((round_up(full_words + (extra_bytes > 0 ? 1 : 0), 8)));
400
401
29.5k
   for(size_t i = 0; i != full_words; ++i) {
402
25.8k
      reg[i] = load_be<word>(buf + length - sizeof(word) * (i + 1), 0);
403
25.8k
   }
404
405
3.69k
   if(extra_bytes > 0) {
406
11.2k
      for(size_t i = 0; i != extra_bytes; ++i) {
407
8.34k
         reg[full_words] = (reg[full_words] << 8) | buf[i];
408
8.34k
      }
409
2.90k
   }
410
411
3.69k
   m_data.swap(reg);
412
3.69k
}
413
414
0
void BigInt::ct_cond_add(bool predicate, const BigInt& value) {
415
0
   if(this->is_negative() || value.is_negative()) {
416
0
      throw Invalid_Argument("BigInt::ct_cond_add requires both values to be positive");
417
0
   }
418
0
   this->grow_to(1 + value.sig_words());
419
420
0
   bigint_cnd_add(static_cast<word>(predicate), this->mutable_data(), this->size(), value.data(), value.sig_words());
421
0
}
422
423
2.33M
void BigInt::ct_cond_swap(bool predicate, BigInt& other) {
424
2.33M
   const size_t max_words = std::max(size(), other.size());
425
2.33M
   grow_to(max_words);
426
2.33M
   other.grow_to(max_words);
427
428
2.33M
   bigint_cnd_swap(predicate, this->mutable_data(), other.mutable_data(), max_words);
429
2.33M
}
430
431
5.97k
void BigInt::cond_flip_sign(bool predicate) {
432
   // This code is assuming Negative == 0, Positive == 1
433
434
5.97k
   const auto mask = CT::Mask<uint8_t>::expand(predicate);
435
436
5.97k
   const uint8_t current_sign = static_cast<uint8_t>(sign());
437
438
5.97k
   const uint8_t new_sign = mask.select(current_sign ^ 1, current_sign);
439
440
5.97k
   set_sign(static_cast<Sign>(new_sign));
441
5.97k
}
442
443
0
void BigInt::ct_cond_assign(bool predicate, const BigInt& other) {
444
0
   const size_t t_words = size();
445
0
   const size_t o_words = other.size();
446
447
0
   if(o_words < t_words) {
448
0
      grow_to(o_words);
449
0
   }
450
451
0
   const size_t r_words = std::max(t_words, o_words);
452
453
0
   const auto mask = CT::Mask<word>::expand(predicate);
454
455
0
   for(size_t i = 0; i != r_words; ++i) {
456
0
      const word o_word = other.word_at(i);
457
0
      const word t_word = this->word_at(i);
458
0
      this->set_word_at(i, mask.select(o_word, t_word));
459
0
   }
460
461
0
   const bool different_sign = sign() != other.sign();
462
0
   cond_flip_sign(predicate && different_sign);
463
0
}
464
465
#if defined(BOTAN_HAS_VALGRIND)
466
void BigInt::const_time_poison() const { CT::poison(m_data.const_data(), m_data.size()); }
467
468
void BigInt::const_time_unpoison() const { CT::unpoison(m_data.const_data(), m_data.size()); }
469
#endif
470
471
}  // namespace Botan