14 #ifndef TLX_SIPHASH_HEADER 15 #define TLX_SIPHASH_HEADER 29 #if (_MSC_VER > 1200) || defined(_mm_free) 33 #endif // !defined(_MSC_VER) 36 #include <emmintrin.h> 42 uint64_t
siphash_plain(
const uint8_t key[16],
const uint8_t* m,
size_t len) {
44 uint64_t v0, v1, v2, v3;
49 k0 = bswap64_le(*reinterpret_cast<const uint64_t*>(key + 0));
50 k1 = bswap64_le(*reinterpret_cast<const uint64_t*>(key + 8));
51 v0 = k0 ^ 0x736f6d6570736575ull;
52 v1 = k1 ^ 0x646f72616e646f6dull;
53 v2 = k0 ^ 0x6c7967656e657261ull;
54 v3 = k1 ^ 0x7465646279746573ull;
56 last7 =
static_cast<uint64_t
>(len & 0xff) << 56;
58 #define TLX_SIPCOMPRESS() \ 70 for (i = 0, blocks = (len & ~7); i < blocks; i += 8) {
71 mi = bswap64_le(*reinterpret_cast<const uint64_t*>(m + i));
78 switch (len - blocks) {
80 last7 |=
static_cast<uint64_t
>(m[i + 6]) << 48;
83 last7 |=
static_cast<uint64_t
>(m[i + 5]) << 40;
86 last7 |=
static_cast<uint64_t
>(m[i + 4]) << 32;
89 last7 |=
static_cast<uint64_t
>(m[i + 3]) << 24;
92 last7 |=
static_cast<uint64_t
>(m[i + 2]) << 16;
95 last7 |=
static_cast<uint64_t
>(m[i + 1]) << 8;
98 last7 |=
static_cast<uint64_t
>(m[i + 0]);
114 #undef TLX_SIPCOMPRESS 116 return v0 ^ v1 ^ v2 ^ v3;
122 #if defined(__SSE2__) 124 union siphash_packedelem64 {
130 static const siphash_packedelem64 siphash_init[2] = {
132 { 0x736f6d6570736575ull, 0x6c7967656e657261ull }
135 { 0x646f72616e646f6dull, 0x7465646279746573ull }
139 static const siphash_packedelem64 siphash_final = {
140 { 0x0000000000000000ull, 0x00000000000000ffull }
144 uint64_t siphash_sse2(
const uint8_t key[16],
const uint8_t* m,
size_t len) {
146 __m128i k, v02, v20, v13, v11, v33, mi;
151 k = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key + 0));
152 v02 = siphash_init[0].v;
153 v13 = siphash_init[1].v;
154 v02 = _mm_xor_si128(v02, _mm_unpacklo_epi64(k, k));
155 v13 = _mm_xor_si128(v13, _mm_unpackhi_epi64(k, k));
157 last7 =
static_cast<uint64_t
>(len & 0xff) << 56;
159 #define TLX_SIPCOMPRESS() \ 161 v33 = _mm_shuffle_epi32(v13, _MM_SHUFFLE(1, 0, 3, 2)); \ 162 v11 = _mm_or_si128(_mm_slli_epi64(v11, 13), _mm_srli_epi64(v11, 64 - 13)); \ 163 v02 = _mm_add_epi64(v02, v13); \ 164 v33 = _mm_shufflelo_epi16(v33, _MM_SHUFFLE(2, 1, 0, 3)); \ 165 v13 = _mm_unpacklo_epi64(v11, v33); \ 166 v13 = _mm_xor_si128(v13, v02); \ 167 v20 = _mm_shuffle_epi32(v02, _MM_SHUFFLE(0, 1, 3, 2)); \ 169 v33 = _mm_shuffle_epi32(v13, _MM_SHUFFLE(1, 0, 3, 2)); \ 170 v11 = _mm_or_si128(_mm_slli_epi64(v11, 17), _mm_srli_epi64(v11, 64 - 17)); \ 171 v20 = _mm_add_epi64(v20, v13); \ 172 v33 = _mm_or_si128(_mm_slli_epi64(v33, 21), _mm_srli_epi64(v33, 64 - 21)); \ 173 v13 = _mm_unpacklo_epi64(v11, v33); \ 174 v02 = _mm_shuffle_epi32(v20, _MM_SHUFFLE(0, 1, 3, 2)); \ 175 v13 = _mm_xor_si128(v13, v20); 177 for (i = 0, blocks = (len & ~7); i < blocks; i += 8) {
178 mi = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(m + i));
179 v13 = _mm_xor_si128(v13, _mm_slli_si128(mi, 8));
182 v02 = _mm_xor_si128(v02, mi);
185 switch (len - blocks) {
187 last7 |=
static_cast<uint64_t
>(m[i + 6]) << 48;
190 last7 |=
static_cast<uint64_t
>(m[i + 5]) << 40;
193 last7 |=
static_cast<uint64_t
>(m[i + 4]) << 32;
196 last7 |=
static_cast<uint64_t
>(m[i + 3]) << 24;
199 last7 |=
static_cast<uint64_t
>(m[i + 2]) << 16;
202 last7 |=
static_cast<uint64_t
>(m[i + 1]) << 8;
205 last7 |=
static_cast<uint64_t
>(m[i + 0]);
211 mi = _mm_unpacklo_epi32(
212 _mm_cvtsi32_si128(static_cast<uint32_t>(last7)),
213 _mm_cvtsi32_si128(static_cast<uint32_t>(last7 >> 32)));
214 v13 = _mm_xor_si128(v13, _mm_slli_si128(mi, 8));
217 v02 = _mm_xor_si128(v02, mi);
218 v02 = _mm_xor_si128(v02, siphash_final.v);
224 v02 = _mm_xor_si128(v02, v13);
225 v02 = _mm_xor_si128(v02, _mm_shuffle_epi32(v02, _MM_SHUFFLE(1, 0, 3, 2)));
226 lo = _mm_cvtsi128_si32(v02);
227 hi = _mm_cvtsi128_si32(_mm_srli_si128(v02, 4));
229 #undef TLX_SIPCOMPRESS 231 return (static_cast<uint64_t>(hi) << 32) | lo;
234 #endif // defined(__SSE2__) 240 uint64_t
siphash(
const uint8_t key[16],
const uint8_t* msg,
size_t size) {
241 #if defined(__SSE2__) 242 return siphash_sse2(key, msg, size);
249 uint64_t
siphash(
const uint8_t* msg,
size_t size) {
250 const unsigned char key[16] = {
251 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
253 return siphash(key, msg, size);
257 uint64_t
siphash(
const char* msg,
size_t size) {
258 return siphash(reinterpret_cast<const uint8_t*>(msg), size);
263 return siphash(str.data(), str.size());
266 template <
typename Type>
269 return siphash(reinterpret_cast<const uint8_t*>(&value),
sizeof(value));
276 #endif // !TLX_SIPHASH_HEADER
#define TLX_ATTRIBUTE_FALLTHROUGH
#define TLX_SIPCOMPRESS()
static uint64_t siphash(const uint8_t key[16], const uint8_t *msg, size_t size)
static uint64_t siphash_plain(const uint8_t key[16], const uint8_t *m, size_t len)