Coverage Report

Created: 2024-11-29 06:10

/src/botan/src/lib/math/bigint/big_code.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* BigInt Encoding/Decoding
3
* (C) 1999-2010,2012,2019,2021 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/hex.h>
11
#include <botan/internal/divide.h>
12
#include <botan/internal/stl_util.h>
13
14
namespace Botan {
15
16
0
std::string BigInt::to_dec_string() const {
17
   // Use the largest power of 10 that fits in a word
18
0
#if(BOTAN_MP_WORD_BITS == 64)
19
0
   const word conversion_radix = 10000000000000000000U;
20
0
   const word radix_digits = 19;
21
#else
22
   const word conversion_radix = 1000000000U;
23
   const word radix_digits = 9;
24
#endif
25
26
   // (over-)estimate of the number of digits needed; log2(10) ~ 3.3219
27
0
   const size_t digit_estimate = static_cast<size_t>(1 + (this->bits() / 3.32));
28
29
   // (over-)estimate of db such that conversion_radix^db > *this
30
0
   const size_t digit_blocks = (digit_estimate + radix_digits - 1) / radix_digits;
31
32
0
   BigInt value = *this;
33
0
   value.set_sign(Positive);
34
35
   // Extract groups of digits into words
36
0
   std::vector<word> digit_groups(digit_blocks);
37
38
0
   for(size_t i = 0; i != digit_blocks; ++i) {
39
0
      word remainder = 0;
40
0
      ct_divide_word(value, conversion_radix, value, remainder);
41
0
      digit_groups[i] = remainder;
42
0
   }
43
44
0
   BOTAN_ASSERT_NOMSG(value.is_zero());
45
46
   // Extract digits from the groups
47
0
   std::vector<uint8_t> digits(digit_blocks * radix_digits);
48
49
0
   for(size_t i = 0; i != digit_blocks; ++i) {
50
0
      word remainder = digit_groups[i];
51
0
      for(size_t j = 0; j != radix_digits; ++j) {
52
         // Compiler should convert div/mod by 10 into mul by magic constant
53
0
         const word digit = remainder % 10;
54
0
         remainder /= 10;
55
0
         digits[radix_digits * i + j] = static_cast<uint8_t>(digit);
56
0
      }
57
0
   }
58
59
   // remove leading zeros
60
0
   while(!digits.empty() && digits.back() == 0) {
61
0
      digits.pop_back();
62
0
   }
63
64
0
   BOTAN_ASSERT_NOMSG(digit_estimate >= digits.size());
65
66
   // Reverse the digits to big-endian and format to text
67
0
   std::string s;
68
0
   s.reserve(1 + digits.size());
69
70
0
   if(is_negative()) {
71
0
      s += "-";
72
0
   }
73
74
   // Reverse and convert to textual digits
75
0
   for(auto i = digits.rbegin(); i != digits.rend(); ++i) {
76
0
      s.push_back(*i + '0');  // assumes ASCII
77
0
   }
78
79
0
   if(s.empty()) {
80
0
      s += "0";
81
0
   }
82
83
0
   return s;
84
0
}
85
86
0
std::string BigInt::to_hex_string() const {
87
0
   const size_t this_bytes = this->bytes();
88
0
   std::vector<uint8_t> bits(std::max<size_t>(1, this_bytes));
89
90
0
   if(this_bytes > 0) {
91
0
      this->serialize_to(bits);
92
0
   }
93
94
0
   std::string hrep;
95
0
   if(is_negative()) {
96
0
      hrep += "-";
97
0
   }
98
0
   hrep += "0x";
99
0
   hrep += hex_encode(bits);
100
0
   return hrep;
101
0
}
102
103
/*
104
* Encode two BigInt, with leading 0s if needed, and concatenate
105
*/
106
0
secure_vector<uint8_t> BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes) {
107
0
   if(n1.is_negative() || n2.is_negative()) {
108
0
      throw Encoding_Error("encode_fixed_length_int_pair: values must be positive");
109
0
   }
110
0
   if(n1.bytes() > bytes || n2.bytes() > bytes) {
111
0
      throw Encoding_Error("encode_fixed_length_int_pair: values too large to encode properly");
112
0
   }
113
0
   secure_vector<uint8_t> output(2 * bytes);
114
0
   BufferStuffer stuffer(output);
115
0
   n1.serialize_to(stuffer.next(bytes));
116
0
   n2.serialize_to(stuffer.next(bytes));
117
0
   return output;
118
0
}
119
120
0
BigInt BigInt::decode(std::span<const uint8_t> buf, Base base) {
121
0
   if(base == Binary) {
122
0
      return BigInt::from_bytes(buf);
123
0
   }
124
0
   return BigInt::decode(buf.data(), buf.size(), base);
125
0
}
126
127
/*
128
* Decode a BigInt
129
*/
130
6.67k
BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) {
131
6.67k
   if(base == Binary) {
132
0
      return BigInt::from_bytes(std::span{buf, length});
133
6.67k
   } else if(base == Hexadecimal) {
134
6.00k
      BigInt r;
135
6.00k
      secure_vector<uint8_t> binary;
136
137
6.00k
      if(length % 2) {
138
         // Handle lack of leading 0
139
526
         const char buf0_with_leading_0[2] = {'0', static_cast<char>(buf[0])};
140
141
526
         binary = hex_decode_locked(buf0_with_leading_0, 2);
142
143
526
         if(length > 1) {
144
526
            binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), length - 1, false);
145
526
         }
146
5.47k
      } else {
147
5.47k
         binary = hex_decode_locked(cast_uint8_ptr_to_char(buf), length, false);
148
5.47k
      }
149
150
6.00k
      r.assign_from_bytes(binary);
151
6.00k
      return r;
152
6.00k
   } else if(base == Decimal) {
153
675
      BigInt r;
154
      // This could be made faster using the same trick as to_dec_string
155
1.35k
      for(size_t i = 0; i != length; ++i) {
156
675
         const char c = buf[i];
157
158
675
         if(c < '0' || c > '9') {
159
0
            throw Invalid_Argument("BigInt::decode: invalid decimal char");
160
0
         }
161
162
675
         const uint8_t x = c - '0';
163
675
         BOTAN_ASSERT_NOMSG(x < 10);
164
165
675
         r *= 10;
166
675
         r += x;
167
675
      }
168
675
      return r;
169
675
   } else {
170
0
      throw Invalid_Argument("Unknown BigInt decoding method");
171
0
   }
172
6.67k
}
173
174
}  // namespace Botan