Commit | Line | Data |
---|---|---|
2c956a60 JD |
1 | /* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. |
2 | * | |
3 | * This file is provided under a dual BSD/GPLv2 license. | |
4 | * | |
5 | * SipHash: a fast short-input PRF | |
6 | * https://131002.net/siphash/ | |
7 | * | |
8 | * This implementation is specifically for SipHash2-4. | |
9 | */ | |
10 | ||
11 | #include <linux/siphash.h> | |
12 | #include <asm/unaligned.h> | |
13 | ||
14 | #if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 | |
15 | #include <linux/dcache.h> | |
16 | #include <asm/word-at-a-time.h> | |
17 | #endif | |
18 | ||
19 | #define SIPROUND \ | |
20 | do { \ | |
21 | v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \ | |
22 | v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \ | |
23 | v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \ | |
24 | v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \ | |
25 | } while (0) | |
26 | ||
27 | #define PREAMBLE(len) \ | |
28 | u64 v0 = 0x736f6d6570736575ULL; \ | |
29 | u64 v1 = 0x646f72616e646f6dULL; \ | |
30 | u64 v2 = 0x6c7967656e657261ULL; \ | |
31 | u64 v3 = 0x7465646279746573ULL; \ | |
32 | u64 b = ((u64)(len)) << 56; \ | |
33 | v3 ^= key->key[1]; \ | |
34 | v2 ^= key->key[0]; \ | |
35 | v1 ^= key->key[1]; \ | |
36 | v0 ^= key->key[0]; | |
37 | ||
38 | #define POSTAMBLE \ | |
39 | v3 ^= b; \ | |
40 | SIPROUND; \ | |
41 | SIPROUND; \ | |
42 | v0 ^= b; \ | |
43 | v2 ^= 0xff; \ | |
44 | SIPROUND; \ | |
45 | SIPROUND; \ | |
46 | SIPROUND; \ | |
47 | SIPROUND; \ | |
48 | return (v0 ^ v1) ^ (v2 ^ v3); | |
49 | ||
50 | u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key) | |
51 | { | |
52 | const u8 *end = data + len - (len % sizeof(u64)); | |
53 | const u8 left = len & (sizeof(u64) - 1); | |
54 | u64 m; | |
55 | PREAMBLE(len) | |
56 | for (; data != end; data += sizeof(u64)) { | |
57 | m = le64_to_cpup(data); | |
58 | v3 ^= m; | |
59 | SIPROUND; | |
60 | SIPROUND; | |
61 | v0 ^= m; | |
62 | } | |
63 | #if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 | |
64 | if (left) | |
65 | b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & | |
66 | bytemask_from_count(left))); | |
67 | #else | |
68 | switch (left) { | |
69 | case 7: b |= ((u64)end[6]) << 48; | |
70 | case 6: b |= ((u64)end[5]) << 40; | |
71 | case 5: b |= ((u64)end[4]) << 32; | |
72 | case 4: b |= le32_to_cpup(data); break; | |
73 | case 3: b |= ((u64)end[2]) << 16; | |
74 | case 2: b |= le16_to_cpup(data); break; | |
75 | case 1: b |= end[0]; | |
76 | } | |
77 | #endif | |
78 | POSTAMBLE | |
79 | } | |
80 | EXPORT_SYMBOL(__siphash_aligned); | |
81 | ||
82 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | |
83 | u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key) | |
84 | { | |
85 | const u8 *end = data + len - (len % sizeof(u64)); | |
86 | const u8 left = len & (sizeof(u64) - 1); | |
87 | u64 m; | |
88 | PREAMBLE(len) | |
89 | for (; data != end; data += sizeof(u64)) { | |
90 | m = get_unaligned_le64(data); | |
91 | v3 ^= m; | |
92 | SIPROUND; | |
93 | SIPROUND; | |
94 | v0 ^= m; | |
95 | } | |
96 | #if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 | |
97 | if (left) | |
98 | b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & | |
99 | bytemask_from_count(left))); | |
100 | #else | |
101 | switch (left) { | |
102 | case 7: b |= ((u64)end[6]) << 48; | |
103 | case 6: b |= ((u64)end[5]) << 40; | |
104 | case 5: b |= ((u64)end[4]) << 32; | |
105 | case 4: b |= get_unaligned_le32(end); break; | |
106 | case 3: b |= ((u64)end[2]) << 16; | |
107 | case 2: b |= get_unaligned_le16(end); break; | |
108 | case 1: b |= end[0]; | |
109 | } | |
110 | #endif | |
111 | POSTAMBLE | |
112 | } | |
113 | EXPORT_SYMBOL(__siphash_unaligned); | |
114 | #endif | |
115 | ||
116 | /** | |
117 | * siphash_1u64 - compute 64-bit siphash PRF value of a u64 | |
118 | * @first: first u64 | |
119 | * @key: the siphash key | |
120 | */ | |
121 | u64 siphash_1u64(const u64 first, const siphash_key_t *key) | |
122 | { | |
123 | PREAMBLE(8) | |
124 | v3 ^= first; | |
125 | SIPROUND; | |
126 | SIPROUND; | |
127 | v0 ^= first; | |
128 | POSTAMBLE | |
129 | } | |
130 | EXPORT_SYMBOL(siphash_1u64); | |
131 | ||
132 | /** | |
133 | * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64 | |
134 | * @first: first u64 | |
135 | * @second: second u64 | |
136 | * @key: the siphash key | |
137 | */ | |
138 | u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key) | |
139 | { | |
140 | PREAMBLE(16) | |
141 | v3 ^= first; | |
142 | SIPROUND; | |
143 | SIPROUND; | |
144 | v0 ^= first; | |
145 | v3 ^= second; | |
146 | SIPROUND; | |
147 | SIPROUND; | |
148 | v0 ^= second; | |
149 | POSTAMBLE | |
150 | } | |
151 | EXPORT_SYMBOL(siphash_2u64); | |
152 | ||
153 | /** | |
154 | * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64 | |
155 | * @first: first u64 | |
156 | * @second: second u64 | |
157 | * @third: third u64 | |
158 | * @key: the siphash key | |
159 | */ | |
160 | u64 siphash_3u64(const u64 first, const u64 second, const u64 third, | |
161 | const siphash_key_t *key) | |
162 | { | |
163 | PREAMBLE(24) | |
164 | v3 ^= first; | |
165 | SIPROUND; | |
166 | SIPROUND; | |
167 | v0 ^= first; | |
168 | v3 ^= second; | |
169 | SIPROUND; | |
170 | SIPROUND; | |
171 | v0 ^= second; | |
172 | v3 ^= third; | |
173 | SIPROUND; | |
174 | SIPROUND; | |
175 | v0 ^= third; | |
176 | POSTAMBLE | |
177 | } | |
178 | EXPORT_SYMBOL(siphash_3u64); | |
179 | ||
180 | /** | |
181 | * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64 | |
182 | * @first: first u64 | |
183 | * @second: second u64 | |
184 | * @third: third u64 | |
185 | * @forth: forth u64 | |
186 | * @key: the siphash key | |
187 | */ | |
188 | u64 siphash_4u64(const u64 first, const u64 second, const u64 third, | |
189 | const u64 forth, const siphash_key_t *key) | |
190 | { | |
191 | PREAMBLE(32) | |
192 | v3 ^= first; | |
193 | SIPROUND; | |
194 | SIPROUND; | |
195 | v0 ^= first; | |
196 | v3 ^= second; | |
197 | SIPROUND; | |
198 | SIPROUND; | |
199 | v0 ^= second; | |
200 | v3 ^= third; | |
201 | SIPROUND; | |
202 | SIPROUND; | |
203 | v0 ^= third; | |
204 | v3 ^= forth; | |
205 | SIPROUND; | |
206 | SIPROUND; | |
207 | v0 ^= forth; | |
208 | POSTAMBLE | |
209 | } | |
210 | EXPORT_SYMBOL(siphash_4u64); | |
211 | ||
212 | u64 siphash_1u32(const u32 first, const siphash_key_t *key) | |
213 | { | |
214 | PREAMBLE(4) | |
215 | b |= first; | |
216 | POSTAMBLE | |
217 | } | |
218 | EXPORT_SYMBOL(siphash_1u32); | |
219 | ||
220 | u64 siphash_3u32(const u32 first, const u32 second, const u32 third, | |
221 | const siphash_key_t *key) | |
222 | { | |
223 | u64 combined = (u64)second << 32 | first; | |
224 | PREAMBLE(12) | |
225 | v3 ^= combined; | |
226 | SIPROUND; | |
227 | SIPROUND; | |
228 | v0 ^= combined; | |
229 | b |= third; | |
230 | POSTAMBLE | |
231 | } | |
232 | EXPORT_SYMBOL(siphash_3u32); |