• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 21768358452

06 Feb 2026 10:35PM UTC coverage: 90.064% (-0.003%) from 90.067%
21768358452

Pull #5289

github

web-flow
Merge f589db195 into 8ea0ca252
Pull Request #5289: Further misc header reductions, forward declarations, etc

102238 of 113517 relevant lines covered (90.06%)

11357432.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.05
/src/lib/math/bigint/big_code.cpp
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/exceptn.h>
11
#include <botan/hex.h>
12
#include <botan/mem_ops.h>
13
#include <botan/internal/buffer_stuffer.h>
14
#include <botan/internal/divide.h>
15
#include <botan/internal/mp_core.h>
16

17
namespace Botan {
18

19
namespace {
20

21
consteval word decimal_conversion_radix() {
22
   if constexpr(sizeof(word) == 8) {
23
      return 10000000000000000000U;
24
   } else {
25
      return 1000000000U;
26
   }
27
}
28

29
consteval size_t decimal_conversion_radix_digits() {
30
   if constexpr(sizeof(word) == 8) {
31
      return 19;
32
   } else {
33
      return 9;
34
   }
35
}
36

37
}  // namespace
38

39
std::string BigInt::to_dec_string() const {
60✔
40
   // Use the largest power of 10 that fits in a word
41
   constexpr word conversion_radix = decimal_conversion_radix();
60✔
42
   constexpr size_t radix_digits = decimal_conversion_radix_digits();
60✔
43

44
   // (over-)estimate of the number of digits needed; log2(10) ~ 3.3219
45
   const size_t digit_estimate = static_cast<size_t>(1 + (static_cast<double>(this->bits()) / 3.32));
60✔
46

47
   // (over-)estimate of db such that conversion_radix^db > *this
48
   const size_t digit_blocks = (digit_estimate + radix_digits - 1) / radix_digits;
60✔
49

50
   BigInt value = *this;
60✔
51
   value.set_sign(Positive);
60✔
52

53
   // Extract groups of digits into words
54
   std::vector<word> digit_groups(digit_blocks);
60✔
55

56
   for(size_t i = 0; i != digit_blocks; ++i) {
132✔
57
      word remainder = 0;
72✔
58
      ct_divide_word(value, conversion_radix, value, remainder);
72✔
59
      digit_groups[i] = remainder;
72✔
60
   }
61

62
   BOTAN_ASSERT_NOMSG(value.is_zero());
120✔
63

64
   // Extract digits from the groups
65
   std::vector<uint8_t> digits(digit_blocks * radix_digits);
60✔
66

67
   for(size_t i = 0; i != digit_blocks; ++i) {
132✔
68
      word remainder = digit_groups[i];
72✔
69
      for(size_t j = 0; j != radix_digits; ++j) {
1,440✔
70
         const word new_remainder = divide_10(remainder);
1,368✔
71
         const word digit = remainder - new_remainder * 10;
1,368✔
72
         digits[radix_digits * i + j] = static_cast<uint8_t>(digit);
1,368✔
73
         remainder = new_remainder;
1,368✔
74
      }
75
   }
76

77
   // remove leading zeros
78
   while(!digits.empty() && digits.back() == 0) {
960✔
79
      digits.pop_back();
900✔
80
   }
81

82
   BOTAN_ASSERT_NOMSG(digit_estimate >= digits.size());
60✔
83

84
   // Reverse the digits to big-endian and format to text
85
   std::string s;
60✔
86
   s.reserve(1 + digits.size());
60✔
87

88
   if(is_negative()) {
60✔
89
      s += "-";
5✔
90
   }
91

92
   // Reverse and convert to textual digits
93
   // TODO(Botan4) use std::ranges::reverse_view here once available (need newer Clang)
94
   // NOLINTNEXTLINE(modernize-loop-convert)
95
   for(auto i = digits.rbegin(); i != digits.rend(); ++i) {
528✔
96
      s.push_back(*i + '0');  // assumes ASCII
468✔
97
   }
98

99
   if(s.empty()) {
60✔
100
      s += "0";
6✔
101
   }
102

103
   return s;
120✔
104
}
120✔
105

106
std::string BigInt::to_hex_string() const {
86✔
107
   const size_t this_bytes = this->bytes();
86✔
108
   std::vector<uint8_t> bits(std::max<size_t>(1, this_bytes));
145✔
109

110
   if(this_bytes > 0) {
86✔
111
      this->serialize_to(bits);
84✔
112
   }
113

114
   std::string hrep;
86✔
115
   if(is_negative()) {
86✔
116
      hrep += "-";
5✔
117
   }
118
   hrep += "0x";
86✔
119
   hrep += hex_encode(bits);
172✔
120
   return hrep;
86✔
121
}
86✔
122

123
/*
124
* Encode two BigInt, with leading 0s if needed, and concatenate
125
*/
126
secure_vector<uint8_t> BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes) {
97✔
127
   if(n1.is_negative() || n2.is_negative()) {
97✔
128
      throw Encoding_Error("encode_fixed_length_int_pair: values must be positive");
×
129
   }
130
   if(n1.bytes() > bytes || n2.bytes() > bytes) {
97✔
131
      throw Encoding_Error("encode_fixed_length_int_pair: values too large to encode properly");
×
132
   }
133
   secure_vector<uint8_t> output(2 * bytes);
97✔
134
   BufferStuffer stuffer(output);
97✔
135
   n1.serialize_to(stuffer.next(bytes));
97✔
136
   n2.serialize_to(stuffer.next(bytes));
97✔
137
   return output;
97✔
138
}
×
139

140
BigInt BigInt::decode(std::span<const uint8_t> buf, Base base) {
46,614✔
141
   if(base == Binary) {
46,614✔
142
      return BigInt::from_bytes(buf);
×
143
   }
144
   return BigInt::decode(buf.data(), buf.size(), base);
46,614✔
145
}
146

147
/*
148
* Decode a BigInt
149
*/
150
BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) {
46,614✔
151
   if(base == Binary) {
46,614✔
152
      return BigInt::from_bytes(std::span{buf, length});
×
153
   } else if(base == Hexadecimal) {
46,614✔
154
      BigInt r;
42,347✔
155
      secure_vector<uint8_t> binary;
42,347✔
156

157
      if(length % 2 == 1) {
42,347✔
158
         // Handle lack of leading 0
159
         const char buf0_with_leading_0[2] = {'0', static_cast<char>(buf[0])};
4,219✔
160

161
         binary = hex_decode_locked(buf0_with_leading_0, 2);
8,438✔
162

163
         if(length > 1) {
4,219✔
164
            binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), length - 1, false);
6,082✔
165
         }
166
      } else {
167
         binary = hex_decode_locked(cast_uint8_ptr_to_char(buf), length, false);
76,256✔
168
      }
169

170
      r.assign_from_bytes(binary);
42,347✔
171
      return r;
42,347✔
172
   } else if(base == Decimal) {
46,614✔
173
      BigInt r;
4,267✔
174
      // This could be made faster using the same trick as to_dec_string
175
      for(size_t i = 0; i != length; ++i) {
382,959✔
176
         const char c = buf[i];
378,692✔
177

178
         if(c < '0' || c > '9') {
378,692✔
179
            throw Invalid_Argument("BigInt::decode: invalid decimal char");
×
180
         }
181

182
         const uint8_t x = c - '0';
378,692✔
183
         BOTAN_ASSERT_NOMSG(x < 10);
378,692✔
184

185
         r *= 10;
378,692✔
186
         r += x;
378,692✔
187
      }
188
      return r;
4,267✔
189
   } else {
4,267✔
190
      throw Invalid_Argument("Unknown BigInt decoding method");
×
191
   }
192
}
193

194
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc