xref: /openbmc/linux/lib/xxhash.c (revision 5d2405227a9eaea48e8cc95756a06d407b11f141)
1*5d240522SNick Terrell /*
2*5d240522SNick Terrell  * xxHash - Extremely Fast Hash algorithm
3*5d240522SNick Terrell  * Copyright (C) 2012-2016, Yann Collet.
4*5d240522SNick Terrell  *
5*5d240522SNick Terrell  * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6*5d240522SNick Terrell  *
7*5d240522SNick Terrell  * Redistribution and use in source and binary forms, with or without
8*5d240522SNick Terrell  * modification, are permitted provided that the following conditions are
9*5d240522SNick Terrell  * met:
10*5d240522SNick Terrell  *
11*5d240522SNick Terrell  *   * Redistributions of source code must retain the above copyright
12*5d240522SNick Terrell  *     notice, this list of conditions and the following disclaimer.
13*5d240522SNick Terrell  *   * Redistributions in binary form must reproduce the above
14*5d240522SNick Terrell  *     copyright notice, this list of conditions and the following disclaimer
15*5d240522SNick Terrell  *     in the documentation and/or other materials provided with the
16*5d240522SNick Terrell  *     distribution.
17*5d240522SNick Terrell  *
18*5d240522SNick Terrell  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19*5d240522SNick Terrell  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20*5d240522SNick Terrell  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21*5d240522SNick Terrell  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22*5d240522SNick Terrell  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23*5d240522SNick Terrell  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24*5d240522SNick Terrell  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25*5d240522SNick Terrell  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26*5d240522SNick Terrell  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27*5d240522SNick Terrell  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28*5d240522SNick Terrell  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*5d240522SNick Terrell  *
30*5d240522SNick Terrell  * This program is free software; you can redistribute it and/or modify it under
31*5d240522SNick Terrell  * the terms of the GNU General Public License version 2 as published by the
32*5d240522SNick Terrell  * Free Software Foundation. This program is dual-licensed; you may select
33*5d240522SNick Terrell  * either version 2 of the GNU General Public License ("GPL") or BSD license
34*5d240522SNick Terrell  * ("BSD").
35*5d240522SNick Terrell  *
36*5d240522SNick Terrell  * You can contact the author at:
37*5d240522SNick Terrell  * - xxHash homepage: http://cyan4973.github.io/xxHash/
38*5d240522SNick Terrell  * - xxHash source repository: https://github.com/Cyan4973/xxHash
39*5d240522SNick Terrell  */
40*5d240522SNick Terrell 
41*5d240522SNick Terrell #include <asm/unaligned.h>
42*5d240522SNick Terrell #include <linux/errno.h>
43*5d240522SNick Terrell #include <linux/compiler.h>
44*5d240522SNick Terrell #include <linux/kernel.h>
45*5d240522SNick Terrell #include <linux/module.h>
46*5d240522SNick Terrell #include <linux/string.h>
47*5d240522SNick Terrell #include <linux/xxhash.h>
48*5d240522SNick Terrell 
49*5d240522SNick Terrell /*-*************************************
50*5d240522SNick Terrell  * Macros
51*5d240522SNick Terrell  **************************************/
52*5d240522SNick Terrell #define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
53*5d240522SNick Terrell #define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
54*5d240522SNick Terrell 
55*5d240522SNick Terrell #ifdef __LITTLE_ENDIAN
56*5d240522SNick Terrell # define XXH_CPU_LITTLE_ENDIAN 1
57*5d240522SNick Terrell #else
58*5d240522SNick Terrell # define XXH_CPU_LITTLE_ENDIAN 0
59*5d240522SNick Terrell #endif
60*5d240522SNick Terrell 
61*5d240522SNick Terrell /*-*************************************
62*5d240522SNick Terrell  * Constants
63*5d240522SNick Terrell  **************************************/
64*5d240522SNick Terrell static const uint32_t PRIME32_1 = 2654435761U;
65*5d240522SNick Terrell static const uint32_t PRIME32_2 = 2246822519U;
66*5d240522SNick Terrell static const uint32_t PRIME32_3 = 3266489917U;
67*5d240522SNick Terrell static const uint32_t PRIME32_4 =  668265263U;
68*5d240522SNick Terrell static const uint32_t PRIME32_5 =  374761393U;
69*5d240522SNick Terrell 
70*5d240522SNick Terrell static const uint64_t PRIME64_1 = 11400714785074694791ULL;
71*5d240522SNick Terrell static const uint64_t PRIME64_2 = 14029467366897019727ULL;
72*5d240522SNick Terrell static const uint64_t PRIME64_3 =  1609587929392839161ULL;
73*5d240522SNick Terrell static const uint64_t PRIME64_4 =  9650029242287828579ULL;
74*5d240522SNick Terrell static const uint64_t PRIME64_5 =  2870177450012600261ULL;
75*5d240522SNick Terrell 
76*5d240522SNick Terrell /*-**************************
77*5d240522SNick Terrell  *  Utils
78*5d240522SNick Terrell  ***************************/
79*5d240522SNick Terrell void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
80*5d240522SNick Terrell {
81*5d240522SNick Terrell 	memcpy(dst, src, sizeof(*dst));
82*5d240522SNick Terrell }
83*5d240522SNick Terrell EXPORT_SYMBOL(xxh32_copy_state);
84*5d240522SNick Terrell 
85*5d240522SNick Terrell void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
86*5d240522SNick Terrell {
87*5d240522SNick Terrell 	memcpy(dst, src, sizeof(*dst));
88*5d240522SNick Terrell }
89*5d240522SNick Terrell EXPORT_SYMBOL(xxh64_copy_state);
90*5d240522SNick Terrell 
91*5d240522SNick Terrell /*-***************************
92*5d240522SNick Terrell  * Simple Hash Functions
93*5d240522SNick Terrell  ****************************/
94*5d240522SNick Terrell static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
95*5d240522SNick Terrell {
96*5d240522SNick Terrell 	seed += input * PRIME32_2;
97*5d240522SNick Terrell 	seed = xxh_rotl32(seed, 13);
98*5d240522SNick Terrell 	seed *= PRIME32_1;
99*5d240522SNick Terrell 	return seed;
100*5d240522SNick Terrell }
101*5d240522SNick Terrell 
102*5d240522SNick Terrell uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
103*5d240522SNick Terrell {
104*5d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
105*5d240522SNick Terrell 	const uint8_t *b_end = p + len;
106*5d240522SNick Terrell 	uint32_t h32;
107*5d240522SNick Terrell 
108*5d240522SNick Terrell 	if (len >= 16) {
109*5d240522SNick Terrell 		const uint8_t *const limit = b_end - 16;
110*5d240522SNick Terrell 		uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
111*5d240522SNick Terrell 		uint32_t v2 = seed + PRIME32_2;
112*5d240522SNick Terrell 		uint32_t v3 = seed + 0;
113*5d240522SNick Terrell 		uint32_t v4 = seed - PRIME32_1;
114*5d240522SNick Terrell 
115*5d240522SNick Terrell 		do {
116*5d240522SNick Terrell 			v1 = xxh32_round(v1, get_unaligned_le32(p));
117*5d240522SNick Terrell 			p += 4;
118*5d240522SNick Terrell 			v2 = xxh32_round(v2, get_unaligned_le32(p));
119*5d240522SNick Terrell 			p += 4;
120*5d240522SNick Terrell 			v3 = xxh32_round(v3, get_unaligned_le32(p));
121*5d240522SNick Terrell 			p += 4;
122*5d240522SNick Terrell 			v4 = xxh32_round(v4, get_unaligned_le32(p));
123*5d240522SNick Terrell 			p += 4;
124*5d240522SNick Terrell 		} while (p <= limit);
125*5d240522SNick Terrell 
126*5d240522SNick Terrell 		h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
127*5d240522SNick Terrell 			xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
128*5d240522SNick Terrell 	} else {
129*5d240522SNick Terrell 		h32 = seed + PRIME32_5;
130*5d240522SNick Terrell 	}
131*5d240522SNick Terrell 
132*5d240522SNick Terrell 	h32 += (uint32_t)len;
133*5d240522SNick Terrell 
134*5d240522SNick Terrell 	while (p + 4 <= b_end) {
135*5d240522SNick Terrell 		h32 += get_unaligned_le32(p) * PRIME32_3;
136*5d240522SNick Terrell 		h32 = xxh_rotl32(h32, 17) * PRIME32_4;
137*5d240522SNick Terrell 		p += 4;
138*5d240522SNick Terrell 	}
139*5d240522SNick Terrell 
140*5d240522SNick Terrell 	while (p < b_end) {
141*5d240522SNick Terrell 		h32 += (*p) * PRIME32_5;
142*5d240522SNick Terrell 		h32 = xxh_rotl32(h32, 11) * PRIME32_1;
143*5d240522SNick Terrell 		p++;
144*5d240522SNick Terrell 	}
145*5d240522SNick Terrell 
146*5d240522SNick Terrell 	h32 ^= h32 >> 15;
147*5d240522SNick Terrell 	h32 *= PRIME32_2;
148*5d240522SNick Terrell 	h32 ^= h32 >> 13;
149*5d240522SNick Terrell 	h32 *= PRIME32_3;
150*5d240522SNick Terrell 	h32 ^= h32 >> 16;
151*5d240522SNick Terrell 
152*5d240522SNick Terrell 	return h32;
153*5d240522SNick Terrell }
154*5d240522SNick Terrell EXPORT_SYMBOL(xxh32);
155*5d240522SNick Terrell 
156*5d240522SNick Terrell static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
157*5d240522SNick Terrell {
158*5d240522SNick Terrell 	acc += input * PRIME64_2;
159*5d240522SNick Terrell 	acc = xxh_rotl64(acc, 31);
160*5d240522SNick Terrell 	acc *= PRIME64_1;
161*5d240522SNick Terrell 	return acc;
162*5d240522SNick Terrell }
163*5d240522SNick Terrell 
164*5d240522SNick Terrell static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
165*5d240522SNick Terrell {
166*5d240522SNick Terrell 	val = xxh64_round(0, val);
167*5d240522SNick Terrell 	acc ^= val;
168*5d240522SNick Terrell 	acc = acc * PRIME64_1 + PRIME64_4;
169*5d240522SNick Terrell 	return acc;
170*5d240522SNick Terrell }
171*5d240522SNick Terrell 
172*5d240522SNick Terrell uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
173*5d240522SNick Terrell {
174*5d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
175*5d240522SNick Terrell 	const uint8_t *const b_end = p + len;
176*5d240522SNick Terrell 	uint64_t h64;
177*5d240522SNick Terrell 
178*5d240522SNick Terrell 	if (len >= 32) {
179*5d240522SNick Terrell 		const uint8_t *const limit = b_end - 32;
180*5d240522SNick Terrell 		uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
181*5d240522SNick Terrell 		uint64_t v2 = seed + PRIME64_2;
182*5d240522SNick Terrell 		uint64_t v3 = seed + 0;
183*5d240522SNick Terrell 		uint64_t v4 = seed - PRIME64_1;
184*5d240522SNick Terrell 
185*5d240522SNick Terrell 		do {
186*5d240522SNick Terrell 			v1 = xxh64_round(v1, get_unaligned_le64(p));
187*5d240522SNick Terrell 			p += 8;
188*5d240522SNick Terrell 			v2 = xxh64_round(v2, get_unaligned_le64(p));
189*5d240522SNick Terrell 			p += 8;
190*5d240522SNick Terrell 			v3 = xxh64_round(v3, get_unaligned_le64(p));
191*5d240522SNick Terrell 			p += 8;
192*5d240522SNick Terrell 			v4 = xxh64_round(v4, get_unaligned_le64(p));
193*5d240522SNick Terrell 			p += 8;
194*5d240522SNick Terrell 		} while (p <= limit);
195*5d240522SNick Terrell 
196*5d240522SNick Terrell 		h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
197*5d240522SNick Terrell 			xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
198*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v1);
199*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v2);
200*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v3);
201*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v4);
202*5d240522SNick Terrell 
203*5d240522SNick Terrell 	} else {
204*5d240522SNick Terrell 		h64  = seed + PRIME64_5;
205*5d240522SNick Terrell 	}
206*5d240522SNick Terrell 
207*5d240522SNick Terrell 	h64 += (uint64_t)len;
208*5d240522SNick Terrell 
209*5d240522SNick Terrell 	while (p + 8 <= b_end) {
210*5d240522SNick Terrell 		const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
211*5d240522SNick Terrell 
212*5d240522SNick Terrell 		h64 ^= k1;
213*5d240522SNick Terrell 		h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
214*5d240522SNick Terrell 		p += 8;
215*5d240522SNick Terrell 	}
216*5d240522SNick Terrell 
217*5d240522SNick Terrell 	if (p + 4 <= b_end) {
218*5d240522SNick Terrell 		h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
219*5d240522SNick Terrell 		h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
220*5d240522SNick Terrell 		p += 4;
221*5d240522SNick Terrell 	}
222*5d240522SNick Terrell 
223*5d240522SNick Terrell 	while (p < b_end) {
224*5d240522SNick Terrell 		h64 ^= (*p) * PRIME64_5;
225*5d240522SNick Terrell 		h64 = xxh_rotl64(h64, 11) * PRIME64_1;
226*5d240522SNick Terrell 		p++;
227*5d240522SNick Terrell 	}
228*5d240522SNick Terrell 
229*5d240522SNick Terrell 	h64 ^= h64 >> 33;
230*5d240522SNick Terrell 	h64 *= PRIME64_2;
231*5d240522SNick Terrell 	h64 ^= h64 >> 29;
232*5d240522SNick Terrell 	h64 *= PRIME64_3;
233*5d240522SNick Terrell 	h64 ^= h64 >> 32;
234*5d240522SNick Terrell 
235*5d240522SNick Terrell 	return h64;
236*5d240522SNick Terrell }
237*5d240522SNick Terrell EXPORT_SYMBOL(xxh64);
238*5d240522SNick Terrell 
239*5d240522SNick Terrell /*-**************************************************
240*5d240522SNick Terrell  * Advanced Hash Functions
241*5d240522SNick Terrell  ***************************************************/
242*5d240522SNick Terrell void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
243*5d240522SNick Terrell {
244*5d240522SNick Terrell 	/* use a local state for memcpy() to avoid strict-aliasing warnings */
245*5d240522SNick Terrell 	struct xxh32_state state;
246*5d240522SNick Terrell 
247*5d240522SNick Terrell 	memset(&state, 0, sizeof(state));
248*5d240522SNick Terrell 	state.v1 = seed + PRIME32_1 + PRIME32_2;
249*5d240522SNick Terrell 	state.v2 = seed + PRIME32_2;
250*5d240522SNick Terrell 	state.v3 = seed + 0;
251*5d240522SNick Terrell 	state.v4 = seed - PRIME32_1;
252*5d240522SNick Terrell 	memcpy(statePtr, &state, sizeof(state));
253*5d240522SNick Terrell }
254*5d240522SNick Terrell EXPORT_SYMBOL(xxh32_reset);
255*5d240522SNick Terrell 
256*5d240522SNick Terrell void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
257*5d240522SNick Terrell {
258*5d240522SNick Terrell 	/* use a local state for memcpy() to avoid strict-aliasing warnings */
259*5d240522SNick Terrell 	struct xxh64_state state;
260*5d240522SNick Terrell 
261*5d240522SNick Terrell 	memset(&state, 0, sizeof(state));
262*5d240522SNick Terrell 	state.v1 = seed + PRIME64_1 + PRIME64_2;
263*5d240522SNick Terrell 	state.v2 = seed + PRIME64_2;
264*5d240522SNick Terrell 	state.v3 = seed + 0;
265*5d240522SNick Terrell 	state.v4 = seed - PRIME64_1;
266*5d240522SNick Terrell 	memcpy(statePtr, &state, sizeof(state));
267*5d240522SNick Terrell }
268*5d240522SNick Terrell EXPORT_SYMBOL(xxh64_reset);
269*5d240522SNick Terrell 
270*5d240522SNick Terrell int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
271*5d240522SNick Terrell {
272*5d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
273*5d240522SNick Terrell 	const uint8_t *const b_end = p + len;
274*5d240522SNick Terrell 
275*5d240522SNick Terrell 	if (input == NULL)
276*5d240522SNick Terrell 		return -EINVAL;
277*5d240522SNick Terrell 
278*5d240522SNick Terrell 	state->total_len_32 += (uint32_t)len;
279*5d240522SNick Terrell 	state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
280*5d240522SNick Terrell 
281*5d240522SNick Terrell 	if (state->memsize + len < 16) { /* fill in tmp buffer */
282*5d240522SNick Terrell 		memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
283*5d240522SNick Terrell 		state->memsize += (uint32_t)len;
284*5d240522SNick Terrell 		return 0;
285*5d240522SNick Terrell 	}
286*5d240522SNick Terrell 
287*5d240522SNick Terrell 	if (state->memsize) { /* some data left from previous update */
288*5d240522SNick Terrell 		const uint32_t *p32 = state->mem32;
289*5d240522SNick Terrell 
290*5d240522SNick Terrell 		memcpy((uint8_t *)(state->mem32) + state->memsize, input,
291*5d240522SNick Terrell 			16 - state->memsize);
292*5d240522SNick Terrell 
293*5d240522SNick Terrell 		state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
294*5d240522SNick Terrell 		p32++;
295*5d240522SNick Terrell 		state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
296*5d240522SNick Terrell 		p32++;
297*5d240522SNick Terrell 		state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
298*5d240522SNick Terrell 		p32++;
299*5d240522SNick Terrell 		state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
300*5d240522SNick Terrell 		p32++;
301*5d240522SNick Terrell 
302*5d240522SNick Terrell 		p += 16-state->memsize;
303*5d240522SNick Terrell 		state->memsize = 0;
304*5d240522SNick Terrell 	}
305*5d240522SNick Terrell 
306*5d240522SNick Terrell 	if (p <= b_end - 16) {
307*5d240522SNick Terrell 		const uint8_t *const limit = b_end - 16;
308*5d240522SNick Terrell 		uint32_t v1 = state->v1;
309*5d240522SNick Terrell 		uint32_t v2 = state->v2;
310*5d240522SNick Terrell 		uint32_t v3 = state->v3;
311*5d240522SNick Terrell 		uint32_t v4 = state->v4;
312*5d240522SNick Terrell 
313*5d240522SNick Terrell 		do {
314*5d240522SNick Terrell 			v1 = xxh32_round(v1, get_unaligned_le32(p));
315*5d240522SNick Terrell 			p += 4;
316*5d240522SNick Terrell 			v2 = xxh32_round(v2, get_unaligned_le32(p));
317*5d240522SNick Terrell 			p += 4;
318*5d240522SNick Terrell 			v3 = xxh32_round(v3, get_unaligned_le32(p));
319*5d240522SNick Terrell 			p += 4;
320*5d240522SNick Terrell 			v4 = xxh32_round(v4, get_unaligned_le32(p));
321*5d240522SNick Terrell 			p += 4;
322*5d240522SNick Terrell 		} while (p <= limit);
323*5d240522SNick Terrell 
324*5d240522SNick Terrell 		state->v1 = v1;
325*5d240522SNick Terrell 		state->v2 = v2;
326*5d240522SNick Terrell 		state->v3 = v3;
327*5d240522SNick Terrell 		state->v4 = v4;
328*5d240522SNick Terrell 	}
329*5d240522SNick Terrell 
330*5d240522SNick Terrell 	if (p < b_end) {
331*5d240522SNick Terrell 		memcpy(state->mem32, p, (size_t)(b_end-p));
332*5d240522SNick Terrell 		state->memsize = (uint32_t)(b_end-p);
333*5d240522SNick Terrell 	}
334*5d240522SNick Terrell 
335*5d240522SNick Terrell 	return 0;
336*5d240522SNick Terrell }
337*5d240522SNick Terrell EXPORT_SYMBOL(xxh32_update);
338*5d240522SNick Terrell 
339*5d240522SNick Terrell uint32_t xxh32_digest(const struct xxh32_state *state)
340*5d240522SNick Terrell {
341*5d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)state->mem32;
342*5d240522SNick Terrell 	const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
343*5d240522SNick Terrell 		state->memsize;
344*5d240522SNick Terrell 	uint32_t h32;
345*5d240522SNick Terrell 
346*5d240522SNick Terrell 	if (state->large_len) {
347*5d240522SNick Terrell 		h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
348*5d240522SNick Terrell 			xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
349*5d240522SNick Terrell 	} else {
350*5d240522SNick Terrell 		h32 = state->v3 /* == seed */ + PRIME32_5;
351*5d240522SNick Terrell 	}
352*5d240522SNick Terrell 
353*5d240522SNick Terrell 	h32 += state->total_len_32;
354*5d240522SNick Terrell 
355*5d240522SNick Terrell 	while (p + 4 <= b_end) {
356*5d240522SNick Terrell 		h32 += get_unaligned_le32(p) * PRIME32_3;
357*5d240522SNick Terrell 		h32 = xxh_rotl32(h32, 17) * PRIME32_4;
358*5d240522SNick Terrell 		p += 4;
359*5d240522SNick Terrell 	}
360*5d240522SNick Terrell 
361*5d240522SNick Terrell 	while (p < b_end) {
362*5d240522SNick Terrell 		h32 += (*p) * PRIME32_5;
363*5d240522SNick Terrell 		h32 = xxh_rotl32(h32, 11) * PRIME32_1;
364*5d240522SNick Terrell 		p++;
365*5d240522SNick Terrell 	}
366*5d240522SNick Terrell 
367*5d240522SNick Terrell 	h32 ^= h32 >> 15;
368*5d240522SNick Terrell 	h32 *= PRIME32_2;
369*5d240522SNick Terrell 	h32 ^= h32 >> 13;
370*5d240522SNick Terrell 	h32 *= PRIME32_3;
371*5d240522SNick Terrell 	h32 ^= h32 >> 16;
372*5d240522SNick Terrell 
373*5d240522SNick Terrell 	return h32;
374*5d240522SNick Terrell }
375*5d240522SNick Terrell EXPORT_SYMBOL(xxh32_digest);
376*5d240522SNick Terrell 
377*5d240522SNick Terrell int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
378*5d240522SNick Terrell {
379*5d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
380*5d240522SNick Terrell 	const uint8_t *const b_end = p + len;
381*5d240522SNick Terrell 
382*5d240522SNick Terrell 	if (input == NULL)
383*5d240522SNick Terrell 		return -EINVAL;
384*5d240522SNick Terrell 
385*5d240522SNick Terrell 	state->total_len += len;
386*5d240522SNick Terrell 
387*5d240522SNick Terrell 	if (state->memsize + len < 32) { /* fill in tmp buffer */
388*5d240522SNick Terrell 		memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
389*5d240522SNick Terrell 		state->memsize += (uint32_t)len;
390*5d240522SNick Terrell 		return 0;
391*5d240522SNick Terrell 	}
392*5d240522SNick Terrell 
393*5d240522SNick Terrell 	if (state->memsize) { /* tmp buffer is full */
394*5d240522SNick Terrell 		uint64_t *p64 = state->mem64;
395*5d240522SNick Terrell 
396*5d240522SNick Terrell 		memcpy(((uint8_t *)p64) + state->memsize, input,
397*5d240522SNick Terrell 			32 - state->memsize);
398*5d240522SNick Terrell 
399*5d240522SNick Terrell 		state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
400*5d240522SNick Terrell 		p64++;
401*5d240522SNick Terrell 		state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
402*5d240522SNick Terrell 		p64++;
403*5d240522SNick Terrell 		state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
404*5d240522SNick Terrell 		p64++;
405*5d240522SNick Terrell 		state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
406*5d240522SNick Terrell 
407*5d240522SNick Terrell 		p += 32 - state->memsize;
408*5d240522SNick Terrell 		state->memsize = 0;
409*5d240522SNick Terrell 	}
410*5d240522SNick Terrell 
411*5d240522SNick Terrell 	if (p + 32 <= b_end) {
412*5d240522SNick Terrell 		const uint8_t *const limit = b_end - 32;
413*5d240522SNick Terrell 		uint64_t v1 = state->v1;
414*5d240522SNick Terrell 		uint64_t v2 = state->v2;
415*5d240522SNick Terrell 		uint64_t v3 = state->v3;
416*5d240522SNick Terrell 		uint64_t v4 = state->v4;
417*5d240522SNick Terrell 
418*5d240522SNick Terrell 		do {
419*5d240522SNick Terrell 			v1 = xxh64_round(v1, get_unaligned_le64(p));
420*5d240522SNick Terrell 			p += 8;
421*5d240522SNick Terrell 			v2 = xxh64_round(v2, get_unaligned_le64(p));
422*5d240522SNick Terrell 			p += 8;
423*5d240522SNick Terrell 			v3 = xxh64_round(v3, get_unaligned_le64(p));
424*5d240522SNick Terrell 			p += 8;
425*5d240522SNick Terrell 			v4 = xxh64_round(v4, get_unaligned_le64(p));
426*5d240522SNick Terrell 			p += 8;
427*5d240522SNick Terrell 		} while (p <= limit);
428*5d240522SNick Terrell 
429*5d240522SNick Terrell 		state->v1 = v1;
430*5d240522SNick Terrell 		state->v2 = v2;
431*5d240522SNick Terrell 		state->v3 = v3;
432*5d240522SNick Terrell 		state->v4 = v4;
433*5d240522SNick Terrell 	}
434*5d240522SNick Terrell 
435*5d240522SNick Terrell 	if (p < b_end) {
436*5d240522SNick Terrell 		memcpy(state->mem64, p, (size_t)(b_end-p));
437*5d240522SNick Terrell 		state->memsize = (uint32_t)(b_end - p);
438*5d240522SNick Terrell 	}
439*5d240522SNick Terrell 
440*5d240522SNick Terrell 	return 0;
441*5d240522SNick Terrell }
442*5d240522SNick Terrell EXPORT_SYMBOL(xxh64_update);
443*5d240522SNick Terrell 
444*5d240522SNick Terrell uint64_t xxh64_digest(const struct xxh64_state *state)
445*5d240522SNick Terrell {
446*5d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)state->mem64;
447*5d240522SNick Terrell 	const uint8_t *const b_end = (const uint8_t *)state->mem64 +
448*5d240522SNick Terrell 		state->memsize;
449*5d240522SNick Terrell 	uint64_t h64;
450*5d240522SNick Terrell 
451*5d240522SNick Terrell 	if (state->total_len >= 32) {
452*5d240522SNick Terrell 		const uint64_t v1 = state->v1;
453*5d240522SNick Terrell 		const uint64_t v2 = state->v2;
454*5d240522SNick Terrell 		const uint64_t v3 = state->v3;
455*5d240522SNick Terrell 		const uint64_t v4 = state->v4;
456*5d240522SNick Terrell 
457*5d240522SNick Terrell 		h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
458*5d240522SNick Terrell 			xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
459*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v1);
460*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v2);
461*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v3);
462*5d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v4);
463*5d240522SNick Terrell 	} else {
464*5d240522SNick Terrell 		h64  = state->v3 + PRIME64_5;
465*5d240522SNick Terrell 	}
466*5d240522SNick Terrell 
467*5d240522SNick Terrell 	h64 += (uint64_t)state->total_len;
468*5d240522SNick Terrell 
469*5d240522SNick Terrell 	while (p + 8 <= b_end) {
470*5d240522SNick Terrell 		const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
471*5d240522SNick Terrell 
472*5d240522SNick Terrell 		h64 ^= k1;
473*5d240522SNick Terrell 		h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
474*5d240522SNick Terrell 		p += 8;
475*5d240522SNick Terrell 	}
476*5d240522SNick Terrell 
477*5d240522SNick Terrell 	if (p + 4 <= b_end) {
478*5d240522SNick Terrell 		h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
479*5d240522SNick Terrell 		h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
480*5d240522SNick Terrell 		p += 4;
481*5d240522SNick Terrell 	}
482*5d240522SNick Terrell 
483*5d240522SNick Terrell 	while (p < b_end) {
484*5d240522SNick Terrell 		h64 ^= (*p) * PRIME64_5;
485*5d240522SNick Terrell 		h64 = xxh_rotl64(h64, 11) * PRIME64_1;
486*5d240522SNick Terrell 		p++;
487*5d240522SNick Terrell 	}
488*5d240522SNick Terrell 
489*5d240522SNick Terrell 	h64 ^= h64 >> 33;
490*5d240522SNick Terrell 	h64 *= PRIME64_2;
491*5d240522SNick Terrell 	h64 ^= h64 >> 29;
492*5d240522SNick Terrell 	h64 *= PRIME64_3;
493*5d240522SNick Terrell 	h64 ^= h64 >> 32;
494*5d240522SNick Terrell 
495*5d240522SNick Terrell 	return h64;
496*5d240522SNick Terrell }
497*5d240522SNick Terrell EXPORT_SYMBOL(xxh64_digest);
498*5d240522SNick Terrell 
499*5d240522SNick Terrell MODULE_LICENSE("Dual BSD/GPL");
500*5d240522SNick Terrell MODULE_DESCRIPTION("xxHash");
501