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: 37*d89775fcSAlexander 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 ***************************/ 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 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 ****************************/ 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 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 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 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 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 ***************************************************/ 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 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 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 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 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 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