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