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