xref: /openbmc/linux/lib/xxhash.c (revision d89775fc)
15d240522SNick Terrell /*
25d240522SNick Terrell  * xxHash - Extremely Fast Hash algorithm
35d240522SNick Terrell  * Copyright (C) 2012-2016, Yann Collet.
45d240522SNick Terrell  *
55d240522SNick Terrell  * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
65d240522SNick Terrell  *
75d240522SNick Terrell  * Redistribution and use in source and binary forms, with or without
85d240522SNick Terrell  * modification, are permitted provided that the following conditions are
95d240522SNick Terrell  * met:
105d240522SNick Terrell  *
115d240522SNick Terrell  *   * Redistributions of source code must retain the above copyright
125d240522SNick Terrell  *     notice, this list of conditions and the following disclaimer.
135d240522SNick Terrell  *   * Redistributions in binary form must reproduce the above
145d240522SNick Terrell  *     copyright notice, this list of conditions and the following disclaimer
155d240522SNick Terrell  *     in the documentation and/or other materials provided with the
165d240522SNick Terrell  *     distribution.
175d240522SNick Terrell  *
185d240522SNick Terrell  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195d240522SNick Terrell  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205d240522SNick Terrell  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215d240522SNick Terrell  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225d240522SNick Terrell  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235d240522SNick Terrell  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245d240522SNick Terrell  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255d240522SNick Terrell  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265d240522SNick Terrell  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275d240522SNick Terrell  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285d240522SNick Terrell  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295d240522SNick Terrell  *
305d240522SNick Terrell  * This program is free software; you can redistribute it and/or modify it under
315d240522SNick Terrell  * the terms of the GNU General Public License version 2 as published by the
325d240522SNick Terrell  * Free Software Foundation. This program is dual-licensed; you may select
335d240522SNick Terrell  * either version 2 of the GNU General Public License ("GPL") or BSD license
345d240522SNick Terrell  * ("BSD").
355d240522SNick Terrell  *
365d240522SNick Terrell  * You can contact the author at:
37d89775fcSAlexander A. Klimov  * - xxHash homepage: https://cyan4973.github.io/xxHash/
385d240522SNick Terrell  * - xxHash source repository: https://github.com/Cyan4973/xxHash
395d240522SNick Terrell  */
405d240522SNick Terrell 
415d240522SNick Terrell #include <asm/unaligned.h>
425d240522SNick Terrell #include <linux/errno.h>
435d240522SNick Terrell #include <linux/compiler.h>
445d240522SNick Terrell #include <linux/kernel.h>
455d240522SNick Terrell #include <linux/module.h>
465d240522SNick Terrell #include <linux/string.h>
475d240522SNick Terrell #include <linux/xxhash.h>
485d240522SNick Terrell 
495d240522SNick Terrell /*-*************************************
505d240522SNick Terrell  * Macros
515d240522SNick Terrell  **************************************/
525d240522SNick Terrell #define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
535d240522SNick Terrell #define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
545d240522SNick Terrell 
555d240522SNick Terrell #ifdef __LITTLE_ENDIAN
565d240522SNick Terrell # define XXH_CPU_LITTLE_ENDIAN 1
575d240522SNick Terrell #else
585d240522SNick Terrell # define XXH_CPU_LITTLE_ENDIAN 0
595d240522SNick Terrell #endif
605d240522SNick Terrell 
615d240522SNick Terrell /*-*************************************
625d240522SNick Terrell  * Constants
635d240522SNick Terrell  **************************************/
645d240522SNick Terrell static const uint32_t PRIME32_1 = 2654435761U;
655d240522SNick Terrell static const uint32_t PRIME32_2 = 2246822519U;
665d240522SNick Terrell static const uint32_t PRIME32_3 = 3266489917U;
675d240522SNick Terrell static const uint32_t PRIME32_4 =  668265263U;
685d240522SNick Terrell static const uint32_t PRIME32_5 =  374761393U;
695d240522SNick Terrell 
705d240522SNick Terrell static const uint64_t PRIME64_1 = 11400714785074694791ULL;
715d240522SNick Terrell static const uint64_t PRIME64_2 = 14029467366897019727ULL;
725d240522SNick Terrell static const uint64_t PRIME64_3 =  1609587929392839161ULL;
735d240522SNick Terrell static const uint64_t PRIME64_4 =  9650029242287828579ULL;
745d240522SNick Terrell static const uint64_t PRIME64_5 =  2870177450012600261ULL;
755d240522SNick Terrell 
765d240522SNick Terrell /*-**************************
775d240522SNick Terrell  *  Utils
785d240522SNick Terrell  ***************************/
xxh32_copy_state(struct xxh32_state * dst,const struct xxh32_state * src)795d240522SNick Terrell void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
805d240522SNick Terrell {
815d240522SNick Terrell 	memcpy(dst, src, sizeof(*dst));
825d240522SNick Terrell }
835d240522SNick Terrell EXPORT_SYMBOL(xxh32_copy_state);
845d240522SNick Terrell 
xxh64_copy_state(struct xxh64_state * dst,const struct xxh64_state * src)855d240522SNick Terrell void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
865d240522SNick Terrell {
875d240522SNick Terrell 	memcpy(dst, src, sizeof(*dst));
885d240522SNick Terrell }
895d240522SNick Terrell EXPORT_SYMBOL(xxh64_copy_state);
905d240522SNick Terrell 
915d240522SNick Terrell /*-***************************
925d240522SNick Terrell  * Simple Hash Functions
935d240522SNick Terrell  ****************************/
xxh32_round(uint32_t seed,const uint32_t input)945d240522SNick Terrell static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
955d240522SNick Terrell {
965d240522SNick Terrell 	seed += input * PRIME32_2;
975d240522SNick Terrell 	seed = xxh_rotl32(seed, 13);
985d240522SNick Terrell 	seed *= PRIME32_1;
995d240522SNick Terrell 	return seed;
1005d240522SNick Terrell }
1015d240522SNick Terrell 
xxh32(const void * input,const size_t len,const uint32_t seed)1025d240522SNick Terrell uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
1035d240522SNick Terrell {
1045d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
1055d240522SNick Terrell 	const uint8_t *b_end = p + len;
1065d240522SNick Terrell 	uint32_t h32;
1075d240522SNick Terrell 
1085d240522SNick Terrell 	if (len >= 16) {
1095d240522SNick Terrell 		const uint8_t *const limit = b_end - 16;
1105d240522SNick Terrell 		uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
1115d240522SNick Terrell 		uint32_t v2 = seed + PRIME32_2;
1125d240522SNick Terrell 		uint32_t v3 = seed + 0;
1135d240522SNick Terrell 		uint32_t v4 = seed - PRIME32_1;
1145d240522SNick Terrell 
1155d240522SNick Terrell 		do {
1165d240522SNick Terrell 			v1 = xxh32_round(v1, get_unaligned_le32(p));
1175d240522SNick Terrell 			p += 4;
1185d240522SNick Terrell 			v2 = xxh32_round(v2, get_unaligned_le32(p));
1195d240522SNick Terrell 			p += 4;
1205d240522SNick Terrell 			v3 = xxh32_round(v3, get_unaligned_le32(p));
1215d240522SNick Terrell 			p += 4;
1225d240522SNick Terrell 			v4 = xxh32_round(v4, get_unaligned_le32(p));
1235d240522SNick Terrell 			p += 4;
1245d240522SNick Terrell 		} while (p <= limit);
1255d240522SNick Terrell 
1265d240522SNick Terrell 		h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
1275d240522SNick Terrell 			xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
1285d240522SNick Terrell 	} else {
1295d240522SNick Terrell 		h32 = seed + PRIME32_5;
1305d240522SNick Terrell 	}
1315d240522SNick Terrell 
1325d240522SNick Terrell 	h32 += (uint32_t)len;
1335d240522SNick Terrell 
1345d240522SNick Terrell 	while (p + 4 <= b_end) {
1355d240522SNick Terrell 		h32 += get_unaligned_le32(p) * PRIME32_3;
1365d240522SNick Terrell 		h32 = xxh_rotl32(h32, 17) * PRIME32_4;
1375d240522SNick Terrell 		p += 4;
1385d240522SNick Terrell 	}
1395d240522SNick Terrell 
1405d240522SNick Terrell 	while (p < b_end) {
1415d240522SNick Terrell 		h32 += (*p) * PRIME32_5;
1425d240522SNick Terrell 		h32 = xxh_rotl32(h32, 11) * PRIME32_1;
1435d240522SNick Terrell 		p++;
1445d240522SNick Terrell 	}
1455d240522SNick Terrell 
1465d240522SNick Terrell 	h32 ^= h32 >> 15;
1475d240522SNick Terrell 	h32 *= PRIME32_2;
1485d240522SNick Terrell 	h32 ^= h32 >> 13;
1495d240522SNick Terrell 	h32 *= PRIME32_3;
1505d240522SNick Terrell 	h32 ^= h32 >> 16;
1515d240522SNick Terrell 
1525d240522SNick Terrell 	return h32;
1535d240522SNick Terrell }
1545d240522SNick Terrell EXPORT_SYMBOL(xxh32);
1555d240522SNick Terrell 
xxh64_round(uint64_t acc,const uint64_t input)1565d240522SNick Terrell static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
1575d240522SNick Terrell {
1585d240522SNick Terrell 	acc += input * PRIME64_2;
1595d240522SNick Terrell 	acc = xxh_rotl64(acc, 31);
1605d240522SNick Terrell 	acc *= PRIME64_1;
1615d240522SNick Terrell 	return acc;
1625d240522SNick Terrell }
1635d240522SNick Terrell 
xxh64_merge_round(uint64_t acc,uint64_t val)1645d240522SNick Terrell static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
1655d240522SNick Terrell {
1665d240522SNick Terrell 	val = xxh64_round(0, val);
1675d240522SNick Terrell 	acc ^= val;
1685d240522SNick Terrell 	acc = acc * PRIME64_1 + PRIME64_4;
1695d240522SNick Terrell 	return acc;
1705d240522SNick Terrell }
1715d240522SNick Terrell 
xxh64(const void * input,const size_t len,const uint64_t seed)1725d240522SNick Terrell uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
1735d240522SNick Terrell {
1745d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
1755d240522SNick Terrell 	const uint8_t *const b_end = p + len;
1765d240522SNick Terrell 	uint64_t h64;
1775d240522SNick Terrell 
1785d240522SNick Terrell 	if (len >= 32) {
1795d240522SNick Terrell 		const uint8_t *const limit = b_end - 32;
1805d240522SNick Terrell 		uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
1815d240522SNick Terrell 		uint64_t v2 = seed + PRIME64_2;
1825d240522SNick Terrell 		uint64_t v3 = seed + 0;
1835d240522SNick Terrell 		uint64_t v4 = seed - PRIME64_1;
1845d240522SNick Terrell 
1855d240522SNick Terrell 		do {
1865d240522SNick Terrell 			v1 = xxh64_round(v1, get_unaligned_le64(p));
1875d240522SNick Terrell 			p += 8;
1885d240522SNick Terrell 			v2 = xxh64_round(v2, get_unaligned_le64(p));
1895d240522SNick Terrell 			p += 8;
1905d240522SNick Terrell 			v3 = xxh64_round(v3, get_unaligned_le64(p));
1915d240522SNick Terrell 			p += 8;
1925d240522SNick Terrell 			v4 = xxh64_round(v4, get_unaligned_le64(p));
1935d240522SNick Terrell 			p += 8;
1945d240522SNick Terrell 		} while (p <= limit);
1955d240522SNick Terrell 
1965d240522SNick Terrell 		h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
1975d240522SNick Terrell 			xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
1985d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v1);
1995d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v2);
2005d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v3);
2015d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v4);
2025d240522SNick Terrell 
2035d240522SNick Terrell 	} else {
2045d240522SNick Terrell 		h64  = seed + PRIME64_5;
2055d240522SNick Terrell 	}
2065d240522SNick Terrell 
2075d240522SNick Terrell 	h64 += (uint64_t)len;
2085d240522SNick Terrell 
2095d240522SNick Terrell 	while (p + 8 <= b_end) {
2105d240522SNick Terrell 		const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
2115d240522SNick Terrell 
2125d240522SNick Terrell 		h64 ^= k1;
2135d240522SNick Terrell 		h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
2145d240522SNick Terrell 		p += 8;
2155d240522SNick Terrell 	}
2165d240522SNick Terrell 
2175d240522SNick Terrell 	if (p + 4 <= b_end) {
2185d240522SNick Terrell 		h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
2195d240522SNick Terrell 		h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
2205d240522SNick Terrell 		p += 4;
2215d240522SNick Terrell 	}
2225d240522SNick Terrell 
2235d240522SNick Terrell 	while (p < b_end) {
2245d240522SNick Terrell 		h64 ^= (*p) * PRIME64_5;
2255d240522SNick Terrell 		h64 = xxh_rotl64(h64, 11) * PRIME64_1;
2265d240522SNick Terrell 		p++;
2275d240522SNick Terrell 	}
2285d240522SNick Terrell 
2295d240522SNick Terrell 	h64 ^= h64 >> 33;
2305d240522SNick Terrell 	h64 *= PRIME64_2;
2315d240522SNick Terrell 	h64 ^= h64 >> 29;
2325d240522SNick Terrell 	h64 *= PRIME64_3;
2335d240522SNick Terrell 	h64 ^= h64 >> 32;
2345d240522SNick Terrell 
2355d240522SNick Terrell 	return h64;
2365d240522SNick Terrell }
2375d240522SNick Terrell EXPORT_SYMBOL(xxh64);
2385d240522SNick Terrell 
2395d240522SNick Terrell /*-**************************************************
2405d240522SNick Terrell  * Advanced Hash Functions
2415d240522SNick Terrell  ***************************************************/
xxh32_reset(struct xxh32_state * statePtr,const uint32_t seed)2425d240522SNick Terrell void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
2435d240522SNick Terrell {
2445d240522SNick Terrell 	/* use a local state for memcpy() to avoid strict-aliasing warnings */
2455d240522SNick Terrell 	struct xxh32_state state;
2465d240522SNick Terrell 
2475d240522SNick Terrell 	memset(&state, 0, sizeof(state));
2485d240522SNick Terrell 	state.v1 = seed + PRIME32_1 + PRIME32_2;
2495d240522SNick Terrell 	state.v2 = seed + PRIME32_2;
2505d240522SNick Terrell 	state.v3 = seed + 0;
2515d240522SNick Terrell 	state.v4 = seed - PRIME32_1;
2525d240522SNick Terrell 	memcpy(statePtr, &state, sizeof(state));
2535d240522SNick Terrell }
2545d240522SNick Terrell EXPORT_SYMBOL(xxh32_reset);
2555d240522SNick Terrell 
xxh64_reset(struct xxh64_state * statePtr,const uint64_t seed)2565d240522SNick Terrell void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
2575d240522SNick Terrell {
2585d240522SNick Terrell 	/* use a local state for memcpy() to avoid strict-aliasing warnings */
2595d240522SNick Terrell 	struct xxh64_state state;
2605d240522SNick Terrell 
2615d240522SNick Terrell 	memset(&state, 0, sizeof(state));
2625d240522SNick Terrell 	state.v1 = seed + PRIME64_1 + PRIME64_2;
2635d240522SNick Terrell 	state.v2 = seed + PRIME64_2;
2645d240522SNick Terrell 	state.v3 = seed + 0;
2655d240522SNick Terrell 	state.v4 = seed - PRIME64_1;
2665d240522SNick Terrell 	memcpy(statePtr, &state, sizeof(state));
2675d240522SNick Terrell }
2685d240522SNick Terrell EXPORT_SYMBOL(xxh64_reset);
2695d240522SNick Terrell 
xxh32_update(struct xxh32_state * state,const void * input,const size_t len)2705d240522SNick Terrell int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
2715d240522SNick Terrell {
2725d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
2735d240522SNick Terrell 	const uint8_t *const b_end = p + len;
2745d240522SNick Terrell 
2755d240522SNick Terrell 	if (input == NULL)
2765d240522SNick Terrell 		return -EINVAL;
2775d240522SNick Terrell 
2785d240522SNick Terrell 	state->total_len_32 += (uint32_t)len;
2795d240522SNick Terrell 	state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
2805d240522SNick Terrell 
2815d240522SNick Terrell 	if (state->memsize + len < 16) { /* fill in tmp buffer */
2825d240522SNick Terrell 		memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
2835d240522SNick Terrell 		state->memsize += (uint32_t)len;
2845d240522SNick Terrell 		return 0;
2855d240522SNick Terrell 	}
2865d240522SNick Terrell 
2875d240522SNick Terrell 	if (state->memsize) { /* some data left from previous update */
2885d240522SNick Terrell 		const uint32_t *p32 = state->mem32;
2895d240522SNick Terrell 
2905d240522SNick Terrell 		memcpy((uint8_t *)(state->mem32) + state->memsize, input,
2915d240522SNick Terrell 			16 - state->memsize);
2925d240522SNick Terrell 
2935d240522SNick Terrell 		state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
2945d240522SNick Terrell 		p32++;
2955d240522SNick Terrell 		state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
2965d240522SNick Terrell 		p32++;
2975d240522SNick Terrell 		state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
2985d240522SNick Terrell 		p32++;
2995d240522SNick Terrell 		state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
3005d240522SNick Terrell 		p32++;
3015d240522SNick Terrell 
3025d240522SNick Terrell 		p += 16-state->memsize;
3035d240522SNick Terrell 		state->memsize = 0;
3045d240522SNick Terrell 	}
3055d240522SNick Terrell 
3065d240522SNick Terrell 	if (p <= b_end - 16) {
3075d240522SNick Terrell 		const uint8_t *const limit = b_end - 16;
3085d240522SNick Terrell 		uint32_t v1 = state->v1;
3095d240522SNick Terrell 		uint32_t v2 = state->v2;
3105d240522SNick Terrell 		uint32_t v3 = state->v3;
3115d240522SNick Terrell 		uint32_t v4 = state->v4;
3125d240522SNick Terrell 
3135d240522SNick Terrell 		do {
3145d240522SNick Terrell 			v1 = xxh32_round(v1, get_unaligned_le32(p));
3155d240522SNick Terrell 			p += 4;
3165d240522SNick Terrell 			v2 = xxh32_round(v2, get_unaligned_le32(p));
3175d240522SNick Terrell 			p += 4;
3185d240522SNick Terrell 			v3 = xxh32_round(v3, get_unaligned_le32(p));
3195d240522SNick Terrell 			p += 4;
3205d240522SNick Terrell 			v4 = xxh32_round(v4, get_unaligned_le32(p));
3215d240522SNick Terrell 			p += 4;
3225d240522SNick Terrell 		} while (p <= limit);
3235d240522SNick Terrell 
3245d240522SNick Terrell 		state->v1 = v1;
3255d240522SNick Terrell 		state->v2 = v2;
3265d240522SNick Terrell 		state->v3 = v3;
3275d240522SNick Terrell 		state->v4 = v4;
3285d240522SNick Terrell 	}
3295d240522SNick Terrell 
3305d240522SNick Terrell 	if (p < b_end) {
3315d240522SNick Terrell 		memcpy(state->mem32, p, (size_t)(b_end-p));
3325d240522SNick Terrell 		state->memsize = (uint32_t)(b_end-p);
3335d240522SNick Terrell 	}
3345d240522SNick Terrell 
3355d240522SNick Terrell 	return 0;
3365d240522SNick Terrell }
3375d240522SNick Terrell EXPORT_SYMBOL(xxh32_update);
3385d240522SNick Terrell 
xxh32_digest(const struct xxh32_state * state)3395d240522SNick Terrell uint32_t xxh32_digest(const struct xxh32_state *state)
3405d240522SNick Terrell {
3415d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)state->mem32;
3425d240522SNick Terrell 	const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
3435d240522SNick Terrell 		state->memsize;
3445d240522SNick Terrell 	uint32_t h32;
3455d240522SNick Terrell 
3465d240522SNick Terrell 	if (state->large_len) {
3475d240522SNick Terrell 		h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
3485d240522SNick Terrell 			xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
3495d240522SNick Terrell 	} else {
3505d240522SNick Terrell 		h32 = state->v3 /* == seed */ + PRIME32_5;
3515d240522SNick Terrell 	}
3525d240522SNick Terrell 
3535d240522SNick Terrell 	h32 += state->total_len_32;
3545d240522SNick Terrell 
3555d240522SNick Terrell 	while (p + 4 <= b_end) {
3565d240522SNick Terrell 		h32 += get_unaligned_le32(p) * PRIME32_3;
3575d240522SNick Terrell 		h32 = xxh_rotl32(h32, 17) * PRIME32_4;
3585d240522SNick Terrell 		p += 4;
3595d240522SNick Terrell 	}
3605d240522SNick Terrell 
3615d240522SNick Terrell 	while (p < b_end) {
3625d240522SNick Terrell 		h32 += (*p) * PRIME32_5;
3635d240522SNick Terrell 		h32 = xxh_rotl32(h32, 11) * PRIME32_1;
3645d240522SNick Terrell 		p++;
3655d240522SNick Terrell 	}
3665d240522SNick Terrell 
3675d240522SNick Terrell 	h32 ^= h32 >> 15;
3685d240522SNick Terrell 	h32 *= PRIME32_2;
3695d240522SNick Terrell 	h32 ^= h32 >> 13;
3705d240522SNick Terrell 	h32 *= PRIME32_3;
3715d240522SNick Terrell 	h32 ^= h32 >> 16;
3725d240522SNick Terrell 
3735d240522SNick Terrell 	return h32;
3745d240522SNick Terrell }
3755d240522SNick Terrell EXPORT_SYMBOL(xxh32_digest);
3765d240522SNick Terrell 
xxh64_update(struct xxh64_state * state,const void * input,const size_t len)3775d240522SNick Terrell int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
3785d240522SNick Terrell {
3795d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)input;
3805d240522SNick Terrell 	const uint8_t *const b_end = p + len;
3815d240522SNick Terrell 
3825d240522SNick Terrell 	if (input == NULL)
3835d240522SNick Terrell 		return -EINVAL;
3845d240522SNick Terrell 
3855d240522SNick Terrell 	state->total_len += len;
3865d240522SNick Terrell 
3875d240522SNick Terrell 	if (state->memsize + len < 32) { /* fill in tmp buffer */
3885d240522SNick Terrell 		memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
3895d240522SNick Terrell 		state->memsize += (uint32_t)len;
3905d240522SNick Terrell 		return 0;
3915d240522SNick Terrell 	}
3925d240522SNick Terrell 
3935d240522SNick Terrell 	if (state->memsize) { /* tmp buffer is full */
3945d240522SNick Terrell 		uint64_t *p64 = state->mem64;
3955d240522SNick Terrell 
3965d240522SNick Terrell 		memcpy(((uint8_t *)p64) + state->memsize, input,
3975d240522SNick Terrell 			32 - state->memsize);
3985d240522SNick Terrell 
3995d240522SNick Terrell 		state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
4005d240522SNick Terrell 		p64++;
4015d240522SNick Terrell 		state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
4025d240522SNick Terrell 		p64++;
4035d240522SNick Terrell 		state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
4045d240522SNick Terrell 		p64++;
4055d240522SNick Terrell 		state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
4065d240522SNick Terrell 
4075d240522SNick Terrell 		p += 32 - state->memsize;
4085d240522SNick Terrell 		state->memsize = 0;
4095d240522SNick Terrell 	}
4105d240522SNick Terrell 
4115d240522SNick Terrell 	if (p + 32 <= b_end) {
4125d240522SNick Terrell 		const uint8_t *const limit = b_end - 32;
4135d240522SNick Terrell 		uint64_t v1 = state->v1;
4145d240522SNick Terrell 		uint64_t v2 = state->v2;
4155d240522SNick Terrell 		uint64_t v3 = state->v3;
4165d240522SNick Terrell 		uint64_t v4 = state->v4;
4175d240522SNick Terrell 
4185d240522SNick Terrell 		do {
4195d240522SNick Terrell 			v1 = xxh64_round(v1, get_unaligned_le64(p));
4205d240522SNick Terrell 			p += 8;
4215d240522SNick Terrell 			v2 = xxh64_round(v2, get_unaligned_le64(p));
4225d240522SNick Terrell 			p += 8;
4235d240522SNick Terrell 			v3 = xxh64_round(v3, get_unaligned_le64(p));
4245d240522SNick Terrell 			p += 8;
4255d240522SNick Terrell 			v4 = xxh64_round(v4, get_unaligned_le64(p));
4265d240522SNick Terrell 			p += 8;
4275d240522SNick Terrell 		} while (p <= limit);
4285d240522SNick Terrell 
4295d240522SNick Terrell 		state->v1 = v1;
4305d240522SNick Terrell 		state->v2 = v2;
4315d240522SNick Terrell 		state->v3 = v3;
4325d240522SNick Terrell 		state->v4 = v4;
4335d240522SNick Terrell 	}
4345d240522SNick Terrell 
4355d240522SNick Terrell 	if (p < b_end) {
4365d240522SNick Terrell 		memcpy(state->mem64, p, (size_t)(b_end-p));
4375d240522SNick Terrell 		state->memsize = (uint32_t)(b_end - p);
4385d240522SNick Terrell 	}
4395d240522SNick Terrell 
4405d240522SNick Terrell 	return 0;
4415d240522SNick Terrell }
4425d240522SNick Terrell EXPORT_SYMBOL(xxh64_update);
4435d240522SNick Terrell 
xxh64_digest(const struct xxh64_state * state)4445d240522SNick Terrell uint64_t xxh64_digest(const struct xxh64_state *state)
4455d240522SNick Terrell {
4465d240522SNick Terrell 	const uint8_t *p = (const uint8_t *)state->mem64;
4475d240522SNick Terrell 	const uint8_t *const b_end = (const uint8_t *)state->mem64 +
4485d240522SNick Terrell 		state->memsize;
4495d240522SNick Terrell 	uint64_t h64;
4505d240522SNick Terrell 
4515d240522SNick Terrell 	if (state->total_len >= 32) {
4525d240522SNick Terrell 		const uint64_t v1 = state->v1;
4535d240522SNick Terrell 		const uint64_t v2 = state->v2;
4545d240522SNick Terrell 		const uint64_t v3 = state->v3;
4555d240522SNick Terrell 		const uint64_t v4 = state->v4;
4565d240522SNick Terrell 
4575d240522SNick Terrell 		h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
4585d240522SNick Terrell 			xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
4595d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v1);
4605d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v2);
4615d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v3);
4625d240522SNick Terrell 		h64 = xxh64_merge_round(h64, v4);
4635d240522SNick Terrell 	} else {
4645d240522SNick Terrell 		h64  = state->v3 + PRIME64_5;
4655d240522SNick Terrell 	}
4665d240522SNick Terrell 
4675d240522SNick Terrell 	h64 += (uint64_t)state->total_len;
4685d240522SNick Terrell 
4695d240522SNick Terrell 	while (p + 8 <= b_end) {
4705d240522SNick Terrell 		const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
4715d240522SNick Terrell 
4725d240522SNick Terrell 		h64 ^= k1;
4735d240522SNick Terrell 		h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
4745d240522SNick Terrell 		p += 8;
4755d240522SNick Terrell 	}
4765d240522SNick Terrell 
4775d240522SNick Terrell 	if (p + 4 <= b_end) {
4785d240522SNick Terrell 		h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
4795d240522SNick Terrell 		h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
4805d240522SNick Terrell 		p += 4;
4815d240522SNick Terrell 	}
4825d240522SNick Terrell 
4835d240522SNick Terrell 	while (p < b_end) {
4845d240522SNick Terrell 		h64 ^= (*p) * PRIME64_5;
4855d240522SNick Terrell 		h64 = xxh_rotl64(h64, 11) * PRIME64_1;
4865d240522SNick Terrell 		p++;
4875d240522SNick Terrell 	}
4885d240522SNick Terrell 
4895d240522SNick Terrell 	h64 ^= h64 >> 33;
4905d240522SNick Terrell 	h64 *= PRIME64_2;
4915d240522SNick Terrell 	h64 ^= h64 >> 29;
4925d240522SNick Terrell 	h64 *= PRIME64_3;
4935d240522SNick Terrell 	h64 ^= h64 >> 32;
4945d240522SNick Terrell 
4955d240522SNick Terrell 	return h64;
4965d240522SNick Terrell }
4975d240522SNick Terrell EXPORT_SYMBOL(xxh64_digest);
4985d240522SNick Terrell 
4995d240522SNick Terrell MODULE_LICENSE("Dual BSD/GPL");
5005d240522SNick Terrell MODULE_DESCRIPTION("xxHash");
501