Line data Source code
1 : #include "fd_siphash13.h"
2 :
3 : /* This code is a modified version of https://github.com/antirez/siphash
4 : For further license info see NOTICE in the root of this repo.
5 :
6 : Copyright (c) 2012-2016 Jean-Philippe Aumasson
7 : <jeanphilippe.aumasson@gmail.com>
8 : Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
9 : Copyright (c) 2017 Salvatore Sanfilippo <antirez@gmail.com>
10 : Modified 2023 by Firedancer Contributors */
11 :
12 : static const ulong __attribute__((aligned(64UL)))
13 : fd_siphash13_initial[4] = {
14 : 0x736f6d6570736575UL,
15 : 0x646f72616e646f6dUL,
16 : 0x6c7967656e657261UL,
17 : 0x7465646279746573UL,
18 : };
19 :
20 : fd_siphash13_t *
21 : fd_siphash13_init( fd_siphash13_t * sip,
22 : ulong k0,
23 4 : ulong k1 ) {
24 :
25 4 : memset( sip, 0, sizeof(fd_siphash13_t) );
26 :
27 4 : ulong * v = sip->v;
28 :
29 4 : v[ 0 ] = fd_siphash13_initial[ 0 ];
30 4 : v[ 1 ] = fd_siphash13_initial[ 1 ];
31 4 : v[ 2 ] = fd_siphash13_initial[ 2 ];
32 4 : v[ 3 ] = fd_siphash13_initial[ 3 ];
33 4 : v[ 3 ] ^= k1;
34 4 : v[ 2 ] ^= k0;
35 4 : v[ 1 ] ^= k1;
36 4 : v[ 0 ] ^= k0;
37 :
38 4 : return sip;
39 4 : }
40 :
41 : static void
42 : fd_siphash1N_core( ulong v[ static 4 ],
43 : uchar const * buf,
44 12 : ulong n ) {
45 12 : ulong m;
46 48 : for( ulong i=0UL; i<n; i++ ) {
47 36 : m = ((ulong const *)buf)[ i ];
48 36 : v[ 3 ] ^= m;
49 36 : FD_SIPHASH_ROUND( v );
50 36 : v[ 0 ] ^= m;
51 36 : }
52 12 : }
53 :
54 : fd_siphash13_t *
55 : fd_siphash13_append( fd_siphash13_t * sip,
56 : uchar const * data,
57 8 : ulong sz ) {
58 :
59 8 : ulong * v = sip->v;
60 8 : uchar * buf = sip->buf;
61 8 : ulong buf_used = sip->n & 7UL;
62 :
63 8 : sip->n += sz;
64 :
65 8 : if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
66 :
67 : /* If the append isn't large enough to complete the current block,
68 : buffer these bytes too and return */
69 :
70 0 : ulong buf_rem = 8UL - buf_used;
71 0 : if( FD_UNLIKELY( sz < buf_rem ) ) {
72 0 : fd_memcpy( buf + buf_used, data, sz );
73 0 : return sip;
74 0 : }
75 :
76 : /* Otherwise, buffer enough leading bytes of data complete the
77 : block, update the hash and then continue processing any remaining
78 : bytes of data. */
79 :
80 0 : fd_memcpy( buf + buf_used, data, buf_rem );
81 0 : data += buf_rem;
82 0 : sz -= buf_rem;
83 :
84 0 : fd_siphash1N_core( v, buf, 1UL );
85 0 : }
86 :
87 : /* Append the bulk of the data */
88 :
89 8 : ulong block_cnt = sz >> 3;
90 8 : if( FD_LIKELY( block_cnt ) ) fd_siphash1N_core( v, data, block_cnt );
91 :
92 : /* Buffer any leftover bytes */
93 :
94 8 : buf_used = sz & 7UL;
95 8 : if( FD_UNLIKELY( buf_used ) )
96 0 : fd_memcpy( buf, data + (sz - buf_used), buf_used );
97 :
98 8 : return sip;
99 8 : }
100 :
101 : fd_siphash13_t *
102 : fd_siphash13_append_fast( fd_siphash13_t * sip,
103 : uchar const * data,
104 0 : ulong sz ) {
105 : /* TODO debug assertions */
106 0 : sip->n += sz;
107 0 : fd_siphash1N_core( sip->v, data, sz >> 3 );
108 0 : return sip;
109 0 : }
110 :
111 : ulong
112 4 : fd_siphash13_fini( fd_siphash13_t * sip ) {
113 :
114 : /* Unpack inputs */
115 :
116 4 : ulong * v = sip->v;
117 4 : uchar * buf = sip->buf;
118 4 : ulong n = sip->n;
119 4 : ulong buf_used = sip->n & 7UL;
120 :
121 : /* Hash last block */
122 :
123 4 : ulong b = n<<56UL;
124 4 : switch( buf_used ) {
125 0 : case 7: b |= ((ulong)buf[6]) << 48; __attribute__((fallthrough));
126 0 : case 6: b |= ((ulong)buf[5]) << 40; __attribute__((fallthrough));
127 0 : case 5: b |= ((ulong)buf[4]) << 32; __attribute__((fallthrough));
128 0 : case 4: b |= ((ulong)buf[3]) << 24; __attribute__((fallthrough));
129 0 : case 3: b |= ((ulong)buf[2]) << 16; __attribute__((fallthrough));
130 0 : case 2: b |= ((ulong)buf[1]) << 8; __attribute__((fallthrough));
131 0 : case 1: b |= ((ulong)buf[0]); break;
132 4 : case 0: break;
133 4 : }
134 4 : fd_siphash1N_core( v, (uchar const *)&b, 1UL );
135 :
136 : /* Finalize */
137 :
138 4 : v[ 2 ] ^= 0xff;
139 4 : FD_SIPHASH_ROUND( v );
140 4 : FD_SIPHASH_ROUND( v );
141 4 : FD_SIPHASH_ROUND( v );
142 4 : b = v[ 0 ] ^ v[ 1 ] ^ v[ 2 ] ^ v[ 3 ];
143 4 : return b;
144 4 : }
145 :
146 : FD_FN_PURE ulong
147 : fd_siphash13_hash( void const * data,
148 : ulong data_sz,
149 : ulong k0,
150 0 : ulong k1 ) {
151 :
152 : /* Initialize */
153 :
154 0 : ulong v[ 4 ];
155 0 : memcpy( v, fd_siphash13_initial, 32UL );
156 :
157 0 : v[ 3 ] ^= k1;
158 0 : v[ 2 ] ^= k0;
159 0 : v[ 1 ] ^= k1;
160 0 : v[ 0 ] ^= k0;
161 :
162 : /* Hash blocks */
163 :
164 0 : ulong m;
165 0 : ulong const * in = (ulong const *)data;
166 0 : ulong const * end = in + data_sz/8UL;
167 0 : for( ; in!=end; in++ ) {
168 0 : m = *in;
169 0 : v[ 3 ] ^= m;
170 0 : FD_SIPHASH_ROUND( v );
171 0 : v[ 0 ] ^= m;
172 0 : }
173 :
174 : /* Hash last block */
175 :
176 0 : int const left = data_sz & 7;
177 0 : ulong b = ((ulong)data_sz) << 56;
178 0 : uchar const * rem = (uchar const *)in;
179 0 : switch( left ) {
180 0 : case 7: b |= ((ulong)rem[6]) << 48; __attribute__((fallthrough));
181 0 : case 6: b |= ((ulong)rem[5]) << 40; __attribute__((fallthrough));
182 0 : case 5: b |= ((ulong)rem[4]) << 32; __attribute__((fallthrough));
183 0 : case 4: b |= ((ulong)rem[3]) << 24; __attribute__((fallthrough));
184 0 : case 3: b |= ((ulong)rem[2]) << 16; __attribute__((fallthrough));
185 0 : case 2: b |= ((ulong)rem[1]) << 8; __attribute__((fallthrough));
186 0 : case 1: b |= ((ulong)rem[0]); break;
187 0 : case 0: break;
188 0 : }
189 :
190 0 : v[ 3 ] ^= b;
191 0 : FD_SIPHASH_ROUND( v );
192 0 : v[ 0 ] ^= b;
193 :
194 : /* Finalize */
195 :
196 0 : v[ 2 ] ^= 0xff;
197 0 : FD_SIPHASH_ROUND( v );
198 0 : FD_SIPHASH_ROUND( v );
199 0 : FD_SIPHASH_ROUND( v );
200 0 : b = v[ 0 ] ^ v[ 1 ] ^ v[ 2 ] ^ v[ 3 ];
201 :
202 0 : return b;
203 0 : }
|