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

randombit / botan / 13274522654

11 Feb 2025 11:26PM UTC coverage: 91.645% (-0.007%) from 91.652%
13274522654

push

github

web-flow
Merge pull request #4647 from randombit/jack/internal-assert-and-mem-ops

Avoid using mem_ops.h or assert.h in public headers

94854 of 103501 relevant lines covered (91.65%)

11334975.77 hits per line

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

88.51
/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/hex.h>
11
#include <botan/mem_ops.h>
12
#include <botan/internal/divide.h>
13
#include <botan/internal/stl_util.h>
14

15
namespace Botan {
16

17
namespace {
18

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

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

35
}  // namespace
36

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

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

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

48
   BigInt value = *this;
57✔
49
   value.set_sign(Positive);
57✔
50

51
   // Extract groups of digits into words
52
   std::vector<word> digit_groups(digit_blocks);
57✔
53

54
   for(size_t i = 0; i != digit_blocks; ++i) {
125✔
55
      word remainder = 0;
68✔
56
      ct_divide_word(value, conversion_radix, value, remainder);
68✔
57
      digit_groups[i] = remainder;
68✔
58
   }
59

60
   BOTAN_ASSERT_NOMSG(value.is_zero());
114✔
61

62
   // Extract digits from the groups
63
   std::vector<uint8_t> digits(digit_blocks * radix_digits);
57✔
64

65
   for(size_t i = 0; i != digit_blocks; ++i) {
125✔
66
      word remainder = digit_groups[i];
68✔
67
      for(size_t j = 0; j != radix_digits; ++j) {
1,360✔
68
         // Compiler should convert div/mod by 10 into mul by magic constant
69
         const word digit = remainder % 10;
1,292✔
70
         remainder /= 10;
1,292✔
71
         digits[radix_digits * i + j] = static_cast<uint8_t>(digit);
1,292✔
72
      }
73
   }
74

75
   // remove leading zeros
76
   while(!digits.empty() && digits.back() == 0) {
926✔
77
      digits.pop_back();
869✔
78
   }
79

80
   BOTAN_ASSERT_NOMSG(digit_estimate >= digits.size());
57✔
81

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

86
   if(is_negative()) {
57✔
87
      s += "-";
5✔
88
   }
89

90
   // Reverse and convert to textual digits
91
   for(auto i = digits.rbegin(); i != digits.rend(); ++i) {
480✔
92
      s.push_back(*i + '0');  // assumes ASCII
423✔
93
   }
94

95
   if(s.empty()) {
57✔
96
      s += "0";
6✔
97
   }
98

99
   return s;
114✔
100
}
114✔
101

102
std::string BigInt::to_hex_string() const {
84✔
103
   const size_t this_bytes = this->bytes();
84✔
104
   std::vector<uint8_t> bits(std::max<size_t>(1, this_bytes));
141✔
105

106
   if(this_bytes > 0) {
84✔
107
      this->serialize_to(bits);
82✔
108
   }
109

110
   std::string hrep;
84✔
111
   if(is_negative()) {
84✔
112
      hrep += "-";
5✔
113
   }
114
   hrep += "0x";
84✔
115
   hrep += hex_encode(bits);
168✔
116
   return hrep;
84✔
117
}
84✔
118

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

136
BigInt BigInt::decode(std::span<const uint8_t> buf, Base base) {
×
137
   if(base == Binary) {
×
138
      return BigInt::from_bytes(buf);
×
139
   }
140
   return BigInt::decode(buf.data(), buf.size(), base);
×
141
}
142

143
/*
144
* Decode a BigInt
145
*/
146
BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) {
46,604✔
147
   if(base == Binary) {
46,604✔
148
      return BigInt::from_bytes(std::span{buf, length});
×
149
   } else if(base == Hexadecimal) {
46,604✔
150
      BigInt r;
42,042✔
151
      secure_vector<uint8_t> binary;
42,042✔
152

153
      if(length % 2) {
42,042✔
154
         // Handle lack of leading 0
155
         const char buf0_with_leading_0[2] = {'0', static_cast<char>(buf[0])};
3,906✔
156

157
         binary = hex_decode_locked(buf0_with_leading_0, 2);
7,812✔
158

159
         if(length > 1) {
3,906✔
160
            binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), length - 1, false);
6,092✔
161
         }
162
      } else {
163
         binary = hex_decode_locked(cast_uint8_ptr_to_char(buf), length, false);
76,272✔
164
      }
165

166
      r.assign_from_bytes(binary);
42,042✔
167
      return r;
42,042✔
168
   } else if(base == Decimal) {
46,604✔
169
      BigInt r;
4,562✔
170
      // This could be made faster using the same trick as to_dec_string
171
      for(size_t i = 0; i != length; ++i) {
383,604✔
172
         const char c = buf[i];
379,042✔
173

174
         if(c < '0' || c > '9') {
379,042✔
175
            throw Invalid_Argument("BigInt::decode: invalid decimal char");
×
176
         }
177

178
         const uint8_t x = c - '0';
379,042✔
179
         BOTAN_ASSERT_NOMSG(x < 10);
379,042✔
180

181
         r *= 10;
379,042✔
182
         r += x;
379,042✔
183
      }
184
      return r;
4,562✔
185
   } else {
4,562✔
186
      throw Invalid_Argument("Unknown BigInt decoding method");
×
187
   }
188
}
189

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