Skip to content

Commit cfbed2c

Browse files
[Support] Import SipHash c reference implementation. (#94393)
This brings the unmodified SipHash reference implementation: https://github.com/veorq/SipHash which has been very graciously licensed under our llvm license (Apache-2.0 WITH LLVM-exception) by Jean-Philippe Aumasson. SipHash is a lightweight hash function optimized for speed on short messages. We use it as part of the AArch64 ptrauth ABI (in arm64e and ELF PAuth) to generate discriminators based on language identifiers and mangled names. This commit brings the unmodified reference implementation and tests as of f26d35e, specifically siphash.c and vectors.h, as SipHash.cpp and SipHashTest.cpp. Next, we will integrate it properly into libSupport, with a wrapping API suited for the ptrauth use-case.
1 parent 84e9401 commit cfbed2c

File tree

4 files changed

+3017
-0
lines changed

4 files changed

+3017
-0
lines changed

llvm/lib/Support/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ endif()
127127

128128
add_subdirectory(BLAKE3)
129129

130+
# Temporarily ignore SipHash.cpp before we fully integrate it into LLVMSupport.
131+
set(LLVM_OPTIONAL_SOURCES SipHash.cpp)
132+
130133
add_llvm_component_library(LLVMSupport
131134
ABIBreak.cpp
132135
AMDGPUMetadata.cpp

llvm/lib/Support/SipHash.cpp

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
SipHash reference C implementation
3+
4+
Copyright (c) 2012-2022 Jean-Philippe Aumasson
5+
<jeanphilippe.aumasson@gmail.com>
6+
Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
7+
8+
To the extent possible under law, the author(s) have dedicated all copyright
9+
and related and neighboring rights to this software to the public domain
10+
worldwide. This software is distributed without any warranty.
11+
12+
You should have received a copy of the CC0 Public Domain Dedication along
13+
with
14+
this software. If not, see
15+
<http://creativecommons.org/publicdomain/zero/1.0/>.
16+
*/
17+
18+
#include "siphash.h"
19+
#include <assert.h>
20+
#include <stddef.h>
21+
#include <stdint.h>
22+
23+
/* default: SipHash-2-4 */
24+
#ifndef cROUNDS
25+
#define cROUNDS 2
26+
#endif
27+
#ifndef dROUNDS
28+
#define dROUNDS 4
29+
#endif
30+
31+
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
32+
33+
#define U32TO8_LE(p, v) \
34+
(p)[0] = (uint8_t)((v)); \
35+
(p)[1] = (uint8_t)((v) >> 8); \
36+
(p)[2] = (uint8_t)((v) >> 16); \
37+
(p)[3] = (uint8_t)((v) >> 24);
38+
39+
#define U64TO8_LE(p, v) \
40+
U32TO8_LE((p), (uint32_t)((v))); \
41+
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
42+
43+
#define U8TO64_LE(p) \
44+
(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
45+
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
46+
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
47+
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
48+
49+
#define SIPROUND \
50+
do { \
51+
v0 += v1; \
52+
v1 = ROTL(v1, 13); \
53+
v1 ^= v0; \
54+
v0 = ROTL(v0, 32); \
55+
v2 += v3; \
56+
v3 = ROTL(v3, 16); \
57+
v3 ^= v2; \
58+
v0 += v3; \
59+
v3 = ROTL(v3, 21); \
60+
v3 ^= v0; \
61+
v2 += v1; \
62+
v1 = ROTL(v1, 17); \
63+
v1 ^= v2; \
64+
v2 = ROTL(v2, 32); \
65+
} while (0)
66+
67+
#ifdef DEBUG_SIPHASH
68+
#include <stdio.h>
69+
70+
#define TRACE \
71+
do { \
72+
printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \
73+
printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \
74+
printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \
75+
printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \
76+
} while (0)
77+
#else
78+
#define TRACE
79+
#endif
80+
81+
/*
82+
Computes a SipHash value
83+
*in: pointer to input data (read-only)
84+
inlen: input data length in bytes (any size_t value)
85+
*k: pointer to the key data (read-only), must be 16 bytes
86+
*out: pointer to output data (write-only), outlen bytes must be allocated
87+
outlen: length of the output in bytes, must be 8 or 16
88+
*/
89+
int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out,
90+
const size_t outlen) {
91+
92+
const unsigned char *ni = (const unsigned char *)in;
93+
const unsigned char *kk = (const unsigned char *)k;
94+
95+
assert((outlen == 8) || (outlen == 16));
96+
uint64_t v0 = UINT64_C(0x736f6d6570736575);
97+
uint64_t v1 = UINT64_C(0x646f72616e646f6d);
98+
uint64_t v2 = UINT64_C(0x6c7967656e657261);
99+
uint64_t v3 = UINT64_C(0x7465646279746573);
100+
uint64_t k0 = U8TO64_LE(kk);
101+
uint64_t k1 = U8TO64_LE(kk + 8);
102+
uint64_t m;
103+
int i;
104+
const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
105+
const int left = inlen & 7;
106+
uint64_t b = ((uint64_t)inlen) << 56;
107+
v3 ^= k1;
108+
v2 ^= k0;
109+
v1 ^= k1;
110+
v0 ^= k0;
111+
112+
if (outlen == 16)
113+
v1 ^= 0xee;
114+
115+
for (; ni != end; ni += 8) {
116+
m = U8TO64_LE(ni);
117+
v3 ^= m;
118+
119+
TRACE;
120+
for (i = 0; i < cROUNDS; ++i)
121+
SIPROUND;
122+
123+
v0 ^= m;
124+
}
125+
126+
switch (left) {
127+
case 7:
128+
b |= ((uint64_t)ni[6]) << 48;
129+
/* FALLTHRU */
130+
case 6:
131+
b |= ((uint64_t)ni[5]) << 40;
132+
/* FALLTHRU */
133+
case 5:
134+
b |= ((uint64_t)ni[4]) << 32;
135+
/* FALLTHRU */
136+
case 4:
137+
b |= ((uint64_t)ni[3]) << 24;
138+
/* FALLTHRU */
139+
case 3:
140+
b |= ((uint64_t)ni[2]) << 16;
141+
/* FALLTHRU */
142+
case 2:
143+
b |= ((uint64_t)ni[1]) << 8;
144+
/* FALLTHRU */
145+
case 1:
146+
b |= ((uint64_t)ni[0]);
147+
break;
148+
case 0:
149+
break;
150+
}
151+
152+
v3 ^= b;
153+
154+
TRACE;
155+
for (i = 0; i < cROUNDS; ++i)
156+
SIPROUND;
157+
158+
v0 ^= b;
159+
160+
if (outlen == 16)
161+
v2 ^= 0xee;
162+
else
163+
v2 ^= 0xff;
164+
165+
TRACE;
166+
for (i = 0; i < dROUNDS; ++i)
167+
SIPROUND;
168+
169+
b = v0 ^ v1 ^ v2 ^ v3;
170+
U64TO8_LE(out, b);
171+
172+
if (outlen == 8)
173+
return 0;
174+
175+
v1 ^= 0xdd;
176+
177+
TRACE;
178+
for (i = 0; i < dROUNDS; ++i)
179+
SIPROUND;
180+
181+
b = v0 ^ v1 ^ v2 ^ v3;
182+
U64TO8_LE(out + 8, b);
183+
184+
return 0;
185+
}

llvm/unittests/Support/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ set(LLVM_LINK_COMPONENTS
33
TargetParser
44
)
55

6+
# Temporarily ignore SipHashTest.cpp before we fully integrate it.
7+
set(LLVM_OPTIONAL_SOURCES SipHashTest.cpp)
8+
69
add_llvm_unittest(SupportTests
710
AddressRangeTest.cpp
811
AlignmentTest.cpp

0 commit comments

Comments
 (0)