xref: /openbsd-src/gnu/usr.bin/perl/perl_siphash.h (revision 256a93a44f36679bee503f12e49566c2183f6181)
1*256a93a4Safresh1 /* This is SipHash by Jean-Philippe Aumasson and Daniel J. Bernstein.
2*256a93a4Safresh1  * The authors claim it is relatively secure compared to the alternatives
3*256a93a4Safresh1  * and that performance wise it is a suitable hash for languages like Perl.
4*256a93a4Safresh1  * See:
5*256a93a4Safresh1  *
6*256a93a4Safresh1  * https://www.131002.net/siphash/
7*256a93a4Safresh1  *
8*256a93a4Safresh1  * This implementation seems to perform slightly slower than one-at-a-time for
9*256a93a4Safresh1  * short keys, but degrades slower for longer keys. Murmur Hash outperforms it
10*256a93a4Safresh1  * regardless of keys size.
11*256a93a4Safresh1  *
12*256a93a4Safresh1  * It is 64 bit only.
13*256a93a4Safresh1  */
14*256a93a4Safresh1 
15*256a93a4Safresh1 #ifdef CAN64BITHASH
16*256a93a4Safresh1 
17*256a93a4Safresh1 #define SIPROUND            \
18*256a93a4Safresh1   STMT_START {              \
19*256a93a4Safresh1     v0 += v1; v1=ROTL64(v1,13); v1 ^= v0; v0=ROTL64(v0,32); \
20*256a93a4Safresh1     v2 += v3; v3=ROTL64(v3,16); v3 ^= v2;     \
21*256a93a4Safresh1     v0 += v3; v3=ROTL64(v3,21); v3 ^= v0;     \
22*256a93a4Safresh1     v2 += v1; v1=ROTL64(v1,17); v1 ^= v2; v2=ROTL64(v2,32); \
23*256a93a4Safresh1   } STMT_END
24*256a93a4Safresh1 
25*256a93a4Safresh1 #define SIPHASH_SEED_STATE(key,v0,v1,v2,v3) \
26*256a93a4Safresh1 do {                                    \
27*256a93a4Safresh1     v0 = v2 = U8TO64_LE(key + 0);       \
28*256a93a4Safresh1     v1 = v3 = U8TO64_LE(key + 8);       \
29*256a93a4Safresh1   /* "somepseudorandomlygeneratedbytes" */  \
30*256a93a4Safresh1     v0 ^= UINT64_C(0x736f6d6570736575);  \
31*256a93a4Safresh1     v1 ^= UINT64_C(0x646f72616e646f6d);      \
32*256a93a4Safresh1     v2 ^= UINT64_C(0x6c7967656e657261);      \
33*256a93a4Safresh1     v3 ^= UINT64_C(0x7465646279746573);      \
34*256a93a4Safresh1 } while (0)
35*256a93a4Safresh1 
36*256a93a4Safresh1 PERL_STATIC_INLINE
S_perl_siphash_seed_state(const unsigned char * const seed_buf,unsigned char * state_buf)37*256a93a4Safresh1 void S_perl_siphash_seed_state(const unsigned char * const seed_buf, unsigned char * state_buf) {
38*256a93a4Safresh1     U64 *v= (U64*) state_buf;
39*256a93a4Safresh1     SIPHASH_SEED_STATE(seed_buf, v[0],v[1],v[2],v[3]);
40*256a93a4Safresh1 }
41*256a93a4Safresh1 
42*256a93a4Safresh1 #define PERL_SIPHASH_FNC(FNC,SIP_ROUNDS,SIP_FINAL_ROUNDS) \
43*256a93a4Safresh1 PERL_STATIC_INLINE U64 \
44*256a93a4Safresh1 FNC ## _with_state_64 \
45*256a93a4Safresh1   (const unsigned char * const state, const unsigned char *in, const STRLEN inlen) \
46*256a93a4Safresh1 {                                           \
47*256a93a4Safresh1   const int left = inlen & 7;               \
48*256a93a4Safresh1   const U8 *end = in + inlen - left;        \
49*256a93a4Safresh1                                             \
50*256a93a4Safresh1   U64 b = ( ( U64 )(inlen) ) << 56;         \
51*256a93a4Safresh1   U64 m;                                    \
52*256a93a4Safresh1   U64 v0 = U8TO64_LE(state);                \
53*256a93a4Safresh1   U64 v1 = U8TO64_LE(state+8);              \
54*256a93a4Safresh1   U64 v2 = U8TO64_LE(state+16);             \
55*256a93a4Safresh1   U64 v3 = U8TO64_LE(state+24);             \
56*256a93a4Safresh1                                             \
57*256a93a4Safresh1   for ( ; in != end; in += 8 )              \
58*256a93a4Safresh1   {                                         \
59*256a93a4Safresh1     m = U8TO64_LE( in );                    \
60*256a93a4Safresh1     v3 ^= m;                                \
61*256a93a4Safresh1                                             \
62*256a93a4Safresh1     SIP_ROUNDS;                             \
63*256a93a4Safresh1                                             \
64*256a93a4Safresh1     v0 ^= m;                                \
65*256a93a4Safresh1   }                                         \
66*256a93a4Safresh1                                             \
67*256a93a4Safresh1   switch( left )                            \
68*256a93a4Safresh1   {                                         \
69*256a93a4Safresh1   case 7: b |= ( ( U64 )in[ 6] )  << 48; /*FALLTHROUGH*/    \
70*256a93a4Safresh1   case 6: b |= ( ( U64 )in[ 5] )  << 40; /*FALLTHROUGH*/    \
71*256a93a4Safresh1   case 5: b |= ( ( U64 )in[ 4] )  << 32; /*FALLTHROUGH*/    \
72*256a93a4Safresh1   case 4: b |= ( ( U64 )in[ 3] )  << 24; /*FALLTHROUGH*/    \
73*256a93a4Safresh1   case 3: b |= ( ( U64 )in[ 2] )  << 16; /*FALLTHROUGH*/    \
74*256a93a4Safresh1   case 2: b |= ( ( U64 )in[ 1] )  <<  8; /*FALLTHROUGH*/    \
75*256a93a4Safresh1   case 1: b |= ( ( U64 )in[ 0] ); break;    \
76*256a93a4Safresh1   case 0: break;                            \
77*256a93a4Safresh1   }                                         \
78*256a93a4Safresh1                                             \
79*256a93a4Safresh1   v3 ^= b;                                  \
80*256a93a4Safresh1                                             \
81*256a93a4Safresh1   SIP_ROUNDS;                               \
82*256a93a4Safresh1                                             \
83*256a93a4Safresh1   v0 ^= b;                                  \
84*256a93a4Safresh1                                             \
85*256a93a4Safresh1   v2 ^= 0xff;                               \
86*256a93a4Safresh1                                             \
87*256a93a4Safresh1   SIP_FINAL_ROUNDS                          \
88*256a93a4Safresh1                                             \
89*256a93a4Safresh1   b = v0 ^ v1 ^ v2  ^ v3;                   \
90*256a93a4Safresh1   return b;                                 \
91*256a93a4Safresh1 }                                           \
92*256a93a4Safresh1                                             \
93*256a93a4Safresh1 PERL_STATIC_INLINE U32                      \
94*256a93a4Safresh1 FNC ## _with_state                          \
95*256a93a4Safresh1   (const unsigned char * const state, const unsigned char *in, const STRLEN inlen) \
96*256a93a4Safresh1 {                                           \
97*256a93a4Safresh1     union {                                 \
98*256a93a4Safresh1         U64 h64;                            \
99*256a93a4Safresh1         U32 h32[2];                         \
100*256a93a4Safresh1     } h;                                    \
101*256a93a4Safresh1     h.h64= FNC ## _with_state_64(state,in,inlen); \
102*256a93a4Safresh1     return h.h32[0] ^ h.h32[1];             \
103*256a93a4Safresh1 }                                           \
104*256a93a4Safresh1                                             \
105*256a93a4Safresh1                                             \
106*256a93a4Safresh1 PERL_STATIC_INLINE U32                      \
107*256a93a4Safresh1 FNC (const unsigned char * const seed, const unsigned char *in, const STRLEN inlen) \
108*256a93a4Safresh1 {                                                                   \
109*256a93a4Safresh1     U64 state[4];                                                   \
110*256a93a4Safresh1     SIPHASH_SEED_STATE(seed,state[0],state[1],state[2],state[3]);   \
111*256a93a4Safresh1     return FNC ## _with_state((U8*)state,in,inlen);                 \
112*256a93a4Safresh1 }
113*256a93a4Safresh1 
114*256a93a4Safresh1 
115*256a93a4Safresh1 PERL_SIPHASH_FNC(
116*256a93a4Safresh1     S_perl_hash_siphash_1_3
117*256a93a4Safresh1     ,SIPROUND;
118*256a93a4Safresh1     ,SIPROUND;SIPROUND;SIPROUND;
119*256a93a4Safresh1 )
120*256a93a4Safresh1 
121*256a93a4Safresh1 PERL_SIPHASH_FNC(
122*256a93a4Safresh1     S_perl_hash_siphash_2_4
123*256a93a4Safresh1     ,SIPROUND;SIPROUND;
124*256a93a4Safresh1     ,SIPROUND;SIPROUND;SIPROUND;SIPROUND;
125*256a93a4Safresh1 )
126*256a93a4Safresh1 
127*256a93a4Safresh1 #endif /* defined(CAN64BITHASH) */
128