/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 |