Coverage Report

Created: 2020-02-14 15:38

/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
#include <botan/internal/mp_core.h>
10
#include <botan/internal/rounding.h>
11
#include <botan/internal/bit_ops.h>
12
#include <botan/internal/ct_utils.h>
13
#include <botan/loadstor.h>
14
15
namespace Botan {
16
17
BigInt::BigInt(const word words[], size_t length)
18
85.9k
   {
19
85.9k
   m_data.set_words(words, length);
20
85.9k
   }
21
22
/*
23
* Construct a BigInt from a regular number
24
*/
25
BigInt::BigInt(uint64_t n)
26
5.59M
   {
27
5.59M
   if(n > 0)
28
2.73M
      {
29
#if BOTAN_MP_WORD_BITS == 32
30
      m_data.set_word_at(0, static_cast<word>(n));
31
      m_data.set_word_at(1, static_cast<word>(n >> 32));
32
#else
33
      m_data.set_word_at(0, n);
34
2.73M
#endif
35
2.73M
      }
36
5.59M
37
5.59M
   }
38
39
/*
40
* Construct a BigInt of the specified size
41
*/
42
BigInt::BigInt(Sign s, size_t size)
43
19.0M
   {
44
19.0M
   m_data.set_size(size);
45
19.0M
   m_signedness = s;
46
19.0M
   }
47
48
/*
49
* Construct a BigInt from a string
50
*/
51
BigInt::BigInt(const std::string& str)
52
19.9k
   {
53
19.9k
   Base base = Decimal;
54
19.9k
   size_t markers = 0;
55
19.9k
   bool negative = false;
56
19.9k
57
19.9k
   if(str.length() > 0 && str[0] == '-')
58
0
      {
59
0
      markers += 1;
60
0
      negative = true;
61
0
      }
62
19.9k
63
19.9k
   if(str.length() > markers + 2 && str[markers    ] == '0' &&
64
19.9k
                                    str[markers + 1] == 'x')
65
19.9k
      {
66
19.9k
      markers += 2;
67
19.9k
      base = Hexadecimal;
68
19.9k
      }
69
19.9k
70
19.9k
   *this = decode(cast_char_ptr_to_uint8(str.data()) + markers,
71
19.9k
                  str.length() - markers, base);
72
19.9k
73
19.9k
   if(negative) set_sign(Negative);
74
19.9k
   else         set_sign(Positive);
75
19.9k
   }
76
77
BigInt::BigInt(const uint8_t input[], size_t length)
78
108k
   {
79
108k
   binary_decode(input, length);
80
108k
   }
81
82
/*
83
* Construct a BigInt from an encoded BigInt
84
*/
85
BigInt::BigInt(const uint8_t input[], size_t length, Base base)
86
0
   {
87
0
   *this = decode(input, length, base);
88
0
   }
89
90
BigInt::BigInt(const uint8_t buf[], size_t length, size_t max_bits)
91
623
   {
92
623
   const size_t max_bytes = std::min(length, (max_bits + 7) / 8);
93
623
   binary_decode(buf, max_bytes);
94
623
95
623
   const size_t b = this->bits();
96
623
   if(b > max_bits)
97
0
      {
98
0
      *this >>= (b - max_bits);
99
0
      }
100
623
   }
101
102
/*
103
* Construct a BigInt from an encoded BigInt
104
*/
105
BigInt::BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit)
106
50.5k
   {
107
50.5k
   randomize(rng, bits, set_high_bit);
108
50.5k
   }
109
110
uint8_t BigInt::byte_at(size_t n) const
111
68.7k
   {
112
68.7k
   return get_byte(sizeof(word) - (n % sizeof(word)) - 1,
113
68.7k
                   word_at(n / sizeof(word)));
114
68.7k
   }
115
116
int32_t BigInt::cmp_word(word other) const
117
6.93M
   {
118
6.93M
   if(is_negative())
119
8.44k
      return -1; // other is positive ...
120
6.92M
121
6.92M
   const size_t sw = this->sig_words();
122
6.92M
   if(sw > 1)
123
6.23M
      return 1; // must be larger since other is just one word ...
124
692k
125
692k
   return bigint_cmp(this->data(), sw, &other, 1);
126
692k
   }
127
128
/*
129
* Comparison Function
130
*/
131
int32_t BigInt::cmp(const BigInt& other, bool check_signs) const
132
631k
   {
133
631k
   if(check_signs)
134
631k
      {
135
631k
      if(other.is_positive() && this->is_negative())
136
0
         return -1;
137
631k
138
631k
      if(other.is_negative() && this->is_positive())
139
1
         return 1;
140
631k
141
631k
      if(other.is_negative() && this->is_negative())
142
0
         return (-bigint_cmp(this->data(), this->size(),
143
0
                             other.data(), other.size()));
144
631k
      }
145
631k
146
631k
   return bigint_cmp(this->data(), this->size(),
147
631k
                     other.data(), other.size());
148
631k
   }
149
150
bool BigInt::is_equal(const BigInt& other) const
151
285k
   {
152
285k
   if(this->sign() != other.sign())
153
0
      return false;
154
285k
155
285k
   return bigint_ct_is_eq(this->data(), this->sig_words(),
156
285k
                          other.data(), other.sig_words()).is_set();
157
285k
   }
158
159
bool BigInt::is_less_than(const BigInt& other) const
160
5.56M
   {
161
5.56M
   if(this->is_negative() && other.is_positive())
162
109
      return true;
163
5.56M
164
5.56M
   if(this->is_positive() && other.is_negative())
165
0
      return false;
166
5.56M
167
5.56M
   if(other.is_negative() && this->is_negative())
168
0
      {
169
0
      return !bigint_ct_is_lt(other.data(), other.sig_words(),
170
0
                              this->data(), this->sig_words(), true).is_set();
171
0
      }
172
5.56M
173
5.56M
   return bigint_ct_is_lt(this->data(), this->sig_words(),
174
5.56M
                          other.data(), other.sig_words()).is_set();
175
5.56M
   }
176
177
void BigInt::encode_words(word out[], size_t size) const
178
3.25M
   {
179
3.25M
   const size_t words = sig_words();
180
3.25M
181
3.25M
   if(words > size)
182
0
      throw Encoding_Error("BigInt::encode_words value too large to encode");
183
3.25M
184
3.25M
   clear_mem(out, size);
185
3.25M
   copy_mem(out, data(), words);
186
3.25M
   }
187
188
size_t BigInt::Data::calc_sig_words() const
189
128M
   {
190
128M
   const size_t sz = m_reg.size();
191
128M
   size_t sig = sz;
192
128M
193
128M
   word sub = 1;
194
128M
195
4.11G
   for(size_t i = 0; i != sz; ++i)
196
3.98G
      {
197
3.98G
      const word w = m_reg[sz - i - 1];
198
3.98G
      sub &= ct_is_zero(w);
199
3.98G
      sig -= sub;
200
3.98G
      }
201
128M
202
128M
   /*
203
128M
   * This depends on the data so is poisoned, but unpoison it here as
204
128M
   * later conditionals are made on the size.
205
128M
   */
206
128M
   CT::unpoison(sig);
207
128M
208
128M
   return sig;
209
128M
   }
210
211
/*
212
* Return bits {offset...offset+length}
213
*/
214
uint32_t BigInt::get_substring(size_t offset, size_t length) const
215
10.4M
   {
216
10.4M
   if(length == 0 || length > 32)
217
0
      throw Invalid_Argument("BigInt::get_substring invalid substring length");
218
10.4M
219
10.4M
   const uint32_t mask = 0xFFFFFFFF >> (32 - length);
220
10.4M
221
10.4M
   const size_t word_offset = offset / BOTAN_MP_WORD_BITS;
222
10.4M
   const size_t wshift = (offset % BOTAN_MP_WORD_BITS);
223
10.4M
224
10.4M
   /*
225
10.4M
   * The substring is contained within one or at most two words. The
226
10.4M
   * offset and length are not secret, so we can perform conditional
227
10.4M
   * operations on those values.
228
10.4M
   */
229
10.4M
   const word w0 = word_at(word_offset);
230
10.4M
231
10.4M
   if(wshift == 0 || (offset + length) / BOTAN_MP_WORD_BITS == word_offset)
232
9.88M
      {
233
9.88M
      return static_cast<uint32_t>(w0 >> wshift) & mask;
234
9.88M
      }
235
530k
   else
236
530k
      {
237
530k
      const word w1 = word_at(word_offset + 1);
238
530k
      return static_cast<uint32_t>((w0 >> wshift) | (w1 << (BOTAN_MP_WORD_BITS - wshift))) & mask;
239
530k
      }
240
10.4M
   }
241
242
/*
243
* Convert this number to a uint32_t, if possible
244
*/
245
uint32_t BigInt::to_u32bit() const
246
0
   {
247
0
   if(is_negative())
248
0
      throw Encoding_Error("BigInt::to_u32bit: Number is negative");
249
0
   if(bits() > 32)
250
0
      throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert");
251
0
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
   return out;
256
0
   }
257
258
/*
259
* Set bit number n
260
*/
261
void BigInt::conditionally_set_bit(size_t n, bool set_it)
262
317M
   {
263
317M
   const size_t which = n / BOTAN_MP_WORD_BITS;
264
317M
   const word mask = static_cast<word>(set_it) << (n % BOTAN_MP_WORD_BITS);
265
317M
   m_data.set_word_at(which, word_at(which) | mask);
266
317M
   }
267
268
/*
269
* Clear bit number n
270
*/
271
void BigInt::clear_bit(size_t n)
272
0
   {
273
0
   const size_t which = n / BOTAN_MP_WORD_BITS;
274
0
275
0
   if(which < size())
276
0
      {
277
0
      const word mask = ~(static_cast<word>(1) << (n % BOTAN_MP_WORD_BITS));
278
0
      m_data.set_word_at(which, word_at(which) & mask);
279
0
      }
280
0
   }
281
282
size_t BigInt::bytes() const
283
193k
   {
284
193k
   return round_up(bits(), 8) / 8;
285
193k
   }
286
287
size_t BigInt::top_bits_free() const
288
10.9M
   {
289
10.9M
   const size_t words = sig_words();
290
10.9M
291
10.9M
   const word top_word = word_at(words - 1);
292
10.9M
   const size_t bits_used = high_bit(top_word);
293
10.9M
   CT::unpoison(bits_used);
294
10.9M
   return BOTAN_MP_WORD_BITS - bits_used;
295
10.9M
   }
296
297
size_t BigInt::bits() const
298
3.24M
   {
299
3.24M
   const size_t words = sig_words();
300
3.24M
301
3.24M
   if(words == 0)
302
12.9k
      return 0;
303
3.23M
304
3.23M
   const size_t full_words = (words - 1) * BOTAN_MP_WORD_BITS;
305
3.23M
   const size_t top_bits = BOTAN_MP_WORD_BITS - top_bits_free();
306
3.23M
307
3.23M
   return full_words + top_bits;
308
3.23M
   }
309
310
/*
311
* Calcluate the size in a certain base
312
*/
313
size_t BigInt::encoded_size(Base base) const
314
0
   {
315
0
   static const double LOG_2_BASE_10 = 0.30102999566;
316
0
317
0
   if(base == Binary)
318
0
      return bytes();
319
0
   else if(base == Hexadecimal)
320
0
      return 2*bytes();
321
0
   else if(base == Decimal)
322
0
      return static_cast<size_t>((bits() * LOG_2_BASE_10) + 1);
323
0
   else
324
0
      throw Invalid_Argument("Unknown base for BigInt encoding");
325
0
   }
326
327
/*
328
* Return the negation of this number
329
*/
330
BigInt BigInt::operator-() const
331
7.47k
   {
332
7.47k
   BigInt x = (*this);
333
7.47k
   x.flip_sign();
334
7.47k
   return x;
335
7.47k
   }
336
337
size_t BigInt::reduce_below(const BigInt& p, secure_vector<word>& ws)
338
47.5M
   {
339
47.5M
   if(p.is_negative() || this->is_negative())
340
0
      throw Invalid_Argument("BigInt::reduce_below both values must be positive");
341
47.5M
342
47.5M
   const size_t p_words = p.sig_words();
343
47.5M
344
47.5M
   if(size() < p_words + 1)
345
554
      grow_to(p_words + 1);
346
47.5M
347
47.5M
   if(ws.size() < p_words + 1)
348
2.57M
      ws.resize(p_words + 1);
349
47.5M
350
47.5M
   clear_mem(ws.data(), ws.size());
351
47.5M
352
47.5M
   size_t reductions = 0;
353
47.5M
354
47.5M
   for(;;)
355
120M
      {
356
120M
      word borrow = bigint_sub3(ws.data(), data(), p_words + 1, p.data(), p_words);
357
120M
      if(borrow)
358
47.5M
         break;
359
73.0M
360
73.0M
      ++reductions;
361
73.0M
      swap_reg(ws);
362
73.0M
      }
363
47.5M
364
47.5M
   return reductions;
365
47.5M
   }
366
367
void BigInt::ct_reduce_below(const BigInt& mod, secure_vector<word>& ws, size_t bound)
368
6.73M
   {
369
6.73M
   if(mod.is_negative() || this->is_negative())
370
0
      throw Invalid_Argument("BigInt::ct_reduce_below both values must be positive");
371
6.73M
372
6.73M
   const size_t mod_words = mod.sig_words();
373
6.73M
374
6.73M
   grow_to(mod_words);
375
6.73M
376
6.73M
   const size_t sz = size();
377
6.73M
378
6.73M
   ws.resize(sz);
379
6.73M
380
6.73M
   clear_mem(ws.data(), sz);
381
6.73M
382
20.2M
   for(size_t i = 0; i != bound; ++i)
383
13.4M
      {
384
13.4M
      word borrow = bigint_sub3(ws.data(), data(), sz, mod.data(), mod_words);
385
13.4M
386
13.4M
      CT::Mask<word>::is_zero(borrow).select_n(mutable_data(), ws.data(), data(), sz);
387
13.4M
      }
388
6.73M
   }
389
390
/*
391
* Return the absolute value of this number
392
*/
393
BigInt BigInt::abs() const
394
1.26k
   {
395
1.26k
   BigInt x = (*this);
396
1.26k
   x.set_sign(Positive);
397
1.26k
   return x;
398
1.26k
   }
399
400
void BigInt::binary_encode(uint8_t buf[]) const
401
51.2k
   {
402
51.2k
   this->binary_encode(buf, bytes());
403
51.2k
   }
404
405
/*
406
* Encode this number into bytes
407
*/
408
void BigInt::binary_encode(uint8_t output[], size_t len) const
409
107k
   {
410
107k
   const size_t full_words = len / sizeof(word);
411
107k
   const size_t extra_bytes = len % sizeof(word);
412
107k
413
1.27M
   for(size_t i = 0; i != full_words; ++i)
414
1.17M
      {
415
1.17M
      const word w = word_at(i);
416
1.17M
      store_be(w, output + (len - (i+1)*sizeof(word)));
417
1.17M
      }
418
107k
419
107k
   if(extra_bytes > 0)
420
52.4k
      {
421
52.4k
      const word w = word_at(full_words);
422
52.4k
423
178k
      for(size_t i = 0; i != extra_bytes; ++i)
424
126k
         {
425
126k
         output[extra_bytes - i - 1] = get_byte(sizeof(word) - i - 1, w);
426
126k
         }
427
52.4k
      }
428
107k
   }
429
430
/*
431
* Set this number to the value in buf
432
*/
433
void BigInt::binary_decode(const uint8_t buf[], size_t length)
434
617k
   {
435
617k
   clear();
436
617k
437
617k
   const size_t full_words = length / sizeof(word);
438
617k
   const size_t extra_bytes = length % sizeof(word);
439
617k
440
617k
   secure_vector<word> reg((round_up(full_words + (extra_bytes > 0 ? 1 : 0), 8)));
441
617k
442
4.51M
   for(size_t i = 0; i != full_words; ++i)
443
3.89M
      {
444
3.89M
      reg[i] = load_be<word>(buf + length - sizeof(word)*(i+1), 0);
445
3.89M
      }
446
617k
447
617k
   if(extra_bytes > 0)
448
303k
      {
449
858k
      for(size_t i = 0; i != extra_bytes; ++i)
450
555k
         reg[full_words] = (reg[full_words] << 8) | buf[i];
451
303k
      }
452
617k
453
617k
   m_data.swap(reg);
454
617k
   }
455
456
void BigInt::ct_cond_swap(bool predicate, BigInt& other)
457
158M
   {
458
158M
   const size_t max_words = std::max(size(), other.size());
459
158M
   grow_to(max_words);
460
158M
   other.grow_to(max_words);
461
158M
462
158M
   bigint_cnd_swap(predicate, this->mutable_data(), other.mutable_data(), max_words);
463
158M
   }
464
465
void BigInt::cond_flip_sign(bool predicate)
466
19.6M
   {
467
19.6M
   // This code is assuming Negative == 0, Positive == 1
468
19.6M
469
19.6M
   const auto mask = CT::Mask<uint8_t>::expand(predicate);
470
19.6M
471
19.6M
   const uint8_t current_sign = static_cast<uint8_t>(sign());
472
19.6M
473
19.6M
   const uint8_t new_sign = mask.select(current_sign ^ 1, current_sign);
474
19.6M
475
19.6M
   set_sign(static_cast<Sign>(new_sign));
476
19.6M
   }
477
478
void BigInt::ct_cond_assign(bool predicate, const BigInt& other)
479
4.20M
   {
480
4.20M
   const size_t t_words = size();
481
4.20M
   const size_t o_words = other.size();
482
4.20M
483
4.20M
   if(o_words < t_words)
484
547k
      grow_to(o_words);
485
4.20M
486
4.20M
   const size_t r_words = std::max(t_words, o_words);
487
4.20M
488
4.20M
   const auto mask = CT::Mask<word>::expand(predicate);
489
4.20M
490
139M
   for(size_t i = 0; i != r_words; ++i)
491
135M
      {
492
135M
      const word o_word = other.word_at(i);
493
135M
      const word t_word = this->word_at(i);
494
135M
      this->set_word_at(i, mask.select(o_word, t_word));
495
135M
      }
496
4.20M
497
4.20M
   if(sign() != other.sign())
498
860k
      {
499
860k
      cond_flip_sign(predicate);
500
860k
      }
501
4.20M
   }
502
503
#if defined(BOTAN_HAS_VALGRIND)
504
void BigInt::const_time_poison() const
505
   {
506
   CT::poison(m_data.const_data(), m_data.size());
507
   }
508
509
void BigInt::const_time_unpoison() const
510
   {
511
   CT::unpoison(m_data.const_data(), m_data.size());
512
   }
513
#endif
514
515
void BigInt::const_time_lookup(secure_vector<word>& output,
516
                               const std::vector<BigInt>& vec,
517
                               size_t idx)
518
0
   {
519
0
   const size_t words = output.size();
520
0
521
0
   clear_mem(output.data(), output.size());
522
0
523
0
   CT::poison(&idx, sizeof(idx));
524
0
525
0
   for(size_t i = 0; i != vec.size(); ++i)
526
0
      {
527
0
      BOTAN_ASSERT(vec[i].size() >= words,
528
0
                   "Word size as expected in const_time_lookup");
529
0
530
0
      const auto mask = CT::Mask<word>::is_equal(i, idx);
531
0
532
0
      for(size_t w = 0; w != words; ++w)
533
0
         {
534
0
         const word viw = vec[i].word_at(w);
535
0
         output[w] = mask.if_set_return(viw);
536
0
         }
537
0
      }
538
0
539
0
   CT::unpoison(idx);
540
0
   CT::unpoison(output.data(), output.size());
541
0
   }
542
543
}