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