Bitcoin Core 28.99.0
P2P Digital Currency
int_utils.h
Go to the documentation of this file.
1/**********************************************************************
2 * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
3 * Distributed under the MIT software license, see the accompanying *
4 * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
5 **********************************************************************/
6
7#ifndef _MINISKETCH_INT_UTILS_H_
8#define _MINISKETCH_INT_UTILS_H_
9
10#include <stdint.h>
11#include <stdlib.h>
12
13#include <limits>
14#include <algorithm>
15#include <type_traits>
16
17#if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
18# include <bit>
19#elif defined(_MSC_VER)
20# include <intrin.h>
21#endif
22
23template<int bits>
24static constexpr inline uint64_t Rot(uint64_t x) { return (x << bits) | (x >> (64 - bits)); }
25
26static inline void SipHashRound(uint64_t& v0, uint64_t& v1, uint64_t& v2, uint64_t& v3) {
27 v0 += v1; v1 = Rot<13>(v1); v1 ^= v0;
28 v0 = Rot<32>(v0);
29 v2 += v3; v3 = Rot<16>(v3); v3 ^= v2;
30 v0 += v3; v3 = Rot<21>(v3); v3 ^= v0;
31 v2 += v1; v1 = Rot<17>(v1); v1 ^= v2;
32 v2 = Rot<32>(v2);
33}
34
35inline uint64_t SipHash(uint64_t k0, uint64_t k1, uint64_t data) {
36 uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
37 uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
38 uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
39 uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ data;
40 SipHashRound(v0, v1, v2, v3);
41 SipHashRound(v0, v1, v2, v3);
42 v0 ^= data;
43 v3 ^= 0x800000000000000ULL;
44 SipHashRound(v0, v1, v2, v3);
45 SipHashRound(v0, v1, v2, v3);
46 v0 ^= 0x800000000000000ULL;
47 v2 ^= 0xFF;
48 SipHashRound(v0, v1, v2, v3);
49 SipHashRound(v0, v1, v2, v3);
50 SipHashRound(v0, v1, v2, v3);
51 SipHashRound(v0, v1, v2, v3);
52 return v0 ^ v1 ^ v2 ^ v3;
53}
54
55class BitWriter {
56 unsigned char state = 0;
57 int offset = 0;
58 unsigned char* out;
59
60 template<int BITS, typename I>
61 inline void WriteInner(I val) {
62 // We right shift by up to 8 bits below. Verify that's well defined for the type I.
63 static_assert(std::numeric_limits<I>::digits > 8, "BitWriter::WriteInner needs I > 8 bits");
64 int bits = BITS;
65 if (bits + offset >= 8) {
66 state |= ((val & ((I(1) << (8 - offset)) - 1)) << offset);
67 *(out++) = state;
68 val >>= (8 - offset);
69 bits -= 8 - offset;
70 offset = 0;
71 state = 0;
72 }
73 while (bits >= 8) {
74 *(out++) = val & 255;
75 val >>= 8;
76 bits -= 8;
77 }
78 state |= ((val & ((I(1) << bits) - 1)) << offset);
79 offset += bits;
80 }
81
82
83public:
84 BitWriter(unsigned char* output) : out(output) {}
85
86 template<int BITS, typename I>
87 inline void Write(I val) {
88 // If I is smaller than an unsigned int, invoke WriteInner with argument converted to unsigned.
89 using compute_type = typename std::conditional<
90 (std::numeric_limits<I>::digits < std::numeric_limits<unsigned>::digits),
91 unsigned, I>::type;
92 return WriteInner<BITS, compute_type>(val);
93 }
94
95 inline void Flush() {
96 if (offset) {
97 *(out++) = state;
98 state = 0;
99 offset = 0;
100 }
101 }
102};
103
105 unsigned char state = 0;
106 int offset = 0;
107 const unsigned char* in;
108
109public:
110 BitReader(const unsigned char* input) : in(input) {}
111
112 template<int BITS, typename I>
113 inline I Read() {
114 int bits = BITS;
115 if (offset >= bits) {
116 I ret = state & ((1 << bits) - 1);
117 state >>= bits;
118 offset -= bits;
119 return ret;
120 }
121 I val = state;
122 int out = offset;
123 while (out + 8 <= bits) {
124 val |= ((I(*(in++))) << out);
125 out += 8;
126 }
127 if (out < bits) {
128 unsigned char c = *(in++);
129 val |= (c & ((I(1) << (bits - out)) - 1)) << out;
130 state = c >> (bits - out);
131 offset = 8 - (bits - out);
132 } else {
133 state = 0;
134 offset = 0;
135 }
136 return val;
137 }
138};
139
141template<int BITS, typename I>
142constexpr inline I Mask() { return ((I((I(-1)) << (std::numeric_limits<I>::digits - BITS))) >> (std::numeric_limits<I>::digits - BITS)); }
143
145template<typename I>
146static inline int CountBits(I val, int max) {
147#if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
148 // c++20 impl
149 (void)max;
150 return std::bit_width(val);
151#elif defined(_MSC_VER)
152 (void)max;
153 unsigned long index;
154 unsigned char ret;
155 if (std::numeric_limits<I>::digits <= 32) {
156 ret = _BitScanReverse(&index, val);
157 } else {
158 ret = _BitScanReverse64(&index, val);
159 }
160 if (!ret) return 0;
161 return index + 1;
162#elif defined(HAVE_CLZ)
163 (void)max;
164 if (val == 0) return 0;
165 if (std::numeric_limits<unsigned>::digits >= std::numeric_limits<I>::digits) {
166 return std::numeric_limits<unsigned>::digits - __builtin_clz(val);
167 } else if (std::numeric_limits<unsigned long>::digits >= std::numeric_limits<I>::digits) {
168 return std::numeric_limits<unsigned long>::digits - __builtin_clzl(val);
169 } else {
170 return std::numeric_limits<unsigned long long>::digits - __builtin_clzll(val);
171 }
172#else
173 while (max && (val >> (max - 1) == 0)) --max;
174 return max;
175#endif
176}
177
178template<typename I, int BITS>
179class BitsInt {
180private:
181 static_assert(std::is_integral<I>::value && std::is_unsigned<I>::value, "BitsInt requires an unsigned integer type");
182 static_assert(BITS > 0 && BITS <= std::numeric_limits<I>::digits, "BitsInt requires 1 <= Bits <= representation type size");
183
184 static constexpr I MASK = Mask<BITS, I>();
185
186public:
187
188 typedef I Repr;
189
190 static constexpr int SIZE = BITS;
191
192 static void inline Swap(I& a, I& b) {
193 std::swap(a, b);
194 }
195
196 static constexpr inline bool IsZero(I a) { return a == 0; }
197 static constexpr inline bool IsOne(I a) { return a == 1; }
198 static constexpr inline I Mask(I val) { return val & MASK; }
199 static constexpr inline I Shift(I val, int bits) { return ((val << bits) & MASK); }
200 static constexpr inline I UnsafeShift(I val, int bits) { return (val << bits); }
201
202 template<int Offset, int Count>
203 static constexpr inline int MidBits(I val) {
204 static_assert(Count > 0, "BITSInt::MidBits needs Count > 0");
205 static_assert(Count + Offset <= BITS, "BitsInt::MidBits overflow of Count+Offset");
206 return (val >> Offset) & ((I(1) << Count) - 1);
207 }
208
209 template<int Count>
210 static constexpr inline int TopBits(I val) {
211 static_assert(Count > 0, "BitsInt::TopBits needs Count > 0");
212 static_assert(Count <= BITS, "BitsInt::TopBits needs Offset <= BITS");
213 return static_cast<int>(val >> (BITS - Count));
214 }
215
216 static inline constexpr I CondXorWith(I val, bool cond, I v) {
217 return val ^ (-I(cond) & v);
218 }
219
220 template<I MOD>
221 static inline constexpr I CondXorWith(I val, bool cond) {
222 return val ^ (-I(cond) & MOD);
223 }
224
225 static inline int Bits(I val, int max) { return CountBits<I>(val, max); }
226};
227
229template<typename F, uint32_t MOD>
230struct LFSR {
231 typedef typename F::Repr I;
233 static inline constexpr I Call(const I& a) {
234 return F::template CondXorWith<MOD>(F::Shift(a, 1), F::template TopBits<1>(a));
235 }
236};
237
239template<typename I, int N, typename L, typename F, int K> struct GFMulHelper;
240template<typename I, int N, typename L, typename F> struct GFMulHelper<I, N, L, F, 0>
241{
242 static inline constexpr I Run(const I& a, const I& b) { return I(0); }
243};
244template<typename I, int N, typename L, typename F, int K> struct GFMulHelper
245{
246 static inline constexpr I Run(const I& a, const I& b) { return F::CondXorWith(GFMulHelper<I, N, L, F, K - 1>::Run(L::Call(a), b), F::template MidBits<N - K, 1>(b), a); }
247};
248
250template<typename I, int N, typename L, typename F> inline constexpr I GFMul(const I& a, const I& b) { return GFMulHelper<I, N, L, F, N>::Run(a, b); }
251
253template<typename I, typename F, int BITS, uint32_t MOD>
254inline I InvExtGCD(I x)
255{
256 if (F::IsZero(x) || F::IsOne(x)) return x;
257 I t(0), newt(1);
258 I r(MOD), newr = x;
259 int rlen = BITS + 1, newrlen = F::Bits(newr, BITS);
260 while (newr) {
261 int q = rlen - newrlen;
262 r ^= F::Shift(newr, q);
263 t ^= F::UnsafeShift(newt, q);
264 rlen = F::Bits(r, rlen - 1);
265 if (r < newr) {
266 F::Swap(t, newt);
267 F::Swap(r, newr);
268 std::swap(rlen, newrlen);
269 }
270 }
271 return t;
272}
273
279template<typename I, typename F, int BITS, I (*MUL)(I, I), I (*SQR)(I), I (*SQR2)(I), I(*SQR4)(I), I(*SQR8)(I), I(*SQR16)(I)>
280inline I InvLadder(I x1)
281{
282 static constexpr int INV_EXP = BITS - 1;
283 I x2 = (INV_EXP >= 2) ? MUL(SQR(x1), x1) : I();
284 I x4 = (INV_EXP >= 4) ? MUL(SQR2(x2), x2) : I();
285 I x8 = (INV_EXP >= 8) ? MUL(SQR4(x4), x4) : I();
286 I x16 = (INV_EXP >= 16) ? MUL(SQR8(x8), x8) : I();
287 I x32 = (INV_EXP >= 32) ? MUL(SQR16(x16), x16) : I();
288 I r;
289 if (INV_EXP >= 32) {
290 r = x32;
291 } else if (INV_EXP >= 16) {
292 r = x16;
293 } else if (INV_EXP >= 8) {
294 r = x8;
295 } else if (INV_EXP >= 4) {
296 r = x4;
297 } else if (INV_EXP >= 2) {
298 r = x2;
299 } else {
300 r = x1;
301 }
302 if (INV_EXP >= 32 && (INV_EXP & 16)) r = MUL(SQR16(r), x16);
303 if (INV_EXP >= 16 && (INV_EXP & 8)) r = MUL(SQR8(r), x8);
304 if (INV_EXP >= 8 && (INV_EXP & 4)) r = MUL(SQR4(r), x4);
305 if (INV_EXP >= 4 && (INV_EXP & 2)) r = MUL(SQR2(r), x2);
306 if (INV_EXP >= 2 && (INV_EXP & 1)) r = MUL(SQR(r), x1);
307 return SQR(r);
308}
309
310#endif
int ret
int offset
Definition: int_utils.h:106
I Read()
Definition: int_utils.h:113
BitReader(const unsigned char *input)
Definition: int_utils.h:110
const unsigned char * in
Definition: int_utils.h:107
unsigned char state
Definition: int_utils.h:105
void Flush()
Definition: int_utils.h:95
BitWriter(unsigned char *output)
Definition: int_utils.h:84
unsigned char state
Definition: int_utils.h:56
void WriteInner(I val)
Definition: int_utils.h:61
unsigned char * out
Definition: int_utils.h:58
void Write(I val)
Definition: int_utils.h:87
int offset
Definition: int_utils.h:57
static constexpr I MASK
Definition: int_utils.h:184
static int Bits(I val, int max)
Definition: int_utils.h:225
static constexpr I CondXorWith(I val, bool cond)
Definition: int_utils.h:221
static constexpr int TopBits(I val)
Definition: int_utils.h:210
static constexpr int SIZE
Definition: int_utils.h:190
static constexpr I Shift(I val, int bits)
Definition: int_utils.h:199
static constexpr I CondXorWith(I val, bool cond, I v)
Definition: int_utils.h:216
static constexpr bool IsZero(I a)
Definition: int_utils.h:196
static constexpr I Mask(I val)
Definition: int_utils.h:198
static constexpr bool IsOne(I a)
Definition: int_utils.h:197
static constexpr I UnsafeShift(I val, int bits)
Definition: int_utils.h:200
static constexpr int MidBits(I val)
Definition: int_utils.h:203
static void Swap(I &a, I &b)
Definition: int_utils.h:192
I InvLadder(I x1)
Compute the inverse of x1 using an exponentiation ladder.
Definition: int_utils.h:280
I InvExtGCD(I x)
Compute the inverse of x using an extgcd algorithm.
Definition: int_utils.h:254
static void SipHashRound(uint64_t &v0, uint64_t &v1, uint64_t &v2, uint64_t &v3)
Definition: int_utils.h:26
static int CountBits(I val, int max)
Compute the smallest power of two that is larger than val.
Definition: int_utils.h:146
constexpr I GFMul(const I &a, const I &b)
Compute the carry-less multiplication of a and b, with N bits, using L as LFSR type.
Definition: int_utils.h:250
uint64_t SipHash(uint64_t k0, uint64_t k1, uint64_t data)
Definition: int_utils.h:35
static constexpr uint64_t Rot(uint64_t x)
Definition: int_utils.h:24
constexpr I Mask()
Return a value of type I with its bits lowest bits set (bits must be > 0).
Definition: int_utils.h:142
static constexpr I Run(const I &a, const I &b)
Definition: int_utils.h:242
Helper class for carryless multiplications.
Definition: int_utils.h:245
static constexpr I Run(const I &a, const I &b)
Definition: int_utils.h:246
Class which implements a stateless LFSR for generic moduli.
Definition: int_utils.h:230
F::Repr I
Definition: int_utils.h:231
static constexpr I Call(const I &a)
Shift a value a up once, treating it as an N-bit LFSR, with pattern MOD.
Definition: int_utils.h:233