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) */ 128