LCOV - code coverage report
Current view: top level - Python - pyhash.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 83 86 96.5 %
Date: 2022-07-20 13:12:14 Functions: 9 9 100.0 %
Branches: 29 32 90.6 %

           Branch data     Line data    Source code
       1                 :            : /* Set of hash utility functions to help maintaining the invariant that
       2                 :            :     if a==b then hash(a)==hash(b)
       3                 :            : 
       4                 :            :    All the utility functions (_Py_Hash*()) return "-1" to signify an error.
       5                 :            : */
       6                 :            : #include "Python.h"
       7                 :            : 
       8                 :            : #ifdef __APPLE__
       9                 :            : #  include <libkern/OSByteOrder.h>
      10                 :            : #elif defined(HAVE_LE64TOH) && defined(HAVE_ENDIAN_H)
      11                 :            : #  include <endian.h>
      12                 :            : #elif defined(HAVE_LE64TOH) && defined(HAVE_SYS_ENDIAN_H)
      13                 :            : #  include <sys/endian.h>
      14                 :            : #endif
      15                 :            : 
      16                 :            : #ifdef __cplusplus
      17                 :            : extern "C" {
      18                 :            : #endif
      19                 :            : 
      20                 :            : _Py_HashSecret_t _Py_HashSecret = {{0}};
      21                 :            : 
      22                 :            : #if Py_HASH_ALGORITHM == Py_HASH_EXTERNAL
      23                 :            : extern PyHash_FuncDef PyHash_Func;
      24                 :            : #else
      25                 :            : static PyHash_FuncDef PyHash_Func;
      26                 :            : #endif
      27                 :            : 
      28                 :            : /* Count _Py_HashBytes() calls */
      29                 :            : #ifdef Py_HASH_STATS
      30                 :            : #define Py_HASH_STATS_MAX 32
      31                 :            : static Py_ssize_t hashstats[Py_HASH_STATS_MAX + 1] = {0};
      32                 :            : #endif
      33                 :            : 
      34                 :            : /* For numeric types, the hash of a number x is based on the reduction
      35                 :            :    of x modulo the prime P = 2**_PyHASH_BITS - 1.  It's designed so that
      36                 :            :    hash(x) == hash(y) whenever x and y are numerically equal, even if
      37                 :            :    x and y have different types.
      38                 :            : 
      39                 :            :    A quick summary of the hashing strategy:
      40                 :            : 
      41                 :            :    (1) First define the 'reduction of x modulo P' for any rational
      42                 :            :    number x; this is a standard extension of the usual notion of
      43                 :            :    reduction modulo P for integers.  If x == p/q (written in lowest
      44                 :            :    terms), the reduction is interpreted as the reduction of p times
      45                 :            :    the inverse of the reduction of q, all modulo P; if q is exactly
      46                 :            :    divisible by P then define the reduction to be infinity.  So we've
      47                 :            :    got a well-defined map
      48                 :            : 
      49                 :            :       reduce : { rational numbers } -> { 0, 1, 2, ..., P-1, infinity }.
      50                 :            : 
      51                 :            :    (2) Now for a rational number x, define hash(x) by:
      52                 :            : 
      53                 :            :       reduce(x)   if x >= 0
      54                 :            :       -reduce(-x) if x < 0
      55                 :            : 
      56                 :            :    If the result of the reduction is infinity (this is impossible for
      57                 :            :    integers, floats and Decimals) then use the predefined hash value
      58                 :            :    _PyHASH_INF for x >= 0, or -_PyHASH_INF for x < 0, instead.
      59                 :            :    _PyHASH_INF and -_PyHASH_INF are also used for the
      60                 :            :    hashes of float and Decimal infinities.
      61                 :            : 
      62                 :            :    NaNs hash with a pointer hash.  Having distinct hash values prevents
      63                 :            :    catastrophic pileups from distinct NaN instances which used to always
      64                 :            :    have the same hash value but would compare unequal.
      65                 :            : 
      66                 :            :    A selling point for the above strategy is that it makes it possible
      67                 :            :    to compute hashes of decimal and binary floating-point numbers
      68                 :            :    efficiently, even if the exponent of the binary or decimal number
      69                 :            :    is large.  The key point is that
      70                 :            : 
      71                 :            :       reduce(x * y) == reduce(x) * reduce(y) (modulo _PyHASH_MODULUS)
      72                 :            : 
      73                 :            :    provided that {reduce(x), reduce(y)} != {0, infinity}.  The reduction of a
      74                 :            :    binary or decimal float is never infinity, since the denominator is a power
      75                 :            :    of 2 (for binary) or a divisor of a power of 10 (for decimal).  So we have,
      76                 :            :    for nonnegative x,
      77                 :            : 
      78                 :            :       reduce(x * 2**e) == reduce(x) * reduce(2**e) % _PyHASH_MODULUS
      79                 :            : 
      80                 :            :       reduce(x * 10**e) == reduce(x) * reduce(10**e) % _PyHASH_MODULUS
      81                 :            : 
      82                 :            :    and reduce(10**e) can be computed efficiently by the usual modular
      83                 :            :    exponentiation algorithm.  For reduce(2**e) it's even better: since
      84                 :            :    P is of the form 2**n-1, reduce(2**e) is 2**(e mod n), and multiplication
      85                 :            :    by 2**(e mod n) modulo 2**n-1 just amounts to a rotation of bits.
      86                 :            : 
      87                 :            :    */
      88                 :            : 
      89                 :            : Py_hash_t _Py_HashPointer(const void *);
      90                 :            : 
      91                 :            : Py_hash_t
      92                 :     202188 : _Py_HashDouble(PyObject *inst, double v)
      93                 :            : {
      94                 :            :     int e, sign;
      95                 :            :     double m;
      96                 :            :     Py_uhash_t x, y;
      97                 :            : 
      98         [ +  + ]:     202188 :     if (!Py_IS_FINITE(v)) {
      99         [ +  + ]:        306 :         if (Py_IS_INFINITY(v))
     100         [ +  + ]:        215 :             return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
     101                 :            :         else
     102                 :         91 :             return _Py_HashPointer(inst);
     103                 :            :     }
     104                 :            : 
     105                 :     201882 :     m = frexp(v, &e);
     106                 :            : 
     107                 :     201882 :     sign = 1;
     108         [ +  + ]:     201882 :     if (m < 0) {
     109                 :      22015 :         sign = -1;
     110                 :      22015 :         m = -m;
     111                 :            :     }
     112                 :            : 
     113                 :            :     /* process 28 bits at a time;  this should work well both for binary
     114                 :            :        and hexadecimal floating point. */
     115                 :     201882 :     x = 0;
     116         [ +  + ]:     469423 :     while (m) {
     117                 :     267541 :         x = ((x << 28) & _PyHASH_MODULUS) | x >> (_PyHASH_BITS - 28);
     118                 :     267541 :         m *= 268435456.0;  /* 2**28 */
     119                 :     267541 :         e -= 28;
     120                 :     267541 :         y = (Py_uhash_t)m;  /* pull out integer part */
     121                 :     267541 :         m -= y;
     122                 :     267541 :         x += y;
     123         [ -  + ]:     267541 :         if (x >= _PyHASH_MODULUS)
     124                 :          0 :             x -= _PyHASH_MODULUS;
     125                 :            :     }
     126                 :            : 
     127                 :            :     /* adjust for the exponent;  first reduce it modulo _PyHASH_BITS */
     128         [ +  + ]:     201882 :     e = e >= 0 ? e % _PyHASH_BITS : _PyHASH_BITS-1-((-1-e) % _PyHASH_BITS);
     129                 :     201882 :     x = ((x << e) & _PyHASH_MODULUS) | x >> (_PyHASH_BITS - e);
     130                 :            : 
     131                 :     201882 :     x = x * sign;
     132         [ +  + ]:     201882 :     if (x == (Py_uhash_t)-1)
     133                 :       1663 :         x = (Py_uhash_t)-2;
     134                 :     201882 :     return (Py_hash_t)x;
     135                 :            : }
     136                 :            : 
     137                 :            : Py_hash_t
     138                 :   34468015 : _Py_HashPointerRaw(const void *p)
     139                 :            : {
     140                 :   34468015 :     size_t y = (size_t)p;
     141                 :            :     /* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
     142                 :            :        excessive hash collisions for dicts and sets */
     143                 :   34468015 :     y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4));
     144                 :   34468015 :     return (Py_hash_t)y;
     145                 :            : }
     146                 :            : 
     147                 :            : Py_hash_t
     148                 :   23821640 : _Py_HashPointer(const void *p)
     149                 :            : {
     150                 :   23821640 :     Py_hash_t x = _Py_HashPointerRaw(p);
     151         [ -  + ]:   23821640 :     if (x == -1) {
     152                 :          0 :         x = -2;
     153                 :            :     }
     154                 :   23821640 :     return x;
     155                 :            : }
     156                 :            : 
     157                 :            : Py_hash_t
     158                 :  113439656 : _Py_HashBytes(const void *src, Py_ssize_t len)
     159                 :            : {
     160                 :            :     Py_hash_t x;
     161                 :            :     /*
     162                 :            :       We make the hash of the empty string be 0, rather than using
     163                 :            :       (prefix ^ suffix), since this slightly obfuscates the hash secret
     164                 :            :     */
     165         [ +  + ]:  113439656 :     if (len == 0) {
     166                 :       5830 :         return 0;
     167                 :            :     }
     168                 :            : 
     169                 :            : #ifdef Py_HASH_STATS
     170                 :            :     hashstats[(len <= Py_HASH_STATS_MAX) ? len : 0]++;
     171                 :            : #endif
     172                 :            : 
     173                 :            : #if Py_HASH_CUTOFF > 0
     174                 :            :     if (len < Py_HASH_CUTOFF) {
     175                 :            :         /* Optimize hashing of very small strings with inline DJBX33A. */
     176                 :            :         Py_uhash_t hash;
     177                 :            :         const unsigned char *p = src;
     178                 :            :         hash = 5381; /* DJBX33A starts with 5381 */
     179                 :            : 
     180                 :            :         switch(len) {
     181                 :            :             /* ((hash << 5) + hash) + *p == hash * 33 + *p */
     182                 :            :             case 7: hash = ((hash << 5) + hash) + *p++; /* fallthrough */
     183                 :            :             case 6: hash = ((hash << 5) + hash) + *p++; /* fallthrough */
     184                 :            :             case 5: hash = ((hash << 5) + hash) + *p++; /* fallthrough */
     185                 :            :             case 4: hash = ((hash << 5) + hash) + *p++; /* fallthrough */
     186                 :            :             case 3: hash = ((hash << 5) + hash) + *p++; /* fallthrough */
     187                 :            :             case 2: hash = ((hash << 5) + hash) + *p++; /* fallthrough */
     188                 :            :             case 1: hash = ((hash << 5) + hash) + *p++; break;
     189                 :            :             default:
     190                 :            :                 Py_UNREACHABLE();
     191                 :            :         }
     192                 :            :         hash ^= len;
     193                 :            :         hash ^= (Py_uhash_t) _Py_HashSecret.djbx33a.suffix;
     194                 :            :         x = (Py_hash_t)hash;
     195                 :            :     }
     196                 :            :     else
     197                 :            : #endif /* Py_HASH_CUTOFF */
     198                 :  113433826 :         x = PyHash_Func.hash(src, len);
     199                 :            : 
     200         [ -  + ]:  113433826 :     if (x == -1)
     201                 :          0 :         return -2;
     202                 :  113433826 :     return x;
     203                 :            : }
     204                 :            : 
     205                 :            : void
     206                 :       2957 : _PyHash_Fini(void)
     207                 :            : {
     208                 :            : #ifdef Py_HASH_STATS
     209                 :            :     fprintf(stderr, "len   calls    total\n");
     210                 :            :     Py_ssize_t total = 0;
     211                 :            :     for (int i = 1; i <= Py_HASH_STATS_MAX; i++) {
     212                 :            :         total += hashstats[i];
     213                 :            :         fprintf(stderr, "%2i %8zd %8zd\n", i, hashstats[i], total);
     214                 :            :     }
     215                 :            :     total += hashstats[0];
     216                 :            :     fprintf(stderr, ">  %8zd %8zd\n", hashstats[0], total);
     217                 :            : #endif
     218                 :       2957 : }
     219                 :            : 
     220                 :            : PyHash_FuncDef *
     221                 :       3138 : PyHash_GetFuncDef(void)
     222                 :            : {
     223                 :       3138 :     return &PyHash_Func;
     224                 :            : }
     225                 :            : 
     226                 :            : /* Optimized memcpy() for Windows */
     227                 :            : #ifdef _MSC_VER
     228                 :            : #  if SIZEOF_PY_UHASH_T == 4
     229                 :            : #    define PY_UHASH_CPY(dst, src) do {                                    \
     230                 :            :        dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; \
     231                 :            :        } while(0)
     232                 :            : #  elif SIZEOF_PY_UHASH_T == 8
     233                 :            : #    define PY_UHASH_CPY(dst, src) do {                                    \
     234                 :            :        dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; \
     235                 :            :        dst[4] = src[4]; dst[5] = src[5]; dst[6] = src[6]; dst[7] = src[7]; \
     236                 :            :        } while(0)
     237                 :            : #  else
     238                 :            : #    error SIZEOF_PY_UHASH_T must be 4 or 8
     239                 :            : #  endif /* SIZEOF_PY_UHASH_T */
     240                 :            : #else /* not Windows */
     241                 :            : #  define PY_UHASH_CPY(dst, src) memcpy(dst, src, SIZEOF_PY_UHASH_T)
     242                 :            : #endif /* _MSC_VER */
     243                 :            : 
     244                 :            : 
     245                 :            : #if Py_HASH_ALGORITHM == Py_HASH_FNV
     246                 :            : /* **************************************************************************
     247                 :            :  * Modified Fowler-Noll-Vo (FNV) hash function
     248                 :            :  */
     249                 :            : static Py_hash_t
     250                 :            : fnv(const void *src, Py_ssize_t len)
     251                 :            : {
     252                 :            :     const unsigned char *p = src;
     253                 :            :     Py_uhash_t x;
     254                 :            :     Py_ssize_t remainder, blocks;
     255                 :            :     union {
     256                 :            :         Py_uhash_t value;
     257                 :            :         unsigned char bytes[SIZEOF_PY_UHASH_T];
     258                 :            :     } block;
     259                 :            : 
     260                 :            : #ifdef Py_DEBUG
     261                 :            :     assert(_Py_HashSecret_Initialized);
     262                 :            : #endif
     263                 :            :     remainder = len % SIZEOF_PY_UHASH_T;
     264                 :            :     if (remainder == 0) {
     265                 :            :         /* Process at least one block byte by byte to reduce hash collisions
     266                 :            :          * for strings with common prefixes. */
     267                 :            :         remainder = SIZEOF_PY_UHASH_T;
     268                 :            :     }
     269                 :            :     blocks = (len - remainder) / SIZEOF_PY_UHASH_T;
     270                 :            : 
     271                 :            :     x = (Py_uhash_t) _Py_HashSecret.fnv.prefix;
     272                 :            :     x ^= (Py_uhash_t) *p << 7;
     273                 :            :     while (blocks--) {
     274                 :            :         PY_UHASH_CPY(block.bytes, p);
     275                 :            :         x = (_PyHASH_MULTIPLIER * x) ^ block.value;
     276                 :            :         p += SIZEOF_PY_UHASH_T;
     277                 :            :     }
     278                 :            :     /* add remainder */
     279                 :            :     for (; remainder > 0; remainder--)
     280                 :            :         x = (_PyHASH_MULTIPLIER * x) ^ (Py_uhash_t) *p++;
     281                 :            :     x ^= (Py_uhash_t) len;
     282                 :            :     x ^= (Py_uhash_t) _Py_HashSecret.fnv.suffix;
     283                 :            :     if (x == (Py_uhash_t) -1) {
     284                 :            :         x = (Py_uhash_t) -2;
     285                 :            :     }
     286                 :            :     return x;
     287                 :            : }
     288                 :            : 
     289                 :            : static PyHash_FuncDef PyHash_Func = {fnv, "fnv", 8 * SIZEOF_PY_HASH_T,
     290                 :            :                                      16 * SIZEOF_PY_HASH_T};
     291                 :            : 
     292                 :            : #endif /* Py_HASH_ALGORITHM == Py_HASH_FNV */
     293                 :            : 
     294                 :            : 
     295                 :            : /* **************************************************************************
     296                 :            :  <MIT License>
     297                 :            :  Copyright (c) 2013  Marek Majkowski <marek@popcount.org>
     298                 :            : 
     299                 :            :  Permission is hereby granted, free of charge, to any person obtaining a copy
     300                 :            :  of this software and associated documentation files (the "Software"), to deal
     301                 :            :  in the Software without restriction, including without limitation the rights
     302                 :            :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     303                 :            :  copies of the Software, and to permit persons to whom the Software is
     304                 :            :  furnished to do so, subject to the following conditions:
     305                 :            : 
     306                 :            :  The above copyright notice and this permission notice shall be included in
     307                 :            :  all copies or substantial portions of the Software.
     308                 :            : 
     309                 :            :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     310                 :            :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     311                 :            :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     312                 :            :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     313                 :            :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     314                 :            :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     315                 :            :  THE SOFTWARE.
     316                 :            :  </MIT License>
     317                 :            : 
     318                 :            :  Original location:
     319                 :            :     https://github.com/majek/csiphash/
     320                 :            : 
     321                 :            :  Solution inspired by code from:
     322                 :            :     Samuel Neves (supercop/crypto_auth/siphash24/little)
     323                 :            :     djb (supercop/crypto_auth/siphash24/little2)
     324                 :            :     Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c)
     325                 :            : 
     326                 :            :  Modified for Python by Christian Heimes:
     327                 :            :     - C89 / MSVC compatibility
     328                 :            :     - _rotl64() on Windows
     329                 :            :     - letoh64() fallback
     330                 :            : */
     331                 :            : 
     332                 :            : /* byte swap little endian to host endian
     333                 :            :  * Endian conversion not only ensures that the hash function returns the same
     334                 :            :  * value on all platforms. It is also required to for a good dispersion of
     335                 :            :  * the hash values' least significant bits.
     336                 :            :  */
     337                 :            : #if PY_LITTLE_ENDIAN
     338                 :            : #  define _le64toh(x) ((uint64_t)(x))
     339                 :            : #elif defined(__APPLE__)
     340                 :            : #  define _le64toh(x) OSSwapLittleToHostInt64(x)
     341                 :            : #elif defined(HAVE_LETOH64)
     342                 :            : #  define _le64toh(x) le64toh(x)
     343                 :            : #else
     344                 :            : #  define _le64toh(x) (((uint64_t)(x) << 56) | \
     345                 :            :                       (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \
     346                 :            :                       (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \
     347                 :            :                       (((uint64_t)(x) << 8)  & 0xff00000000ULL) | \
     348                 :            :                       (((uint64_t)(x) >> 8)  & 0xff000000ULL) | \
     349                 :            :                       (((uint64_t)(x) >> 24) & 0xff0000ULL) | \
     350                 :            :                       (((uint64_t)(x) >> 40) & 0xff00ULL) | \
     351                 :            :                       ((uint64_t)(x)  >> 56))
     352                 :            : #endif
     353                 :            : 
     354                 :            : 
     355                 :            : #ifdef _MSC_VER
     356                 :            : #  define ROTATE(x, b)  _rotl64(x, b)
     357                 :            : #else
     358                 :            : #  define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) )
     359                 :            : #endif
     360                 :            : 
     361                 :            : #define HALF_ROUND(a,b,c,d,s,t)     \
     362                 :            :     a += b; c += d;                 \
     363                 :            :     b = ROTATE(b, s) ^ a;           \
     364                 :            :     d = ROTATE(d, t) ^ c;           \
     365                 :            :     a = ROTATE(a, 32);
     366                 :            : 
     367                 :            : #define SINGLE_ROUND(v0,v1,v2,v3)   \
     368                 :            :     HALF_ROUND(v0,v1,v2,v3,13,16);  \
     369                 :            :     HALF_ROUND(v2,v1,v0,v3,17,21);
     370                 :            : 
     371                 :            : #define DOUBLE_ROUND(v0,v1,v2,v3)   \
     372                 :            :     SINGLE_ROUND(v0,v1,v2,v3);      \
     373                 :            :     SINGLE_ROUND(v0,v1,v2,v3);
     374                 :            : 
     375                 :            : 
     376                 :            : static uint64_t
     377                 :  113434518 : siphash13(uint64_t k0, uint64_t k1, const void *src, Py_ssize_t src_sz) {
     378                 :  113434518 :     uint64_t b = (uint64_t)src_sz << 56;
     379                 :  113434518 :     const uint8_t *in = (const uint8_t*)src;
     380                 :            : 
     381                 :  113434518 :     uint64_t v0 = k0 ^ 0x736f6d6570736575ULL;
     382                 :  113434518 :     uint64_t v1 = k1 ^ 0x646f72616e646f6dULL;
     383                 :  113434518 :     uint64_t v2 = k0 ^ 0x6c7967656e657261ULL;
     384                 :  113434518 :     uint64_t v3 = k1 ^ 0x7465646279746573ULL;
     385                 :            : 
     386                 :            :     uint64_t t;
     387                 :            :     uint8_t *pt;
     388                 :            : 
     389         [ +  + ]:  232828422 :     while (src_sz >= 8) {
     390                 :            :         uint64_t mi;
     391                 :  119393904 :         memcpy(&mi, in, sizeof(mi));
     392                 :  119393904 :         mi = _le64toh(mi);
     393                 :  119393904 :         in += sizeof(mi);
     394                 :  119393904 :         src_sz -= sizeof(mi);
     395                 :  119393904 :         v3 ^= mi;
     396                 :  119393904 :         SINGLE_ROUND(v0,v1,v2,v3);
     397                 :  119393904 :         v0 ^= mi;
     398                 :            :     }
     399                 :            : 
     400                 :  113434518 :     t = 0;
     401                 :  113434518 :     pt = (uint8_t *)&t;
     402   [ +  +  +  +  :  113434518 :     switch (src_sz) {
             +  +  +  + ]
     403                 :   11469871 :         case 7: pt[6] = in[6]; /* fall through */
     404                 :   28342787 :         case 6: pt[5] = in[5]; /* fall through */
     405                 :   40397519 :         case 5: pt[4] = in[4]; /* fall through */
     406                 :   62304090 :         case 4: memcpy(pt, in, sizeof(uint32_t)); break;
     407                 :   15785184 :         case 3: pt[2] = in[2]; /* fall through */
     408                 :   30059673 :         case 2: pt[1] = in[1]; /* fall through */
     409                 :   38235232 :         case 1: pt[0] = in[0]; /* fall through */
     410                 :            :     }
     411                 :  113434518 :     b |= _le64toh(t);
     412                 :            : 
     413                 :  113434518 :     v3 ^= b;
     414                 :  113434518 :     SINGLE_ROUND(v0,v1,v2,v3);
     415                 :  113434518 :     v0 ^= b;
     416                 :  113434518 :     v2 ^= 0xff;
     417                 :  113434518 :     SINGLE_ROUND(v0,v1,v2,v3);
     418                 :  113434518 :     SINGLE_ROUND(v0,v1,v2,v3);
     419                 :  113434518 :     SINGLE_ROUND(v0,v1,v2,v3);
     420                 :            : 
     421                 :            :     /* modified */
     422                 :  113434518 :     t = (v0 ^ v1) ^ (v2 ^ v3);
     423                 :  113434518 :     return t;
     424                 :            : }
     425                 :            : 
     426                 :            : #if Py_HASH_ALGORITHM == Py_HASH_SIPHASH24
     427                 :            : static uint64_t
     428                 :            : siphash24(uint64_t k0, uint64_t k1, const void *src, Py_ssize_t src_sz) {
     429                 :            :     uint64_t b = (uint64_t)src_sz << 56;
     430                 :            :     const uint8_t *in = (const uint8_t*)src;
     431                 :            : 
     432                 :            :     uint64_t v0 = k0 ^ 0x736f6d6570736575ULL;
     433                 :            :     uint64_t v1 = k1 ^ 0x646f72616e646f6dULL;
     434                 :            :     uint64_t v2 = k0 ^ 0x6c7967656e657261ULL;
     435                 :            :     uint64_t v3 = k1 ^ 0x7465646279746573ULL;
     436                 :            : 
     437                 :            :     uint64_t t;
     438                 :            :     uint8_t *pt;
     439                 :            : 
     440                 :            :     while (src_sz >= 8) {
     441                 :            :         uint64_t mi;
     442                 :            :         memcpy(&mi, in, sizeof(mi));
     443                 :            :         mi = _le64toh(mi);
     444                 :            :         in += sizeof(mi);
     445                 :            :         src_sz -= sizeof(mi);
     446                 :            :         v3 ^= mi;
     447                 :            :         DOUBLE_ROUND(v0,v1,v2,v3);
     448                 :            :         v0 ^= mi;
     449                 :            :     }
     450                 :            : 
     451                 :            :     t = 0;
     452                 :            :     pt = (uint8_t *)&t;
     453                 :            :     switch (src_sz) {
     454                 :            :         case 7: pt[6] = in[6]; /* fall through */
     455                 :            :         case 6: pt[5] = in[5]; /* fall through */
     456                 :            :         case 5: pt[4] = in[4]; /* fall through */
     457                 :            :         case 4: memcpy(pt, in, sizeof(uint32_t)); break;
     458                 :            :         case 3: pt[2] = in[2]; /* fall through */
     459                 :            :         case 2: pt[1] = in[1]; /* fall through */
     460                 :            :         case 1: pt[0] = in[0]; /* fall through */
     461                 :            :     }
     462                 :            :     b |= _le64toh(t);
     463                 :            : 
     464                 :            :     v3 ^= b;
     465                 :            :     DOUBLE_ROUND(v0,v1,v2,v3);
     466                 :            :     v0 ^= b;
     467                 :            :     v2 ^= 0xff;
     468                 :            :     DOUBLE_ROUND(v0,v1,v2,v3);
     469                 :            :     DOUBLE_ROUND(v0,v1,v2,v3);
     470                 :            : 
     471                 :            :     /* modified */
     472                 :            :     t = (v0 ^ v1) ^ (v2 ^ v3);
     473                 :            :     return t;
     474                 :            : }
     475                 :            : #endif
     476                 :            : 
     477                 :            : uint64_t
     478                 :        692 : _Py_KeyedHash(uint64_t key, const void *src, Py_ssize_t src_sz)
     479                 :            : {
     480                 :        692 :     return siphash13(key, 0, src, src_sz);
     481                 :            : }
     482                 :            : 
     483                 :            : 
     484                 :            : #if Py_HASH_ALGORITHM == Py_HASH_SIPHASH13
     485                 :            : static Py_hash_t
     486                 :  113433826 : pysiphash(const void *src, Py_ssize_t src_sz) {
     487                 :  113433826 :     return (Py_hash_t)siphash13(
     488                 :  113433826 :         _le64toh(_Py_HashSecret.siphash.k0), _le64toh(_Py_HashSecret.siphash.k1),
     489                 :            :         src, src_sz);
     490                 :            : }
     491                 :            : 
     492                 :            : static PyHash_FuncDef PyHash_Func = {pysiphash, "siphash13", 64, 128};
     493                 :            : #endif
     494                 :            : 
     495                 :            : #if Py_HASH_ALGORITHM == Py_HASH_SIPHASH24
     496                 :            : static Py_hash_t
     497                 :            : pysiphash(const void *src, Py_ssize_t src_sz) {
     498                 :            :     return (Py_hash_t)siphash24(
     499                 :            :         _le64toh(_Py_HashSecret.siphash.k0), _le64toh(_Py_HashSecret.siphash.k1),
     500                 :            :         src, src_sz);
     501                 :            : }
     502                 :            : 
     503                 :            : static PyHash_FuncDef PyHash_Func = {pysiphash, "siphash24", 64, 128};
     504                 :            : #endif
     505                 :            : 
     506                 :            : #ifdef __cplusplus
     507                 :            : }
     508                 :            : #endif

Generated by: LCOV version 1.14