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