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);
262 uint64_t
siphash(
const std::string& str) {
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