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