File Coverage

/usr/local/lib/perl5/5.42.0/x86_64-linux/CORE/perl_siphash.h
Criterion Covered Total %
statement 0 1 0.0
branch 0 2 0.0
condition n/a
subroutine n/a
pod n/a
total 0 3 0.0


line stmt bran cond sub pod time code
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             * Naming convention:
9             *
10             * S_perl_hash_siphash_N_M: the N refers to how many rounds are performed per
11             * block. The M refers to how many rounds are performed as part of the
12             * finalizer. Increased values of either improve security, but decrease
13             * performance.
14             *
15             * _with_state: these functions take a 32 bit state vector prepared by
16             * S_perl_siphash_seed_state(). Functions without 'with_state' take a 16
17             * byte seed vector and call S_perl_siphash_seed_state() implicitly. If
18             * you are hashing many things with the same seed, the _with_state
19             * variants are faster.
20             *
21             * _64: returns a 64 bit hash
22             *
23             * no-suffix: returns a 32 bit hash.
24             *
25             * This file defines 9 functions related to implementing 2 variants of
26             * the Siphash family of hash functions, Siphash-2-4, and Siphash-1-3.
27              
28             =for apidoc_section $numeric
29             =for apidoc eST|void|S_perl_siphash_seed_state \
30             |const unsigned char * const seed_buf \
31             |unsigned char * state_buf
32              
33             Takes a 16 byte seed and converts it into a 32 byte state buffer. The
34             contents of state_buf will be overwritten.
35              
36             If you need to hash a lot of things, then you can use this to process
37             the seed once, and then reuse the state over and over.
38              
39             The siphash functions which take a seed argument will call this function
40             implicitly every time they are used. Those which take a state argument
41             require the seed to be converted into a state before they are used.
42              
43             See the various _with_state siphash functions for a usage example.
44              
45             =for apidoc eSTP|U64|S_perl_hash_siphash_1_3_with_state_64\
46             |const unsigned char * const state \
47             |const unsigned char *in|const STRLEN inlen
48              
49             Implements the variant of Siphash which performs 1 round function
50             per block, and 3 as part of the finalizer.
51              
52             Takes a 32 byte 'state' vector prepared by S_perl_siphash_seed_state()
53             and uses it to hash C bytes from the buffer pointed to by C,
54             returns a 64 bit hash.
55              
56             The following code should return 0xB70339FD9E758A5C
57              
58             U8 state[32];
59             char seed[] = "Call me Ishmael.";
60             S_perl_siphash_seed_state((const U8*)seed, state);
61              
62             char in[] = "It is not down on any map; true places never are.";
63             U64 hash = S_perl_hash_siphash_1_3_with_state_64(
64             state, (const U8*)in, sizeof(in)-1);
65              
66             =for apidoc eSTP|U32|S_perl_hash_siphash_1_3_with_state\
67             |const unsigned char * const state \
68             |const unsigned char *in|const STRLEN inlen
69              
70             Implements the variant of Siphash which performs 1 round function
71             per block, and 3 as part of the finalizer.
72              
73             Takes a 32 byte 'state' vector prepared by S_perl_siphash_seed_state()
74             and uses it to hash C bytes from the buffer pointed to by C,
75             returns a 32 bit hash.
76              
77             The following code should return 0x2976B3A1
78              
79             U8 state[32];
80             char seed[] = "Call me Ishmael.";
81             S_perl_siphash_seed_state((const U8*)seed, state);
82              
83             char in[] = "It is not down on any map; true places never are.";
84             U32 hash = S_perl_hash_siphash_1_3_with_state(
85             state, (const U8*)in, sizeof(in)-1);
86              
87             =for apidoc eSTP|U64|S_perl_hash_siphash_1_3_64\
88             |const unsigned char * const seed \
89             |const unsigned char *in|const STRLEN inlen
90              
91             Implements the variant of Siphash which performs 1 round function
92             per block, and 3 as part of the finalizer.
93              
94             Takes a 16 byte C vector, and uses it to hash C bytes
95             from the buffer pointed to by C, returns a 64 bit hash.
96              
97             The following code should return 0xB70339FD9E758A5C
98              
99             char seed[] = "Call me Ishmael.";
100             char in[] = "It is not down on any map; true places never are.";
101             U64 hash = S_perl_hash_siphash_1_3_64(
102             (const U8*)seed, (const U8*)in, sizeof(in)-1);
103              
104             =for apidoc eSTP|U64|S_perl_hash_siphash_1_3\
105             |const unsigned char * const seed \
106             |const unsigned char *in|const STRLEN inlen
107              
108             Implements the variant of Siphash which performs 1 round function
109             per block, and 3 as part of the finalizer.
110              
111             Takes a 16 byte C vector, and uses it to hash C bytes
112             from the buffer pointed to by C, returns a 32 bit hash.
113              
114             The following code should return 0x2976B3A1
115              
116             char seed[] = "Call me Ishmael.";
117             char in[] = "It is not down on any map; true places never are.";
118             U32 hash = S_perl_hash_siphash_1_3(
119             (const U8*)seed, (const U8*)in, sizeof(in)-1);
120              
121             =for apidoc eSTP|U64|S_perl_hash_siphash_2_4_with_state_64\
122             |const unsigned char * const state \
123             |const unsigned char *in|const STRLEN inlen
124              
125             Implements the variant of Siphash which performs 2 round functions
126             per block, and 4 as part of the finalizer.
127              
128             Takes a 32 byte 'state' vector prepared by S_perl_siphash_seed_state()
129             and uses it to hash C bytes from the buffer pointed to by C,
130             returns a 64 bit hash.
131              
132             The following code should return 0x1E84CF1D7AA516B7
133              
134             U8 state[32];
135             char seed[] = "Call me Ishmael.";
136             S_perl_siphash_seed_state((const U8*)seed, state);
137              
138             char in[] = "It is not down on any map; true places never are.";
139             U64 hash = S_perl_hash_siphash_2_4_with_state_64(
140             state, (const U8*)in, sizeof(in)-1);
141              
142             =for apidoc eSTP|U32|S_perl_hash_siphash_2_4_with_state\
143             |const unsigned char * const state \
144             |const unsigned char *in|const STRLEN inlen
145              
146             Implements the variant of Siphash which performs 2 round function
147             per block, and 4 as part of the finalizer.
148              
149             Takes a 32 byte 'state' vector prepared by S_perl_siphash_seed_state()
150             and uses it to hash C bytes from the buffer pointed to by C,
151             returns a 32 bit hash.
152              
153             The following code should return 0x6421D9AA
154              
155             U8 state[32];
156             char seed[] = "Call me Ishmael.";
157             S_perl_siphash_seed_state((const U8*)seed, state);
158              
159             char in[] = "It is not down on any map; true places never are.";
160             U32 hash = S_perl_hash_siphash_2_4_with_state(
161             state, (const U8*)in, sizeof(in)-1);
162              
163             =for apidoc eSTP|U64|S_perl_hash_siphash_2_4_64\
164             |const unsigned char * const seed \
165             |const unsigned char *in|const STRLEN inlen
166              
167             Implements the variant of Siphash which performs 2 round functions
168             per block, and 4 as part of the finalizer.
169              
170             Takes a 16 byte C vector, and uses it to hash C bytes
171             from the buffer pointed to by C, returns a 64 bit hash.
172              
173             The following code should return 0x1E84CF1D7AA516B7
174              
175             char seed[] = "Call me Ishmael.";
176             char in[] = "It is not down on any map; true places never are.";
177             U64 hash = S_perl_hash_siphash_2_4_64(
178             (const U8*)seed, (const U8*)in, sizeof(in)-1);
179              
180             =for apidoc eSTP|U32|S_perl_hash_siphash_2_4\
181             |const unsigned char * const seed \
182             |const unsigned char *in|const STRLEN inlen
183              
184             Implements the variant of Siphash which performs 2 round functions
185             per block, and 4 as part of the finalizer.
186              
187             Takes a 16 byte C vector, and uses it to hash C bytes
188             from the buffer pointed to by C, returns a 32 bit hash.
189              
190             The following code should return 0x6421D9AA
191              
192             char seed[] = "Call me Ishmael.";
193             char in[] = "It is not down on any map; true places never are.";
194             U32 hash = S_perl_hash_siphash_2_4(
195             (const U8*)seed, (const U8*)in, sizeof(in)-1);
196              
197             =cut
198             */
199              
200             #ifdef CAN64BITHASH
201              
202             #define SIPROUND \
203             STMT_START { \
204             v0 += v1; v1=ROTL64(v1,13); v1 ^= v0; v0=ROTL64(v0,32); \
205             v2 += v3; v3=ROTL64(v3,16); v3 ^= v2; \
206             v0 += v3; v3=ROTL64(v3,21); v3 ^= v0; \
207             v2 += v1; v1=ROTL64(v1,17); v1 ^= v2; v2=ROTL64(v2,32); \
208             } STMT_END
209              
210             #define SIPHASH_SEED_STATE(key,v0,v1,v2,v3) \
211             do { \
212             v0 = v2 = U8TO64_LE(key + 0); \
213             v1 = v3 = U8TO64_LE(key + 8); \
214             /* "somepseudorandomlygeneratedbytes" */ \
215             v0 ^= UINT64_C(0x736f6d6570736575); \
216             v1 ^= UINT64_C(0x646f72616e646f6d); \
217             v2 ^= UINT64_C(0x6c7967656e657261); \
218             v3 ^= UINT64_C(0x7465646279746573); \
219             } while (0)
220              
221             PERL_STATIC_INLINE
222             void S_perl_siphash_seed_state(const unsigned char * const seed_buf, unsigned char * state_buf) {
223             U64 *v= (U64*) state_buf;
224             SIPHASH_SEED_STATE(seed_buf, v[0],v[1],v[2],v[3]);
225             }
226              
227             #define PERL_SIPHASH_FNC(FNC,SIP_ROUNDS,SIP_FINAL_ROUNDS) \
228             PERL_STATIC_INLINE U64 \
229             FNC ## _with_state_64 \
230             (const unsigned char * const state, const unsigned char *in, const STRLEN inlen) \
231             { \
232             const int left = inlen & 7; \
233             const U8 *end = in + inlen - left;\
234             \
235             U64 b = ( ( U64 )(inlen) ) << 56; \
236             U64 m; \
237             U64 v0 = U8TO64_LE(state); \
238             U64 v1 = U8TO64_LE(state+8); \
239             U64 v2 = U8TO64_LE(state+16); \
240             U64 v3 = U8TO64_LE(state+24); \
241             \
242             for ( ; in != end; in += 8 ) \
243             { \
244             m = U8TO64_LE( in ); \
245             v3 ^= m; \
246             \
247             SIP_ROUNDS; \
248             \
249             v0 ^= m; \
250             } \
251             \
252             switch( left ) \
253             { \
254             case 7: b |= ( ( U64 )in[ 6] ) << 48; /*FALLTHROUGH*/ \
255             case 6: b |= ( ( U64 )in[ 5] ) << 40; /*FALLTHROUGH*/ \
256             case 5: b |= ( ( U64 )in[ 4] ) << 32; /*FALLTHROUGH*/ \
257             case 4: b |= ( ( U64 )in[ 3] ) << 24; /*FALLTHROUGH*/ \
258             case 3: b |= ( ( U64 )in[ 2] ) << 16; /*FALLTHROUGH*/ \
259             case 2: b |= ( ( U64 )in[ 1] ) << 8; /*FALLTHROUGH*/ \
260             case 1: b |= ( ( U64 )in[ 0] ); break; \
261             case 0: break; \
262             } \
263             \
264             v3 ^= b; \
265             \
266             SIP_ROUNDS; \
267             \
268             v0 ^= b; \
269             \
270             v2 ^= 0xff; \
271             \
272             SIP_FINAL_ROUNDS \
273             \
274             b = v0 ^ v1 ^ v2 ^ v3; \
275             return b; \
276             } \
277             \
278             PERL_STATIC_INLINE U32 \
279             FNC ## _with_state \
280             (const unsigned char * const state, const unsigned char *in, const STRLEN inlen) \
281             { \
282             union { \
283             U64 h64; \
284             U32 h32[2]; \
285             } h; \
286             h.h64= FNC ## _with_state_64(state,in,inlen); \
287             return h.h32[0] ^ h.h32[1]; \
288             } \
289             \
290             \
291             PERL_STATIC_INLINE U32 \
292             FNC (const unsigned char * const seed, const unsigned char *in, const STRLEN inlen) \
293             { \
294             U64 state[4]; \
295             SIPHASH_SEED_STATE(seed,state[0],state[1],state[2],state[3]); \
296             return FNC ## _with_state((U8*)state,in,inlen); \
297             } \
298             \
299             PERL_STATIC_INLINE U64 \
300             FNC ## _64 (const unsigned char * const seed, const unsigned char *in, const STRLEN inlen) \
301             { \
302             U64 state[4]; \
303             SIPHASH_SEED_STATE(seed,state[0],state[1],state[2],state[3]); \
304             return FNC ## _with_state_64((U8*)state,in,inlen); \
305             }
306              
307 0 0         PERL_SIPHASH_FNC(
308             S_perl_hash_siphash_1_3
309             ,SIPROUND;
310             ,SIPROUND;SIPROUND;SIPROUND;
311             )
312              
313             PERL_SIPHASH_FNC(
314             S_perl_hash_siphash_2_4
315             ,SIPROUND;SIPROUND;
316             ,SIPROUND;SIPROUND;SIPROUND;SIPROUND;
317             )
318              
319             #endif /* defined(CAN64BITHASH) */