Skip to content

Commit 13cb97d

Browse files
committed
Extract SipHash implementation into a header.
This is so that we'll be able to use it in compiler-rt as well. Dependencies on LLVM Support were removed from the header by restoring code from the original SipHash implementation. Pull Request: llvm#134197
1 parent 5226493 commit 13cb97d

File tree

4 files changed

+168
-130
lines changed

4 files changed

+168
-130
lines changed

llvm/lib/Support/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,8 @@ if(LLVM_WITH_Z3)
368368
${Z3_INCLUDE_DIR}
369369
)
370370
endif()
371+
372+
target_include_directories(LLVMSupport SYSTEM
373+
PRIVATE
374+
${LLVM_THIRD_PARTY_DIR}/siphash/include
375+
)

llvm/lib/Support/SipHash.cpp

+1-130
Original file line numberDiff line numberDiff line change
@@ -15,145 +15,16 @@
1515
#include "llvm/ADT/ArrayRef.h"
1616
#include "llvm/ADT/StringExtras.h"
1717
#include "llvm/ADT/StringRef.h"
18-
#include "llvm/Support/Compiler.h"
1918
#include "llvm/Support/Debug.h"
2019
#include "llvm/Support/Endian.h"
20+
#include "siphash/SipHash.h"
2121
#include <cstdint>
2222

2323
using namespace llvm;
2424
using namespace support;
2525

2626
#define DEBUG_TYPE "llvm-siphash"
2727

28-
// Lightly adapted from the SipHash reference C implementation:
29-
// https://github.com/veorq/SipHash
30-
// by Jean-Philippe Aumasson and Daniel J. Bernstein
31-
32-
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
33-
34-
#define SIPROUND \
35-
do { \
36-
v0 += v1; \
37-
v1 = ROTL(v1, 13); \
38-
v1 ^= v0; \
39-
v0 = ROTL(v0, 32); \
40-
v2 += v3; \
41-
v3 = ROTL(v3, 16); \
42-
v3 ^= v2; \
43-
v0 += v3; \
44-
v3 = ROTL(v3, 21); \
45-
v3 ^= v0; \
46-
v2 += v1; \
47-
v1 = ROTL(v1, 17); \
48-
v1 ^= v2; \
49-
v2 = ROTL(v2, 32); \
50-
} while (0)
51-
52-
namespace {
53-
54-
/// Computes a SipHash value
55-
///
56-
/// \param in: pointer to input data (read-only)
57-
/// \param inlen: input data length in bytes (any size_t value)
58-
/// \param k: reference to the key data 16-byte array (read-only)
59-
/// \returns output data, must be 8 or 16 bytes
60-
///
61-
template <int cROUNDS, int dROUNDS, size_t outlen>
62-
void siphash(const unsigned char *in, uint64_t inlen,
63-
const unsigned char (&k)[16], unsigned char (&out)[outlen]) {
64-
65-
const unsigned char *ni = (const unsigned char *)in;
66-
const unsigned char *kk = (const unsigned char *)k;
67-
68-
static_assert(outlen == 8 || outlen == 16, "result should be 8 or 16 bytes");
69-
70-
uint64_t v0 = UINT64_C(0x736f6d6570736575);
71-
uint64_t v1 = UINT64_C(0x646f72616e646f6d);
72-
uint64_t v2 = UINT64_C(0x6c7967656e657261);
73-
uint64_t v3 = UINT64_C(0x7465646279746573);
74-
uint64_t k0 = endian::read64le(kk);
75-
uint64_t k1 = endian::read64le(kk + 8);
76-
uint64_t m;
77-
int i;
78-
const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
79-
const int left = inlen & 7;
80-
uint64_t b = ((uint64_t)inlen) << 56;
81-
v3 ^= k1;
82-
v2 ^= k0;
83-
v1 ^= k1;
84-
v0 ^= k0;
85-
86-
if (outlen == 16)
87-
v1 ^= 0xee;
88-
89-
for (; ni != end; ni += 8) {
90-
m = endian::read64le(ni);
91-
v3 ^= m;
92-
93-
for (i = 0; i < cROUNDS; ++i)
94-
SIPROUND;
95-
96-
v0 ^= m;
97-
}
98-
99-
switch (left) {
100-
case 7:
101-
b |= ((uint64_t)ni[6]) << 48;
102-
LLVM_FALLTHROUGH;
103-
case 6:
104-
b |= ((uint64_t)ni[5]) << 40;
105-
LLVM_FALLTHROUGH;
106-
case 5:
107-
b |= ((uint64_t)ni[4]) << 32;
108-
LLVM_FALLTHROUGH;
109-
case 4:
110-
b |= ((uint64_t)ni[3]) << 24;
111-
LLVM_FALLTHROUGH;
112-
case 3:
113-
b |= ((uint64_t)ni[2]) << 16;
114-
LLVM_FALLTHROUGH;
115-
case 2:
116-
b |= ((uint64_t)ni[1]) << 8;
117-
LLVM_FALLTHROUGH;
118-
case 1:
119-
b |= ((uint64_t)ni[0]);
120-
break;
121-
case 0:
122-
break;
123-
}
124-
125-
v3 ^= b;
126-
127-
for (i = 0; i < cROUNDS; ++i)
128-
SIPROUND;
129-
130-
v0 ^= b;
131-
132-
if (outlen == 16)
133-
v2 ^= 0xee;
134-
else
135-
v2 ^= 0xff;
136-
137-
for (i = 0; i < dROUNDS; ++i)
138-
SIPROUND;
139-
140-
b = v0 ^ v1 ^ v2 ^ v3;
141-
endian::write64le(out, b);
142-
143-
if (outlen == 8)
144-
return;
145-
146-
v1 ^= 0xdd;
147-
148-
for (i = 0; i < dROUNDS; ++i)
149-
SIPROUND;
150-
151-
b = v0 ^ v1 ^ v2 ^ v3;
152-
endian::write64le(out + 8, b);
153-
}
154-
155-
} // end anonymous namespace
156-
15728
void llvm::getSipHash_2_4_64(ArrayRef<uint8_t> In, const uint8_t (&K)[16],
15829
uint8_t (&Out)[8]) {
15930
siphash<2, 4>(In.data(), In.size(), K, Out);

llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ static_library("Support") {
3131
include_dirs = [
3232
"Unix",
3333
"Windows",
34+
"//third-party/siphash/include",
3435
]
3536
sources = [
3637
"AArch64AttributeParser.cpp",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//===--- SipHash.h - An implementation of SipHash -------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This is a header-only implementation of SipHash. It lacks library
10+
// dependencies so it can be used from LLVM and compiler-rt.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include <stddef.h>
15+
#include <stdint.h>
16+
17+
// Lightly adapted from the SipHash reference C implementation:
18+
// https://github.com/veorq/SipHash
19+
// by Jean-Philippe Aumasson and Daniel J. Bernstein
20+
21+
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
22+
23+
#define U32TO8_LE(p, v) \
24+
(p)[0] = (uint8_t)((v)); \
25+
(p)[1] = (uint8_t)((v) >> 8); \
26+
(p)[2] = (uint8_t)((v) >> 16); \
27+
(p)[3] = (uint8_t)((v) >> 24);
28+
29+
#define U64TO8_LE(p, v) \
30+
U32TO8_LE((p), (uint32_t)((v))); \
31+
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
32+
33+
#define U8TO64_LE(p) \
34+
(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
35+
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
36+
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
37+
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
38+
39+
#define SIPROUND \
40+
do { \
41+
v0 += v1; \
42+
v1 = ROTL(v1, 13); \
43+
v1 ^= v0; \
44+
v0 = ROTL(v0, 32); \
45+
v2 += v3; \
46+
v3 = ROTL(v3, 16); \
47+
v3 ^= v2; \
48+
v0 += v3; \
49+
v3 = ROTL(v3, 21); \
50+
v3 ^= v0; \
51+
v2 += v1; \
52+
v1 = ROTL(v1, 17); \
53+
v1 ^= v2; \
54+
v2 = ROTL(v2, 32); \
55+
} while (0)
56+
57+
namespace {
58+
59+
/// Computes a SipHash value
60+
///
61+
/// \param in: pointer to input data (read-only)
62+
/// \param inlen: input data length in bytes (any size_t value)
63+
/// \param k: reference to the key data 16-byte array (read-only)
64+
/// \returns output data, must be 8 or 16 bytes
65+
///
66+
template <int cROUNDS, int dROUNDS, size_t outlen>
67+
void siphash(const unsigned char *in, uint64_t inlen,
68+
const unsigned char (&k)[16], unsigned char (&out)[outlen]) {
69+
70+
const unsigned char *ni = (const unsigned char *)in;
71+
const unsigned char *kk = (const unsigned char *)k;
72+
73+
static_assert(outlen == 8 || outlen == 16, "result should be 8 or 16 bytes");
74+
75+
uint64_t v0 = UINT64_C(0x736f6d6570736575);
76+
uint64_t v1 = UINT64_C(0x646f72616e646f6d);
77+
uint64_t v2 = UINT64_C(0x6c7967656e657261);
78+
uint64_t v3 = UINT64_C(0x7465646279746573);
79+
uint64_t k0 = U8TO64_LE(kk);
80+
uint64_t k1 = U8TO64_LE(kk + 8);
81+
uint64_t m;
82+
int i;
83+
const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
84+
const int left = inlen & 7;
85+
uint64_t b = ((uint64_t)inlen) << 56;
86+
v3 ^= k1;
87+
v2 ^= k0;
88+
v1 ^= k1;
89+
v0 ^= k0;
90+
91+
if (outlen == 16)
92+
v1 ^= 0xee;
93+
94+
for (; ni != end; ni += 8) {
95+
m = U8TO64_LE(ni);
96+
v3 ^= m;
97+
98+
for (i = 0; i < cROUNDS; ++i)
99+
SIPROUND;
100+
101+
v0 ^= m;
102+
}
103+
104+
switch (left) {
105+
case 7:
106+
b |= ((uint64_t)ni[6]) << 48;
107+
/* FALLTHRU */
108+
case 6:
109+
b |= ((uint64_t)ni[5]) << 40;
110+
/* FALLTHRU */
111+
case 5:
112+
b |= ((uint64_t)ni[4]) << 32;
113+
/* FALLTHRU */
114+
case 4:
115+
b |= ((uint64_t)ni[3]) << 24;
116+
/* FALLTHRU */
117+
case 3:
118+
b |= ((uint64_t)ni[2]) << 16;
119+
/* FALLTHRU */
120+
case 2:
121+
b |= ((uint64_t)ni[1]) << 8;
122+
/* FALLTHRU */
123+
case 1:
124+
b |= ((uint64_t)ni[0]);
125+
/* FALLTHRU */
126+
break;
127+
case 0:
128+
break;
129+
}
130+
131+
v3 ^= b;
132+
133+
for (i = 0; i < cROUNDS; ++i)
134+
SIPROUND;
135+
136+
v0 ^= b;
137+
138+
if (outlen == 16)
139+
v2 ^= 0xee;
140+
else
141+
v2 ^= 0xff;
142+
143+
for (i = 0; i < dROUNDS; ++i)
144+
SIPROUND;
145+
146+
b = v0 ^ v1 ^ v2 ^ v3;
147+
U64TO8_LE(out, b);
148+
149+
if (outlen == 8)
150+
return;
151+
152+
v1 ^= 0xdd;
153+
154+
for (i = 0; i < dROUNDS; ++i)
155+
SIPROUND;
156+
157+
b = v0 ^ v1 ^ v2 ^ v3;
158+
U64TO8_LE(out + 8, b);
159+
}
160+
161+
} // end anonymous namespace

0 commit comments

Comments
 (0)