Botan 3.10.0
Crypto and TLS for C&
bit_ops.h
Go to the documentation of this file.
1/*
2* Bit/Word Operations
3* (C) 1999-2008 Jack Lloyd
4* (C) Copyright Projet SECRET, INRIA, Rocquencourt
5* (C) Bhaskar Biswas and Nicolas Sendrier
6* (C) 2014 cryptosource GmbH
7* (C) 2014 Falko Strenzke fstrenzke@cryptosource.de
8*
9* Botan is released under the Simplified BSD License (see license.txt)
10*/
11
12#ifndef BOTAN_BIT_OPS_H_
13#define BOTAN_BIT_OPS_H_
14
15#include <botan/types.h>
16
17#include <botan/compiler.h>
18#include <botan/internal/bswap.h>
19#include <concepts>
20
21namespace Botan {
22
23/**
24* If top bit of arg is set, return |1| (all bits set). Otherwise return |0| (all bits unset)
25*/
26template <std::unsigned_integral T>
28 return static_cast<T>(0) - (a >> (sizeof(T) * 8 - 1));
29}
30
31/**
32* If arg is zero, return |1|. Otherwise return |0|
33*/
34template <std::unsigned_integral T>
36 return expand_top_bit<T>(~x & (x - 1));
37}
38
39/**
40* If arg is zero, return the size_t `s`. Otherwise return the size_t zero.
41*/
42template <std::unsigned_integral T>
43BOTAN_FORCE_INLINE constexpr size_t ct_if_is_zero_ret(T x, size_t s) {
44 const T a = ~x & (x - 1);
45 const size_t mask = static_cast<size_t>(0) - static_cast<size_t>(a >> (sizeof(T) * 8 - 1));
46 return mask & s;
47}
48
49/**
50* Power of 2 test. T should be an unsigned integer type
51* @param arg an integer value
52* @return true iff arg is 2^n for some n > 0
53*/
54template <std::unsigned_integral T>
55BOTAN_FORCE_INLINE constexpr bool is_power_of_2(T arg) {
56 return (arg != 0) && (arg != 1) && ((arg & static_cast<T>(arg - 1)) == 0);
57}
58
59/**
60* Return the index of the highest set bit
61* T is an unsigned integer type
62* @param n an integer value
63* @return index of the highest set bit in n
64*/
65template <std::unsigned_integral T>
66BOTAN_FORCE_INLINE constexpr size_t high_bit(T n) {
67 size_t hb = 0;
68
69 for(size_t s = 8 * sizeof(T) / 2; s > 0; s /= 2) {
70 // Equivalent to: ((n >> s) == 0) ? 0 : s;
71 const size_t z = s - ct_if_is_zero_ret<T>(n >> s, s);
72 hb += z;
73 n >>= z;
74 }
75
76 hb += n;
77
78 return hb;
79}
80
81/**
82* Return the number of significant bytes in n
83* @param n an integer value
84* @return number of significant bytes in n
85*/
86template <std::unsigned_integral T>
88 size_t b = 0;
89
90 for(size_t s = 8 * sizeof(T) / 2; s >= 8; s /= 2) {
91 // Equivalent to: ((n >> s) == 0) ? 0 : s;
92 const size_t z = s - ct_if_is_zero_ret<T>(n >> s, s);
93 b += z / 8;
94 n >>= z;
95 }
96
97 b += (n != 0);
98
99 return b;
100}
101
102/**
103* Count the trailing zero bits in n
104* @param n an integer value
105* @return maximum x st 2^x divides n
106*/
107template <std::unsigned_integral T>
108BOTAN_FORCE_INLINE constexpr size_t ctz(T n) {
109 /*
110 * If n == 0 then this function will compute 8*sizeof(T)-1, so
111 * initialize lb to 1 if n == 0 to produce the expected result.
112 */
113 size_t lb = ct_if_is_zero_ret<T>(n, 1);
114
115 for(size_t s = 8 * sizeof(T) / 2; s > 0; s /= 2) {
116 const T range = (static_cast<T>(1) << s) - 1;
117 // Equivalent to: ((n & range) == 0) ? s : 0;
118 const size_t z = ct_if_is_zero_ret<T>(n & range, s);
119 lb += z;
120 n >>= z;
121 }
122
123 return lb;
124}
125
126template <std::unsigned_integral T>
128 BOTAN_ARG_CHECK(n != 0, "log2(0) is not defined");
129 return static_cast<T>(high_bit(n) - 1);
130}
131
132template <std::unsigned_integral T>
133constexpr uint8_t ceil_log2(T x)
134 requires(sizeof(T) < 32)
135{
136 if(x >> (sizeof(T) * 8 - 1)) {
137 return sizeof(T) * 8;
138 }
139
140 uint8_t result = 0;
141 T compare = 1;
142
143 while(compare < x) {
144 compare <<= 1;
145 result++;
146 }
147
148 return result;
149}
150
151/**
152 * Ceil of an unsigned integer division. @p b must not be zero.
153 *
154 * @param a divident
155 * @param b divisor
156 *
157 * @returns ceil(a/b)
158 */
159template <std::unsigned_integral T>
160BOTAN_FORCE_INLINE constexpr T ceil_division(T a, T b) {
161 return (a + b - 1) / b;
162}
163
164/**
165 * Return the number of bytes necessary to contain @p bits bits.
166 */
167template <std::unsigned_integral T>
168BOTAN_FORCE_INLINE constexpr T ceil_tobytes(T bits) {
169 return (bits + 7) / 8;
170}
171
172// Potentially variable time ctz used for OCB
173BOTAN_FORCE_INLINE constexpr size_t var_ctz32(uint32_t n) {
174#if BOTAN_COMPILER_HAS_BUILTIN(__builtin_ctz)
175 if(n == 0) {
176 return 32;
177 }
178 return __builtin_ctz(n);
179#else
180 return ctz<uint32_t>(n);
181#endif
182}
183
184template <std::unsigned_integral T>
185BOTAN_FORCE_INLINE constexpr T bit_permute_step(T x, T mask, size_t shift) {
186 /*
187 See https://reflectionsonsecurity.wordpress.com/2014/05/11/efficient-bit-permutation-using-delta-swaps/
188 and http://programming.sirrida.de/bit_perm.html
189 */
190 const T swap = ((x >> shift) ^ x) & mask;
191 return (x ^ swap) ^ (swap << shift);
192}
193
194template <std::unsigned_integral T>
195BOTAN_FORCE_INLINE constexpr void swap_bits(T& x, T& y, T mask, size_t shift) {
196 const T swap = ((x >> shift) ^ y) & mask;
197 x ^= swap << shift;
198 y ^= swap;
199}
200
201/**
202* Bitwise selection
203*
204* If mask is |1| returns a
205* If mask is |0| returns b
206* If mask is some other value returns a or b depending on the bit
207*/
208template <std::unsigned_integral T>
209BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b) {
210 //return (mask & a) | (~mask & b);
211 return (b ^ (mask & (a ^ b)));
212}
213
214template <std::unsigned_integral T>
215BOTAN_FORCE_INLINE constexpr T majority(T a, T b, T c) {
216 /*
217 Considering each bit of a, b, c individually
218
219 If a xor b is set, then c is the deciding vote.
220
221 If a xor b is not set then either a and b are both set or both unset.
222 In either case the value of c doesn't matter, and examining b (or a)
223 allows us to determine which case we are in.
224 */
225 return choose(a ^ b, c, b);
226}
227
228/**
229 * @returns the reversed bits in @p b.
230 */
231template <std::unsigned_integral T>
232inline constexpr T ct_reverse_bits(T b) {
233 auto extend = [](uint8_t m) -> T {
234 T mask = 0;
235 for(size_t i = 0; i < sizeof(T); ++i) {
236 mask |= T(m) << i * 8;
237 }
238 return mask;
239 };
240
241 // First reverse bits in each byte...
242 // From: https://stackoverflow.com/a/2602885
243 b = (b & extend(0xF0)) >> 4 | (b & extend(0x0F)) << 4;
244 b = (b & extend(0xCC)) >> 2 | (b & extend(0x33)) << 2;
245 b = (b & extend(0xAA)) >> 1 | (b & extend(0x55)) << 1;
246
247 // ... then swap the bytes
248 return reverse_bytes(b);
249}
250
251/**
252 * Calculates the number of 1-bits in an unsigned integer in constant-time.
253 * This operation is also known as "population count" or hamming weight.
254 *
255 * Modern compilers will recognize this pattern and replace it by a hardware
256 * instruction, if available. This is the SWAR (SIMD within a register)
257 * algorithm. See: https://nimrod.blog/posts/algorithms-behind-popcount/#swar-algorithm
258 *
259 * Note: C++20 provides std::popcount(), but there's no guarantee that this
260 * is implemented in constant-time.
261 *
262 * @param x an unsigned integer
263 * @returns the number of 1-bits in the provided value
264 */
265template <std::unsigned_integral T>
266BOTAN_FORCE_INLINE constexpr uint8_t ct_popcount(T x) {
267 constexpr size_t s = sizeof(T);
268 static_assert(s <= 8, "T is not a suitable unsigned integer value");
269 if constexpr(s == 8) {
270 x = x - ((x >> 1) & 0x5555555555555555);
271 x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
272 x = (x + (x >> 4)) & 0xF0F0F0F0F0F0F0F;
273 return (x * 0x101010101010101) >> 56;
274 } else if constexpr(s == 4) {
275 x = x - ((x >> 1) & 0x55555555);
276 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
277 x = (x + (x >> 4)) & 0x0F0F0F0F;
278 return (x * 0x01010101) >> 24;
279 } else {
280 // s < 4
281 return ct_popcount(static_cast<uint32_t>(x));
282 }
283}
284
285} // namespace Botan
286
287#endif
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_FORCE_INLINE
Definition compiler.h:87
BOTAN_FORCE_INLINE constexpr bool is_power_of_2(T arg)
Definition bit_ops.h:55
BOTAN_FORCE_INLINE constexpr T floor_log2(T n)
Definition bit_ops.h:127
BOTAN_FORCE_INLINE constexpr T ceil_division(T a, T b)
Definition bit_ops.h:160
BOTAN_FORCE_INLINE constexpr T majority(T a, T b, T c)
Definition bit_ops.h:215
BOTAN_FORCE_INLINE constexpr void swap_bits(T &x, T &y, T mask, size_t shift)
Definition bit_ops.h:195
constexpr T ct_reverse_bits(T b)
Definition bit_ops.h:232
BOTAN_FORCE_INLINE constexpr T bit_permute_step(T x, T mask, size_t shift)
Definition bit_ops.h:185
BOTAN_FORCE_INLINE constexpr size_t var_ctz32(uint32_t n)
Definition bit_ops.h:173
constexpr uint8_t ceil_log2(T x)
Definition bit_ops.h:133
BOTAN_FORCE_INLINE constexpr size_t significant_bytes(T n)
Definition bit_ops.h:87
constexpr T reverse_bytes(T x)
Definition bswap.h:27
BOTAN_FORCE_INLINE constexpr T ceil_tobytes(T bits)
Definition bit_ops.h:168
BOTAN_FORCE_INLINE constexpr uint8_t ct_popcount(T x)
Definition bit_ops.h:266
BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b)
Definition bit_ops.h:209
BOTAN_FORCE_INLINE constexpr size_t high_bit(T n)
Definition bit_ops.h:66
BOTAN_FORCE_INLINE constexpr size_t ct_if_is_zero_ret(T x, size_t s)
Definition bit_ops.h:43
BOTAN_FORCE_INLINE constexpr size_t ctz(T n)
Definition bit_ops.h:108
BOTAN_FORCE_INLINE constexpr T ct_is_zero(T x)
Definition bit_ops.h:35
BOTAN_FORCE_INLINE constexpr T expand_top_bit(T a)
Definition bit_ops.h:27