Line data Source code
1 : #include "fd_sha256.h"
2 :
3 : ulong
4 3 : fd_sha256_align( void ) {
5 3 : return FD_SHA256_ALIGN;
6 3 : }
7 :
8 : ulong
9 3 : fd_sha256_footprint( void ) {
10 3 : return FD_SHA256_FOOTPRINT;
11 3 : }
12 :
13 : void *
14 400962 : fd_sha256_new( void * shmem ) {
15 400962 : fd_sha256_t * sha = (fd_sha256_t *)shmem;
16 :
17 400962 : if( FD_UNLIKELY( !shmem ) ) {
18 3 : FD_LOG_WARNING(( "NULL shmem" ));
19 3 : return NULL;
20 3 : }
21 :
22 400959 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_sha256_align() ) ) ) {
23 3 : FD_LOG_WARNING(( "misaligned shmem" ));
24 3 : return NULL;
25 3 : }
26 :
27 400956 : ulong footprint = fd_sha256_footprint();
28 :
29 400956 : fd_memset( sha, 0, footprint );
30 :
31 400956 : FD_COMPILER_MFENCE();
32 400956 : FD_VOLATILE( sha->magic ) = FD_SHA256_MAGIC;
33 400956 : FD_COMPILER_MFENCE();
34 :
35 400956 : return (void *)sha;
36 400959 : }
37 :
38 : fd_sha256_t *
39 400962 : fd_sha256_join( void * shsha ) {
40 :
41 400962 : if( FD_UNLIKELY( !shsha ) ) {
42 3 : FD_LOG_WARNING(( "NULL shsha" ));
43 3 : return NULL;
44 3 : }
45 :
46 400959 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shsha, fd_sha256_align() ) ) ) {
47 3 : FD_LOG_WARNING(( "misaligned shsha" ));
48 3 : return NULL;
49 3 : }
50 :
51 400956 : fd_sha256_t * sha = (fd_sha256_t *)shsha;
52 :
53 400956 : if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
54 0 : FD_LOG_WARNING(( "bad magic" ));
55 0 : return NULL;
56 0 : }
57 :
58 400956 : return sha;
59 400956 : }
60 :
61 : void *
62 15 : fd_sha256_leave( fd_sha256_t * sha ) {
63 :
64 15 : if( FD_UNLIKELY( !sha ) ) {
65 3 : FD_LOG_WARNING(( "NULL sha" ));
66 3 : return NULL;
67 3 : }
68 :
69 12 : return (void *)sha;
70 15 : }
71 :
72 : void *
73 18 : fd_sha256_delete( void * shsha ) {
74 :
75 18 : if( FD_UNLIKELY( !shsha ) ) {
76 3 : FD_LOG_WARNING(( "NULL shsha" ));
77 3 : return NULL;
78 3 : }
79 :
80 15 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shsha, fd_sha256_align() ) ) ) {
81 3 : FD_LOG_WARNING(( "misaligned shsha" ));
82 3 : return NULL;
83 3 : }
84 :
85 12 : fd_sha256_t * sha = (fd_sha256_t *)shsha;
86 :
87 12 : if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
88 0 : FD_LOG_WARNING(( "bad magic" ));
89 0 : return NULL;
90 0 : }
91 :
92 12 : FD_COMPILER_MFENCE();
93 12 : FD_VOLATILE( sha->magic ) = 0UL;
94 12 : FD_COMPILER_MFENCE();
95 :
96 12 : return (void *)sha;
97 12 : }
98 :
99 : #ifndef FD_SHA256_CORE_IMPL
100 : #if FD_HAS_SHANI
101 : #define FD_SHA256_CORE_IMPL 1
102 : #else
103 : #define FD_SHA256_CORE_IMPL 0
104 : #endif
105 : #endif
106 :
107 : #if FD_SHA256_CORE_IMPL==0
108 :
109 : /* The implementation below was derived from OpenSSL's SHA-256
110 : implementation (Apache-2.0 licensed). See in particular:
111 :
112 : https://github.com/openssl/openssl/blob/master/crypto/sha/sha256.c
113 :
114 : (link valid circa 2022-Dec). It has been made more strict with more
115 : extensive implementation documentation, has been simplified and has
116 : been streamlined specifically for use inside Firedancer base machine
117 : model (no machine specific capabilities required).
118 :
119 : In particular, fd_sha256_core_ref is based on OpenSSL's
120 : OPENSSL_SMALL_FOOTPRINT SHA-256 implementation (Apache licensed).
121 : This should work anywhere but it is not the highest performance
122 : implementation possible.
123 :
124 : It is also straightforward to replace these implementations with HPC
125 : implementations that target specific machine capabilities without
126 : requiring any changes to caller code. */
127 :
128 : static void
129 : fd_sha256_core_ref( uint * state,
130 : uchar const * block,
131 377124692 : ulong block_cnt ) {
132 :
133 377124692 : static uint const K[64] = {
134 377124692 : 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U,
135 377124692 : 0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U,
136 377124692 : 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU,
137 377124692 : 0x983e5152U, 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U, 0x06ca6351U, 0x14292967U,
138 377124692 : 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
139 377124692 : 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U,
140 377124692 : 0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U,
141 377124692 : 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U,
142 377124692 : };
143 :
144 >30147*10^7 : # define ROTATE fd_uint_rotate_left
145 33496882816 : # define Sigma0(x) (ROTATE((x),30) ^ ROTATE((x),19) ^ ROTATE((x),10))
146 33496882816 : # define Sigma1(x) (ROTATE((x),26) ^ ROTATE((x),21) ^ ROTATE((x),7))
147 25122662112 : # define sigma0(x) (ROTATE((x),25) ^ ROTATE((x),14) ^ ((x)>>3))
148 25122662112 : # define sigma1(x) (ROTATE((x),15) ^ ROTATE((x),13) ^ ((x)>>10))
149 33496882816 : # define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
150 33496882816 : # define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
151 :
152 377124692 : uint const * W = (uint const *)block;
153 523388794 : do {
154 523388794 : uint a = state[0];
155 523388794 : uint b = state[1];
156 523388794 : uint c = state[2];
157 523388794 : uint d = state[3];
158 523388794 : uint e = state[4];
159 523388794 : uint f = state[5];
160 523388794 : uint g = state[6];
161 523388794 : uint h = state[7];
162 :
163 523388794 : uint X[16];
164 :
165 523388794 : ulong i;
166 8897609498 : for( i=0UL; i<16UL; i++ ) {
167 8374220704 : X[i] = fd_uint_bswap( W[i] );
168 8374220704 : uint T1 = X[i] + h + Sigma1(e) + Ch(e, f, g) + K[i];
169 8374220704 : uint T2 = Sigma0(a) + Maj(a, b, c);
170 8374220704 : h = g;
171 8374220704 : g = f;
172 8374220704 : f = e;
173 8374220704 : e = d + T1;
174 8374220704 : d = c;
175 8374220704 : c = b;
176 8374220704 : b = a;
177 8374220704 : a = T1 + T2;
178 8374220704 : }
179 25646050906 : for( ; i<64UL; i++ ) {
180 25122662112 : uint s0 = X[(i + 1UL) & 0x0fUL];
181 25122662112 : uint s1 = X[(i + 14UL) & 0x0fUL];
182 25122662112 : s0 = sigma0(s0);
183 25122662112 : s1 = sigma1(s1);
184 25122662112 : X[i & 0xfUL] += s0 + s1 + X[(i + 9UL) & 0xfUL];
185 25122662112 : uint T1 = X[i & 0xfUL ] + h + Sigma1(e) + Ch(e, f, g) + K[i];
186 25122662112 : uint T2 = Sigma0(a) + Maj(a, b, c);
187 25122662112 : h = g;
188 25122662112 : g = f;
189 25122662112 : f = e;
190 25122662112 : e = d + T1;
191 25122662112 : d = c;
192 25122662112 : c = b;
193 25122662112 : b = a;
194 25122662112 : a = T1 + T2;
195 25122662112 : }
196 :
197 523388794 : state[0] += a;
198 523388794 : state[1] += b;
199 523388794 : state[2] += c;
200 523388794 : state[3] += d;
201 523388794 : state[4] += e;
202 523388794 : state[5] += f;
203 523388794 : state[6] += g;
204 523388794 : state[7] += h;
205 :
206 523388794 : W += 16UL;
207 523388794 : } while( --block_cnt );
208 :
209 377124692 : # undef ROTATE
210 377124692 : # undef Sigma0
211 377124692 : # undef Sigma1
212 377124692 : # undef sigma0
213 377124692 : # undef sigma1
214 377124692 : # undef Ch
215 377124692 : # undef Maj
216 :
217 377124692 : }
218 :
219 377124692 : #define fd_sha256_core fd_sha256_core_ref
220 :
221 : #elif FD_SHA256_CORE_IMPL==1
222 :
223 : __attribute__((sysv_abi))
224 : void
225 : fd_sha256_core_shaext( uint * state, /* 64-byte aligned, 8 entries */
226 : uchar const * block, /* ideally 128-byte aligned (but not required), 128*block_cnt in size */
227 : ulong block_cnt ); /* positive */
228 :
229 189637775 : #define fd_sha256_core fd_sha256_core_shaext
230 :
231 : #else
232 : #error "Unsupported FD_SHA256_CORE_IMPL"
233 : #endif
234 :
235 : fd_sha256_t *
236 1400760 : fd_sha256_init( fd_sha256_t * sha ) {
237 1400760 : sha->state[0] = 0x6a09e667U;
238 1400760 : sha->state[1] = 0xbb67ae85U;
239 1400760 : sha->state[2] = 0x3c6ef372U;
240 1400760 : sha->state[3] = 0xa54ff53aU;
241 1400760 : sha->state[4] = 0x510e527fU;
242 1400760 : sha->state[5] = 0x9b05688cU;
243 1400760 : sha->state[6] = 0x1f83d9abU;
244 1400760 : sha->state[7] = 0x5be0cd19U;
245 1400760 : sha->buf_used = 0UL;
246 1400760 : sha->bit_cnt = 0UL;
247 1400760 : return sha;
248 1400760 : }
249 :
250 : fd_sha256_t *
251 : fd_sha256_append( fd_sha256_t * sha,
252 : void const * _data,
253 5402595 : ulong sz ) {
254 :
255 : /* If no data to append, we are done */
256 :
257 5402595 : if( FD_UNLIKELY( !sz ) ) return sha; /* optimize for non-trivial append */
258 :
259 : /* Unpack inputs */
260 :
261 5402103 : uint * state = sha->state;
262 5402103 : uchar * buf = sha->buf;
263 5402103 : ulong buf_used = sha->buf_used;
264 5402103 : ulong bit_cnt = sha->bit_cnt;
265 :
266 5402103 : uchar const * data = (uchar const *)_data;
267 :
268 : /* Update bit_cnt */
269 : /* FIXME: could accumulate bytes here and do bit conversion in append */
270 : /* FIXME: Overflow handling if more than 2^64 bits (unlikely) */
271 :
272 5402103 : sha->bit_cnt = bit_cnt + (sz<<3);
273 :
274 : /* Handle buffered bytes from previous appends */
275 :
276 5402103 : if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
277 :
278 : /* If the append isn't large enough to complete the current block,
279 : buffer these bytes too and return */
280 :
281 78438 : ulong buf_rem = FD_SHA256_PRIVATE_BUF_MAX - buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
282 78438 : if( FD_UNLIKELY( sz < buf_rem ) ) { /* optimize for large append */
283 30849 : fd_memcpy( buf + buf_used, data, sz );
284 30849 : sha->buf_used = buf_used + sz;
285 30849 : return sha;
286 30849 : }
287 :
288 : /* Otherwise, buffer enough leading bytes of data to complete the
289 : block, update the hash and then continue processing any remaining
290 : bytes of data. */
291 :
292 47589 : fd_memcpy( buf + buf_used, data, buf_rem );
293 47589 : data += buf_rem;
294 47589 : sz -= buf_rem;
295 :
296 47589 : fd_sha256_core( state, buf, 1UL );
297 47589 : sha->buf_used = 0UL;
298 47589 : }
299 :
300 : /* Append the bulk of the data */
301 :
302 5371254 : ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
303 5371254 : if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt ); /* optimized for large append */
304 :
305 : /* Buffer any leftover bytes */
306 :
307 5371254 : buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL); /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
308 5371254 : if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
309 1147995 : fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
310 1147995 : sha->buf_used = buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
311 1147995 : }
312 :
313 5371254 : return sha;
314 5402103 : }
315 :
316 : void *
317 : fd_sha256_fini( fd_sha256_t * sha,
318 1448880 : void * _hash ) {
319 :
320 : /* Unpack inputs */
321 :
322 1448880 : uint * state = sha->state;
323 1448880 : uchar * buf = sha->buf;
324 1448880 : ulong buf_used = sha->buf_used; /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
325 1448880 : ulong bit_cnt = sha->bit_cnt;
326 :
327 : /* Append the terminating message byte */
328 :
329 1448880 : buf[ buf_used ] = (uchar)0x80;
330 1448880 : buf_used++;
331 :
332 : /* If there isn't enough room to save the message length in bits at
333 : the end of the in progress block, clear the rest of the in progress
334 : block, update the hash and start a new block. */
335 :
336 1448880 : if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) { /* optimize for well aligned use of append */
337 12057 : fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
338 12057 : fd_sha256_core( state, buf, 1UL );
339 12057 : buf_used = 0UL;
340 12057 : }
341 :
342 : /* Clear in progress block up to last 64-bits, append the message
343 : size in bytes in the last 64-bits of the in progress block and
344 : update the hash to finalize it. */
345 :
346 1448880 : fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
347 1448880 : FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
348 1448880 : fd_sha256_core( state, buf, 1UL );
349 :
350 : /* Unpack the result into md (annoying bswaps here) */
351 :
352 1448880 : state[0] = fd_uint_bswap( state[0] );
353 1448880 : state[1] = fd_uint_bswap( state[1] );
354 1448880 : state[2] = fd_uint_bswap( state[2] );
355 1448880 : state[3] = fd_uint_bswap( state[3] );
356 1448880 : state[4] = fd_uint_bswap( state[4] );
357 1448880 : state[5] = fd_uint_bswap( state[5] );
358 1448880 : state[6] = fd_uint_bswap( state[6] );
359 1448880 : state[7] = fd_uint_bswap( state[7] );
360 1448880 : return memcpy( _hash, state, 32 );
361 1448880 : }
362 :
363 : void *
364 : fd_sha256_hash( void const * _data,
365 : ulong sz,
366 133173377 : void * _hash ) {
367 133173377 : uchar const * data = (uchar const *)_data;
368 :
369 : /* This is just the above streamlined to eliminate all the overheads
370 : to support incremental hashing. */
371 :
372 133173377 : uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ] __attribute__((aligned(128)));
373 133173377 : uint state[8] __attribute__((aligned(32)));
374 :
375 133173377 : state[0] = 0x6a09e667U;
376 133173377 : state[1] = 0xbb67ae85U;
377 133173377 : state[2] = 0x3c6ef372U;
378 133173377 : state[3] = 0xa54ff53aU;
379 133173377 : state[4] = 0x510e527fU;
380 133173377 : state[5] = 0x9b05688cU;
381 133173377 : state[6] = 0x1f83d9abU;
382 133173377 : state[7] = 0x5be0cd19U;
383 :
384 133173377 : ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
385 133173377 : if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt );
386 :
387 133173377 : ulong buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL);
388 133173377 : if( FD_UNLIKELY( buf_used ) ) fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
389 133173377 : buf[ buf_used ] = (uchar)0x80;
390 133173377 : buf_used++;
391 :
392 133173377 : if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) {
393 1176942 : fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
394 1176942 : fd_sha256_core( state, buf, 1UL );
395 1176942 : buf_used = 0UL;
396 1176942 : }
397 :
398 133173377 : ulong bit_cnt = sz << 3;
399 133173377 : fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
400 133173377 : FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
401 133173377 : fd_sha256_core( state, buf, 1UL );
402 :
403 133173377 : state[0] = fd_uint_bswap( state[0] );
404 133173377 : state[1] = fd_uint_bswap( state[1] );
405 133173377 : state[2] = fd_uint_bswap( state[2] );
406 133173377 : state[3] = fd_uint_bswap( state[3] );
407 133173377 : state[4] = fd_uint_bswap( state[4] );
408 133173377 : state[5] = fd_uint_bswap( state[5] );
409 133173377 : state[6] = fd_uint_bswap( state[6] );
410 133173377 : state[7] = fd_uint_bswap( state[7] );
411 133173377 : return memcpy( _hash, state, 32 );
412 133173377 : }
413 :
414 : void *
415 : fd_sha256_hash_32( void const * _data,
416 315071994 : void * _hash ) {
417 315071994 : uchar const * data = (uchar const *)_data;
418 :
419 : /* This is just the above streamlined to eliminate all the overheads
420 : to support incremental hashing. */
421 :
422 315071994 : uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ] __attribute__((aligned(128)));
423 315071994 : uint state[8] __attribute__((aligned(32)));
424 :
425 315071994 : state[0] = 0x6a09e667U;
426 315071994 : state[1] = 0xbb67ae85U;
427 315071994 : state[2] = 0x3c6ef372U;
428 315071994 : state[3] = 0xa54ff53aU;
429 315071994 : state[4] = 0x510e527fU;
430 315071994 : state[5] = 0x9b05688cU;
431 315071994 : state[6] = 0x1f83d9abU;
432 315071994 : state[7] = 0x5be0cd19U;
433 :
434 315071994 : ulong sz = 32;
435 :
436 315071994 : ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
437 315071994 : if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt );
438 :
439 315071994 : ulong buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL);
440 315071994 : if( FD_UNLIKELY( buf_used ) ) memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
441 315071994 : buf[ buf_used ] = (uchar)0x80;
442 315071994 : buf_used++;
443 :
444 315071994 : if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) {
445 0 : memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
446 0 : fd_sha256_core( state, buf, 1UL );
447 0 : buf_used = 0UL;
448 0 : }
449 :
450 315071994 : ulong bit_cnt = sz << 3;
451 315071994 : memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
452 315071994 : FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
453 315071994 : fd_sha256_core( state, buf, 1UL );
454 :
455 315071994 : state[0] = fd_uint_bswap( state[0] );
456 315071994 : state[1] = fd_uint_bswap( state[1] );
457 315071994 : state[2] = fd_uint_bswap( state[2] );
458 315071994 : state[3] = fd_uint_bswap( state[3] );
459 315071994 : state[4] = fd_uint_bswap( state[4] );
460 315071994 : state[5] = fd_uint_bswap( state[5] );
461 315071994 : state[6] = fd_uint_bswap( state[6] );
462 315071994 : state[7] = fd_uint_bswap( state[7] );
463 315071994 : return memcpy( _hash, state, 32 );
464 315071994 : }
465 :
466 : #undef fd_sha256_core
|