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

libbitcoin / libbitcoin-system / 20948398990

13 Jan 2026 07:28AM UTC coverage: 80.39% (-0.8%) from 81.203%
20948398990

Pull #1773

github

web-flow
Merge d75f2288a into 62dd8e3fd
Pull Request #1773: Add AES256-GCM.

0 of 132 new or added lines in 2 files covered. (0.0%)

3 existing lines in 2 files now uncovered.

10843 of 13488 relevant lines covered (80.39%)

3510970.29 hits per line

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

96.88
/include/bitcoin/system/impl/math/bits.ipp
1
/**
2
 * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
3
 *
4
 * This file is part of libbitcoin.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
#ifndef LIBBITCOIN_SYSTEM_MATH_BITS_IPP
20
#define LIBBITCOIN_SYSTEM_MATH_BITS_IPP
21

22
#include <bit>
23
#include <bitcoin/system/define.hpp>
24
#include <bitcoin/system/math/cast.hpp>
25
#include <bitcoin/system/math/logarithm.hpp>
26
#include <bitcoin/system/math/sign.hpp>
27

28
namespace libbitcoin {
29
namespace system {
30

31
// Use depromote only for integral constrained functions.
32

33
// Widths.
34
// ----------------------------------------------------------------------------
35

36
// Called by bc::base2n (for sizing).
37
// Called by machine::number (for is_negated/to_unnegated).
38
template <typename Value, if_unsigned_integer<Value>>
39
constexpr size_t bit_width(Value value) NOEXCEPT
698✔
40
{
41
    // zero-based position of msb.
42
    return ceilinged_log2(value);
698✔
43
}
44

45
// Called by machine::number (for to_unnegated).
46
template <typename Value, if_signed_integer<Value>>
47
constexpr size_t bit_width(Value value) NOEXCEPT
136✔
48
{
49
    return is_negative(value) ? bits<Value> : bit_width(to_unsigned(value));
136✔
50
}
51

52
template <typename Value, if_unsigned_integer<Value>>
53
constexpr size_t left_zeros(Value value) NOEXCEPT
54
{
55
    return to_unsigned(std::countl_zero<Value>(value));
56
}
57

58
template <typename Value, if_unsigned_integer<Value>>
59
constexpr size_t right_zeros(Value value) NOEXCEPT
60
{
61
    return to_unsigned(std::countr_zero<Value>(value));
62
}
63

64
template <typename Value, if_unsigned_integer<Value>>
65
constexpr size_t left_ones(Value value) NOEXCEPT
66
{
67
    return to_unsigned(std::countl_one<Value>(value));
68
}
69

70
template <typename Value, if_unsigned_integer<Value>>
71
constexpr size_t right_ones(Value value) NOEXCEPT
72
{
73
    return to_unsigned(std::countr_one<Value>(value));
74
}
75

76
template <typename Value, if_unsigned_integer<Value>>
77
constexpr size_t ones_count(Value value) NOEXCEPT
78
{
79
    return to_unsigned(std::popcount<Value>(value));
80
}
81

82
template <typename Value, if_unsigned_integer<Value>>
83
constexpr size_t zeros_count(Value value) NOEXCEPT
84
{
85
    return to_unsigned(std::popcount<Value>(bit_not(value)));
86
}
87

88
// Bitwise logical operations.
89
// ----------------------------------------------------------------------------
90

91
// OPERATOR ~
92
template <typename Value, if_integer<Value>>
93
constexpr Value bit_not(Value value) NOEXCEPT
2,295,688✔
94
{
95
    return possible_narrow_and_sign_cast<Value>(~value);
1,170,598✔
96
}
97

98
// OPERATOR &
99
template <typename Value, if_integer<Value>>
100
constexpr Value bit_and(Value left, Value right) NOEXCEPT
4,937,139✔
101
{
102
    // Promotion is safe as leading zeros are truncated.
103
    // Revert sign and/or domain promotion for < 32 bit values.
104
    return possible_narrow_and_sign_cast<Value>(left & right);
4,936,946✔
105
}
106

107
// OPERATOR |
108
template <typename Value, if_integer<Value>>
109
constexpr Value bit_or(Value left, Value right) NOEXCEPT
135✔
110
{
111
    // Promotion is safe as leading zeros are truncated.
112
    // Revert sign and/or domain promotion for < 32 bit Value.
113
    return possible_narrow_and_sign_cast<Value>(left | right);
133✔
114
}
115

116
// OPERATOR ^
117
template <typename Value, if_integer<Value>>
118
constexpr Value bit_xor(Value left, Value right) NOEXCEPT
2,261✔
119
{
120
    // Promotion is safe as leading zeros are truncated.
121
    // Revert sign and/or domain promotion for < 32 bit Value.
122
    return possible_narrow_and_sign_cast<Value>(left ^ right);
2,257✔
123
}
124

125
// Value factories.
126
// ----------------------------------------------------------------------------
127

128
template <typename Value, if_integral_integer<Value>>
129
constexpr Value bit_left(size_t offset) NOEXCEPT
4,454,219✔
130
{
131
    // a >> b is implementation-dependent for negative a:
132
    // "or negative a, the value of a >> b is implementation-defined (in most
133
    // implementations, this performs arithmetic right shift, so that the
134
    // result remains negative)." - so shift to the left (see bit_right).
135
    // en.cppreference.com/w/cpp/language/operator_arithmetic
136

137
    // Subtraction is between size_t operands and guarded.
138
    // This converts the left offset to a right offset, overflow true.
139
    return offset >= bits<Value> ? 0 :
140
        bit_right<Value>(sub1(bits<Value> - offset));
4,454,219✔
141
}
142

143
template <typename Value, if_integral_integer<Value>>
144
constexpr Value bit_right(size_t offset) NOEXCEPT
8,653,231✔
145
{
146
    // a << b is undefined for negative a, but shift into a negative is valid:
147
    // "For signed and non-negative a, if a**b is representable in the unsigned
148
    // version of the return type, then that value, converted to signed, is the
149
    // value of a << b (this makes it legal to create INT_MIN as 1<<31)."
150
    // en.cppreference.com/w/cpp/language/operator_arithmetic
151
    return shift_left(bit_lo<Value>, offset);
8,653,231✔
152
}
153

154
// Get (a bit).
155
// ----------------------------------------------------------------------------
156

157
template <typename Value, if_integral_integer<Value>>
158
constexpr bool get_left(Value value, size_t offset) NOEXCEPT
2,119,722✔
159
{
160
    return to_bool(bit_and(value, bit_left<Value>(offset)));
2,119,722✔
161
}
162

163
template <typename Value, if_integral_integer<Value>>
164
constexpr bool get_right(Value value, size_t offset) NOEXCEPT
2,081,156✔
165
{
166
    return to_bool(bit_and(value, bit_right<Value>(offset)));
2,081,156✔
167
}
168

169
// Set (a bit).
170
// ----------------------------------------------------------------------------
171

172
template <typename Value, if_integral_integer<Value>>
173
constexpr Value set_left(Value target, size_t offset, bool state) NOEXCEPT
49✔
174
{
175
    const auto bit = bit_left<Value>(offset);
49✔
176
    return state ? bit_or(target, bit) : bit_and(target, bit_not(bit));
49✔
177
}
178

179
template <typename Value, if_integral_integer<Value>>
180
constexpr void set_left_into(Value& target, size_t offset, bool state) NOEXCEPT
2,334,448✔
181
{
182
    const auto bit = bit_left<Value>(offset);
2,334,448✔
183
    state ? target |= bit : target &= bit_not(bit);
2,334,448✔
184
}
2,334,448✔
185

186
template <typename Value, if_integral_integer<Value>>
187
constexpr Value set_right(Value target, size_t offset, bool state) NOEXCEPT
88✔
188
{
189
    const auto bit = bit_right<Value>(offset);
88✔
190
    return state ? bit_or(target, bit) : bit_and(target, bit_not(bit));
88✔
191
}
192

193
template <typename Value, if_integral_integer<Value>>
194
constexpr void set_right_into(Value& target, size_t offset, bool state) NOEXCEPT
2,117,766✔
195
{
196
    const auto bit = bit_right<Value>(offset);
2,117,766✔
197
    state ? target |= bit : target &= bit_not(bit);
2,117,766✔
198
}
2,117,766✔
199

200
// Mask (a field of bits from left/right).
201
// ----------------------------------------------------------------------------
202

203
// C++ standard: "Right-shift on signed integral types is an arithmetic right
204
// shift, which performs sign-extension". In other words, repeatedly shifting
205
// -1 of any integer width will produce "1" bits, indefinitely.
206

207
// a << b is undefined for negative a.
208
// a >> b is implementation-dependent for negative a.
209

210
template <typename Value, if_integral_integer<Value>>
211
constexpr Value mask_left(size_t bits) NOEXCEPT
33✔
212
{
213
    return shift_right(bit_all<Value>, bits, true);
33✔
214
}
215

216
template <typename Value, if_integral_integer<Value>>
217
constexpr Value mask_left(Value value, size_t bits) NOEXCEPT
33✔
218
{
219
    return bit_and(value, mask_left<Value>(bits));
20✔
220
}
221

222
template <typename Value, if_integral_integer<Value>>
223
constexpr void mask_left_into(Value& value, size_t bits) NOEXCEPT
224
{
225
    value &= mask_left<Value>(bits);
226
}
227

228
template <typename Value, if_integral_integer<Value>>
229
constexpr Value mask_right(size_t bits) NOEXCEPT
16✔
230
{
231
    return shift_left(bit_all<Value>, bits, true);
16✔
232
}
233

234
template <typename Value, if_integral_integer<Value>>
235
constexpr Value mask_right(Value value, size_t bits) NOEXCEPT
236
{
237
    return bit_and(value, mask_right<Value>(bits));
238
}
239

240
template <typename Value, if_integral_integer<Value>>
241
constexpr void mask_right_into(Value& value, size_t bits) NOEXCEPT
12✔
242
{
243
    value &= mask_right<Value>(bits);
12✔
244
}
12✔
245

246
// Unmask (~mask).
247
// ----------------------------------------------------------------------------
248

249
template <typename Value, if_integral_integer<Value>>
250
constexpr Value unmask_left(size_t bits) NOEXCEPT
251
{
252
    return bit_not(mask_left<Value>(bits));
253
}
254

255
template <typename Value, if_integral_integer<Value>>
256
constexpr Value unmask_left(Value value, size_t bits) NOEXCEPT
257
{
258
    return bit_or(unmask_left<Value>(bits), value);
259
}
260

261
template <typename Value, if_integral_integer<Value>>
262
constexpr void unmask_left_into(Value& value, size_t bits) NOEXCEPT
263
{
264
    value |= unmask_left<Value>(bits);
265
}
266

267
template <typename Value, if_integral_integer<Value>>
268
constexpr Value unmask_right(size_t bits) NOEXCEPT
2✔
269
{
270
    return bit_not(mask_right<Value>(bits));
2✔
271
}
272

273
template <typename Value, if_integral_integer<Value>>
274
constexpr Value unmask_right(Value value, size_t bits) NOEXCEPT
275
{
276
    return bit_or(unmask_right<Value>(bits), value);
277
}
278

279
template <typename Value, if_integral_integer<Value>>
280
constexpr void unmask_right_into(Value& value, size_t bits) NOEXCEPT
281
{
282
    value |= unmask_right<Value>(bits);
283
}
284

285
// Shift (left/right).
286
// ----------------------------------------------------------------------------
287

288
// C++ standard: "The behavior is undefined if the right operand is negative,
289
// or greater than or equal to the width of the promoted left operand."
290
// These functions make explicit the intended behavior in that condition.
291
// overflow true is logically equivalent to shifting by one the specified
292
// shift number of times, which results in a zero if shift >= width(value).
293
// overflow true shifts shift % width(value), which cannot zeroize the value.
294
// These are both default behaviors of different compilers. Shift left/right of
295
// signed Value transits unsigned, as native -<</->> is undefined/unspecified.
296

297
// OPERATOR <<
298
template <typename Value, if_unsigned_integral_integer<Value>>
299
constexpr Value shift_left(Value value, size_t shift, bool overflow) NOEXCEPT
8,654,953✔
300
{
301
    constexpr auto span = bits<Value>;
302
    return overflow && shift >= span ? 0 : depromote<Value>(
13,107,826✔
303
        value << (shift % span));
8,654,607✔
304
}
305
template <typename Value, if_unsigned_integral_integer<Value>>
306
constexpr void shift_left_into(Value& value, size_t shift, bool overflow) NOEXCEPT
307
{
308
    constexpr auto span = bits<Value>;
309
    overflow && shift >= span ? value = 0 : value <<= (shift % span);
310
}
311

312
// signed overloads (shift left of negative is undefined behavior).
313
template <typename Value, if_signed_integral_integer<Value>>
314
constexpr Value shift_left(Value value, size_t shift, bool overflow) NOEXCEPT
68✔
315
{
316
    constexpr auto span = bits<Value>;
317
    return overflow && shift >= span ? 0 : depromote<Value>(
68✔
318
        to_signed(to_unsigned(value) << (shift % span)));
68✔
319
}
320
template <typename Value, if_signed_integral_integer<Value>>
321
constexpr void shift_left_into(Value& value, size_t shift, bool overflow) NOEXCEPT
322
{
323
    // Defined behavior for negative value.
324
    value = to_signed<Value>(shift_left(to_unsigned(value), shift, overflow));
325
}
326

327
// OPERATOR >>
328
template <typename Value, if_unsigned_integral_integer<Value>>
329
constexpr Value shift_right(Value value, size_t shift, bool overflow) NOEXCEPT
738,374✔
330
{
331
    constexpr auto span = bits<Value>;
332
    return overflow && shift >= span ? 0 : depromote<Value>(
738,211✔
333
        value >> (shift % span));
736,296✔
334
}
335
template <typename Value, if_unsigned_integral_integer<Value>>
UNCOV
336
constexpr void shift_right_into(Value& value, size_t shift, bool overflow) NOEXCEPT
×
337
{
338
    constexpr auto span = bits<Value>;
NEW
339
    overflow && shift >= span ? value = 0 : value >>= (shift % span);
×
340
}
341

342
// signed overloads (shift right of negative is unspecified behavior).
343
template <typename Value, if_signed_integral_integer<Value>>
344
constexpr Value shift_right(Value value, size_t shift, bool overflow) NOEXCEPT
345
{
346
    constexpr auto span = bits<Value>;
347
    return overflow && shift >= span ? 0 : depromote<Value>(
348
        to_signed(to_unsigned(value) >> (shift % span)));
349
}
350
template <typename Value, if_signed_integral_integer<Value>>
351
constexpr void shift_right_into(Value& value, size_t shift,
352
    bool overflow) NOEXCEPT
353
{
354
    // Less efficient than =>>, but defined behavior for negative value.
355
    value = to_signed<Value>(shift_right(to_unsigned(value), shift, overflow));
356
}
357

358
// Rotate (left/right).
359
// ----------------------------------------------------------------------------
360
// C++20: std::rotl/rotr unsigned is not defined (at least for msvc).
361
// std lib should pass to intrinsic implementation (optimal).
362

363
template <typename Value, if_integral_integer<Value>>
364
constexpr Value rotate_left(Value value, size_t shift) NOEXCEPT
365
{
366
    if constexpr (!is_signed<Value>)
367
    {
368
        return std::rotl(value, possible_narrow_sign_cast<int>(shift));
369
    }
370
    else
371
    {
372
        constexpr auto span = bits<Value>;
373
        const auto cycle = shift % span;
374
        return bit_or(shift_left(value, cycle),
375
            shift_right(value, span - cycle));
376
    }
377
}
378

379
template <typename Value, if_integral_integer<Value>>
380
constexpr void rotate_left_into(Value& value, size_t shift) NOEXCEPT
42,550✔
381
{
382
    if constexpr (!is_signed<Value>)
383
    {
384
        value = std::rotl(value, possible_narrow_sign_cast<int>(shift));
42,550✔
385
        return;
386
    }
387
    else
388
    {
389
        constexpr auto span = bits<Value>;
390
        const auto cycle = shift % span;
391
        value = bit_or(shift_left(value, cycle),
392
            shift_right(value, span - cycle));
393
    }
394
}
395

396
template <typename Value, if_integral_integer<Value>>
397
constexpr Value rotate_right(Value value, size_t shift) NOEXCEPT
398
{
399
    if constexpr (!is_signed<Value>)
400
    {
401
        return std::rotr(value, possible_narrow_sign_cast<int>(shift));
402
    }
403
    else
404
    {
405
        constexpr auto span = bits<Value>;
406
        const auto cycle = shift % span;
407
        return bit_or(shift_right(value, cycle),
408
            shift_left(value, span - cycle));
409
    }
410
}
411

412
template <typename Value, if_integral_integer<Value>>
413
constexpr void rotate_right_into(Value& value, size_t shift) NOEXCEPT
414
{
415
    if constexpr (!is_signed<Value>)
416
    {
417
        value = std::rotr(value, possible_narrow_sign_cast<int>(shift));
418
        return;
419
    }
420
    else
421
    {
422
        constexpr auto span = bits<Value>;
423
        const auto cycle = shift % span;
424
        value = bit_or(shift_right(value, cycle),
425
            shift_left(value, span - cycle));
426
    }
427
}
428

429
// High/Low word extraction.
430
// ----------------------------------------------------------------------------
431

432
template <typename To, typename From,
433
    if_integral_integer<To>,
434
    if_uintx<From>>
435
constexpr To hi_word(From value) NOEXCEPT
4✔
436
{
437
    return (value >> bits<To>).template convert_to<To>();
4✔
438
}
439

440
template <typename To, typename From,
441
    if_integral_integer<To>,
442
    if_not_uintx<From>>
443
constexpr To hi_word(From value) NOEXCEPT
1,240✔
444
{
445
    return narrow_cast<To>(shift_right(value, bits<To>));
446
}
447

448
template <typename To, typename From,
449
    if_integral_integer<To>,
450
    if_uintx<From>>
451
constexpr To lo_word(From value) NOEXCEPT
4✔
452
{
453
    return value.template convert_to<To>();
4✔
454
}
455

456
template <typename To, typename From,
457
    if_integral_integer<To>,
458
    if_not_uintx<From>>
459
constexpr To lo_word(From value) NOEXCEPT
1,240✔
460
{
461
    return narrow_cast<To>(value);
462
}
463

464
} // namespace system
465
} // namespace libbitcoin
466

467
#endif
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