Coverage Report

Created: 2019-09-11 14:12

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