Coverage Report

Created: 2026-01-16 06:49

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