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