LCOV - code coverage report
Current view: top level - ballet/sha256 - fd_sha256.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 363 370 98.1 %
Date: 2026-09-10 04:29:43 Functions: 17 17 100.0 %

          Line data    Source code
       1             : #include "fd_sha256.h"
       2             : #include "fd_sha256_constants.h"
       3             : 
       4             : #if FD_HAS_SHANI
       5             : /* For the optimized repeated hash */
       6             : #include "../../util/simd/fd_sse.h"
       7             : #endif
       8             : 
       9             : ulong
      10      931047 : fd_sha256_align( void ) {
      11      931047 :   return FD_SHA256_ALIGN;
      12      931047 : }
      13             : 
      14             : ulong
      15      465513 : fd_sha256_footprint( void ) {
      16      465513 :   return FD_SHA256_FOOTPRINT;
      17      465513 : }
      18             : 
      19             : void *
      20      465516 : fd_sha256_new( void * shmem ) {
      21      465516 :   fd_sha256_t * sha = (fd_sha256_t *)shmem;
      22             : 
      23      465516 :   if( FD_UNLIKELY( !shmem ) ) {
      24           3 :     FD_LOG_WARNING(( "NULL shmem" ));
      25           3 :     return NULL;
      26           3 :   }
      27             : 
      28      465513 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_sha256_align() ) ) ) {
      29           3 :     FD_LOG_WARNING(( "misaligned shmem" ));
      30           3 :     return NULL;
      31           3 :   }
      32             : 
      33      465510 :   ulong footprint = fd_sha256_footprint();
      34             : 
      35      465510 :   fd_memset( sha, 0, footprint );
      36             : 
      37      465510 :   FD_COMPILER_MFENCE();
      38      465510 :   FD_VOLATILE( sha->magic ) = FD_SHA256_MAGIC;
      39      465510 :   FD_COMPILER_MFENCE();
      40             : 
      41      465510 :   return (void *)sha;
      42      465513 : }
      43             : 
      44             : fd_sha256_t *
      45      465516 : fd_sha256_join( void * shsha ) {
      46             : 
      47      465516 :   if( FD_UNLIKELY( !shsha ) ) {
      48           3 :     FD_LOG_WARNING(( "NULL shsha" ));
      49           3 :     return NULL;
      50           3 :   }
      51             : 
      52      465513 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shsha, fd_sha256_align() ) ) ) {
      53           3 :     FD_LOG_WARNING(( "misaligned shsha" ));
      54           3 :     return NULL;
      55           3 :   }
      56             : 
      57      465510 :   fd_sha256_t * sha = (fd_sha256_t *)shsha;
      58             : 
      59      465510 :   if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
      60           0 :     FD_LOG_WARNING(( "bad magic" ));
      61           0 :     return NULL;
      62           0 :   }
      63             : 
      64      465510 :   return sha;
      65      465510 : }
      66             : 
      67             : void *
      68          18 : fd_sha256_leave( fd_sha256_t * sha ) {
      69             : 
      70          18 :   if( FD_UNLIKELY( !sha ) ) {
      71           3 :     FD_LOG_WARNING(( "NULL sha" ));
      72           3 :     return NULL;
      73           3 :   }
      74             : 
      75          15 :   return (void *)sha;
      76          18 : }
      77             : 
      78             : void *
      79          21 : fd_sha256_delete( void * shsha ) {
      80             : 
      81          21 :   if( FD_UNLIKELY( !shsha ) ) {
      82           3 :     FD_LOG_WARNING(( "NULL shsha" ));
      83           3 :     return NULL;
      84           3 :   }
      85             : 
      86          18 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shsha, fd_sha256_align() ) ) ) {
      87           3 :     FD_LOG_WARNING(( "misaligned shsha" ));
      88           3 :     return NULL;
      89           3 :   }
      90             : 
      91          15 :   fd_sha256_t * sha = (fd_sha256_t *)shsha;
      92             : 
      93          15 :   if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
      94           0 :     FD_LOG_WARNING(( "bad magic" ));
      95           0 :     return NULL;
      96           0 :   }
      97             : 
      98          15 :   FD_COMPILER_MFENCE();
      99          15 :   FD_VOLATILE( sha->magic ) = 0UL;
     100          15 :   FD_COMPILER_MFENCE();
     101             : 
     102          15 :   return (void *)sha;
     103          15 : }
     104             : 
     105             : #ifndef FD_SHA256_CORE_IMPL
     106             : #if FD_HAS_ARM_SHA256
     107             : #define FD_SHA256_CORE_IMPL 2
     108             : #elif FD_HAS_SHANI
     109             : #define FD_SHA256_CORE_IMPL 1
     110             : #else
     111             : #define FD_SHA256_CORE_IMPL 0
     112             : #endif
     113             : #endif
     114             : 
     115             : #if FD_SHA256_CORE_IMPL==0
     116             : 
     117             : /* The implementation below was derived from OpenSSL's SHA-256
     118             :    implementation (Apache-2.0 licensed).  See in particular:
     119             : 
     120             :     https://github.com/openssl/openssl/blob/master/crypto/sha/sha256.c
     121             : 
     122             :    (link valid circa 2022-Dec).  It has been made more strict with more
     123             :    extensive implementation documentation, has been simplified and has
     124             :    been streamlined specifically for use inside Firedancer base machine
     125             :    model (no machine specific capabilities required).
     126             : 
     127             :    In particular, fd_sha256_core_ref is based on OpenSSL's
     128             :    OPENSSL_SMALL_FOOTPRINT SHA-256 implementation (Apache licensed).
     129             :    This should work anywhere but it is not the highest performance
     130             :    implementation possible.
     131             : 
     132             :    It is also straightforward to replace these implementations with HPC
     133             :    implementations that target specific machine capabilities without
     134             :    requiring any changes to caller code. */
     135             : 
     136             : static void
     137             : fd_sha256_core_ref( uint *        state,
     138             :                     uchar const * block,
     139    38197850 :                     ulong         block_cnt ) {
     140             : 
     141             : 
     142 22325984640 : # define ROTATE     fd_uint_rotate_left
     143  2480664960 : # define Sigma0(x)  (ROTATE((x),30) ^ ROTATE((x),19) ^ ROTATE((x),10))
     144  2480664960 : # define Sigma1(x)  (ROTATE((x),26) ^ ROTATE((x),21) ^ ROTATE((x),7))
     145  1860498720 : # define sigma0(x)  (ROTATE((x),25) ^ ROTATE((x),14) ^ ((x)>>3))
     146  1860498720 : # define sigma1(x)  (ROTATE((x),15) ^ ROTATE((x),13) ^ ((x)>>10))
     147  2480664960 : # define Ch(x,y,z)  (((x) & (y)) ^ ((~(x)) & (z)))
     148  2480664960 : # define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
     149             : 
     150    38197850 :   uchar const * W = block;
     151    38760390 :   do {
     152    38760390 :     uint a = state[0];
     153    38760390 :     uint b = state[1];
     154    38760390 :     uint c = state[2];
     155    38760390 :     uint d = state[3];
     156    38760390 :     uint e = state[4];
     157    38760390 :     uint f = state[5];
     158    38760390 :     uint g = state[6];
     159    38760390 :     uint h = state[7];
     160             : 
     161    38760390 :     uint X[16];
     162             : 
     163    38760390 :     ulong i;
     164   658926630 :     for( i=0UL; i<16UL; i++ ) {
     165   620166240 :       X[i] = fd_uint_bswap( FD_LOAD( uint, W + i*sizeof(uint) ) );
     166   620166240 :       uint T1 = X[i] + h + Sigma1(e) + Ch(e, f, g) + fd_sha256_K[i];
     167   620166240 :       uint T2 = Sigma0(a) + Maj(a, b, c);
     168   620166240 :       h = g;
     169   620166240 :       g = f;
     170   620166240 :       f = e;
     171   620166240 :       e = d + T1;
     172   620166240 :       d = c;
     173   620166240 :       c = b;
     174   620166240 :       b = a;
     175   620166240 :       a = T1 + T2;
     176   620166240 :     }
     177  1899259110 :     for( ; i<64UL; i++ ) {
     178  1860498720 :       uint s0 = X[(i +  1UL) & 0x0fUL];
     179  1860498720 :       uint s1 = X[(i + 14UL) & 0x0fUL];
     180  1860498720 :       s0 = sigma0(s0);
     181  1860498720 :       s1 = sigma1(s1);
     182  1860498720 :       X[i & 0xfUL] += s0 + s1 + X[(i + 9UL) & 0xfUL];
     183  1860498720 :       uint T1 = X[i & 0xfUL ] + h + Sigma1(e) + Ch(e, f, g) + fd_sha256_K[i];
     184  1860498720 :       uint T2 = Sigma0(a) + Maj(a, b, c);
     185  1860498720 :       h = g;
     186  1860498720 :       g = f;
     187  1860498720 :       f = e;
     188  1860498720 :       e = d + T1;
     189  1860498720 :       d = c;
     190  1860498720 :       c = b;
     191  1860498720 :       b = a;
     192  1860498720 :       a = T1 + T2;
     193  1860498720 :     }
     194             : 
     195    38760390 :     state[0] += a;
     196    38760390 :     state[1] += b;
     197    38760390 :     state[2] += c;
     198    38760390 :     state[3] += d;
     199    38760390 :     state[4] += e;
     200    38760390 :     state[5] += f;
     201    38760390 :     state[6] += g;
     202    38760390 :     state[7] += h;
     203             : 
     204    38760390 :     W += 16UL*sizeof(uint);
     205    38760390 :   } while( --block_cnt );
     206             : 
     207    38197850 : # undef ROTATE
     208    38197850 : # undef Sigma0
     209    38197850 : # undef Sigma1
     210    38197850 : # undef sigma0
     211    38197850 : # undef sigma1
     212    38197850 : # undef Ch
     213    38197850 : # undef Maj
     214             : 
     215    38197850 : }
     216             : 
     217    38197850 : #define fd_sha256_core fd_sha256_core_ref
     218             : 
     219             : #elif FD_SHA256_CORE_IMPL==1
     220             : 
     221             : /* _mm_sha256rnds2_epu32 does two rounds, one from the first uint in
     222             :    wk and one from the second.  Since wk stores four rounds worth of
     223             :    message schedule values, it makes sense for the macro to do four
     224             :    rounds at a time.  We need to permute wk in between so that the
     225             :    second call to the intrinsic will use the other values. */
     226   324376016 : #define FOUR_ROUNDS( wk ) do {                                                               \
     227   324376016 :       vu_t __wk = (wk);                                                                      \
     228   324376016 :       vu_t temp_state = stateFEBA;                                                           \
     229   324376016 :       stateFEBA = _mm_sha256rnds2_epu32( stateHGDC, stateFEBA, __wk );                       \
     230   324376016 :       stateHGDC = temp_state;                                                                \
     231   324376016 :                                                                                              \
     232   324376016 :       temp_state = stateFEBA;                                                                \
     233   324376016 :       stateFEBA = _mm_sha256rnds2_epu32( stateHGDC, stateFEBA, vu_permute( __wk, 2,3,0,1 ) );\
     234   324376016 :       stateHGDC = temp_state;                                                                \
     235   324376016 :     } while( 0 )
     236             : 
     237             : 
     238             : /* For completeness, here's the documentation for _mm_sha256msg1_epu32
     239             :    and _mm_sha256msg2_epu32 in a slightly reformatted way, where all
     240             :    values are uints, and "-" indicates a don't-care value:
     241             : 
     242             :        _mm_sha256msg1_epu32( (w[j  ], w[j+1], w[j+1], w[j+3]),
     243             :                              (w[j+4], -,      -,      -     ) )
     244             :          = ( w[j  ]+s0( w[j+1] ),  w[j+1]+s0( w[j+2] ),
     245             :              w[j+2]+s0( w[j+3] ),  w[j+3]+s0( w[j+4] ) ).
     246             : 
     247             : 
     248             :        _mm_sha256msg2_epu32( (v[j  ], v[j+1], v[j+1], v[j+3]),
     249             :                              (-,      -,      w[j-2], w[j-1]) )
     250             :          sets w[j  ] = v[j  ] + s1( w[j-2] ) and
     251             :               w[j+1] = v[j+1] + s1( w[j-1] ), and then returns
     252             : 
     253             :            ( v[j  ]+s1( w[j-2] ), v[j+1]+s1( w[j-1] ),
     254             :              v[j+2]+s1( w[j  ] ), v[j+3]+s1( w[j+1] ) )   */
     255             : 
     256             : 
     257             : /* w[i] for i>= 16 is w[i-16] + s0(w[i-15]) + w[i-7] + s1(w[i-2])
     258             :    Since our vector size is 4 uints, it's only s1 that is a little
     259             :    problematic, because it references items in the same vector.
     260             :    Thankfully, the msg2 intrinsic takes care of the complexity, but we
     261             :    need to execute it last.
     262             : 
     263             :    We get w[i-16] and s0(s[i-15]) using the msg1 intrinsic, setting j =
     264             :    i-16.  For example, to compute w1013, we pass in w0003 and w0407.
     265             :    Then we can get w[i-7] by using the alignr instruction on
     266             :    (w[i-8], w[i-7], w[i-6], w[i-5]) and (w[i-4], w[i-3], w[i-2], w[i-1])
     267             :    to concatenate them and shift by one uint.  Continuing with the
     268             :    example of w1013, we need w080b and w0c0f.  We then put
     269             :              v[i] = w[i-16] + s0(w[i-15]) + w[i-7],
     270             :    and invoke the msg2 intrinsic with j=i, which gives w[i], as desired.
     271             :    Each invocation of NEXT_W computes 4 values of w. */
     272             : 
     273   243282012 : #define NEXT_W( w_minus_16, w_minus_12, w_minus_8, w_minus_4 ) (__extension__({      \
     274   243282012 :     vu_t __w_i_16_s0_i_15 = _mm_sha256msg1_epu32( w_minus_16, w_minus_12 );          \
     275   243282012 :     vu_t __w_i_7          = _mm_alignr_epi8( w_minus_4, w_minus_8, 4 );              \
     276   243282012 :     _mm_sha256msg2_epu32( vu_add( __w_i_7, __w_i_16_s0_i_15 ), w_minus_4 );          \
     277   243282012 :     }))
     278             : 
     279             : /* Zen 5's sha256rnds2 has an RTP of 2, while Zen 4's has an RTP of 1. We can
     280             :    win some performance by moving the schedule updates earlier in the loop,
     281             :    which improves the speed by around 1M hashes/s for the repeated hashing. */
     282             : #ifdef __znver5__
     283             : #define FULL_ROUNDS() do {                                                                                        \
     284             :     vu_t w1013 = NEXT_W( w0003, w0407, w080b, w0c0f ); FOUR_ROUNDS( vu_add( w0003, vu_ld( fd_sha256_K+ 0UL ) ) ); \
     285             :     vu_t w1417 = NEXT_W( w0407, w080b, w0c0f, w1013 ); FOUR_ROUNDS( vu_add( w0407, vu_ld( fd_sha256_K+ 4UL ) ) ); \
     286             :     vu_t w181b = NEXT_W( w080b, w0c0f, w1013, w1417 ); FOUR_ROUNDS( vu_add( w080b, vu_ld( fd_sha256_K+ 8UL ) ) ); \
     287             :     vu_t w1c1f = NEXT_W( w0c0f, w1013, w1417, w181b ); FOUR_ROUNDS( vu_add( w0c0f, vu_ld( fd_sha256_K+12UL ) ) ); \
     288             :     vu_t w2023 = NEXT_W( w1013, w1417, w181b, w1c1f ); FOUR_ROUNDS( vu_add( w1013, vu_ld( fd_sha256_K+16UL ) ) ); \
     289             :     vu_t w2427 = NEXT_W( w1417, w181b, w1c1f, w2023 ); FOUR_ROUNDS( vu_add( w1417, vu_ld( fd_sha256_K+20UL ) ) ); \
     290             :     vu_t w282b = NEXT_W( w181b, w1c1f, w2023, w2427 ); FOUR_ROUNDS( vu_add( w181b, vu_ld( fd_sha256_K+24UL ) ) ); \
     291             :     vu_t w2c2f = NEXT_W( w1c1f, w2023, w2427, w282b ); FOUR_ROUNDS( vu_add( w1c1f, vu_ld( fd_sha256_K+28UL ) ) ); \
     292             :     vu_t w3033 = NEXT_W( w2023, w2427, w282b, w2c2f ); FOUR_ROUNDS( vu_add( w2023, vu_ld( fd_sha256_K+32UL ) ) ); \
     293             :     vu_t w3437 = NEXT_W( w2427, w282b, w2c2f, w3033 ); FOUR_ROUNDS( vu_add( w2427, vu_ld( fd_sha256_K+36UL ) ) ); \
     294             :     vu_t w383b = NEXT_W( w282b, w2c2f, w3033, w3437 ); FOUR_ROUNDS( vu_add( w282b, vu_ld( fd_sha256_K+40UL ) ) ); \
     295             :     vu_t w3c3f = NEXT_W( w2c2f, w3033, w3437, w383b ); FOUR_ROUNDS( vu_add( w2c2f, vu_ld( fd_sha256_K+44UL ) ) ); \
     296             :     /*                                              */ FOUR_ROUNDS( vu_add( w3033, vu_ld( fd_sha256_K+48UL ) ) ); \
     297             :     /*                                              */ FOUR_ROUNDS( vu_add( w3437, vu_ld( fd_sha256_K+52UL ) ) ); \
     298             :     /*                                              */ FOUR_ROUNDS( vu_add( w383b, vu_ld( fd_sha256_K+56UL ) ) ); \
     299             :     /*                                              */ FOUR_ROUNDS( vu_add( w3c3f, vu_ld( fd_sha256_K+60UL ) ) ); \
     300             :     } while ( 0 )
     301             : #else
     302    20273501 : #define FULL_ROUNDS() do {                                                                                        \
     303    20273501 :     /*                                              */ FOUR_ROUNDS( vu_add( w0003, vu_ld( fd_sha256_K+ 0UL ) ) ); \
     304    20273501 :     /*                                              */ FOUR_ROUNDS( vu_add( w0407, vu_ld( fd_sha256_K+ 4UL ) ) ); \
     305    20273501 :     /*                                              */ FOUR_ROUNDS( vu_add( w080b, vu_ld( fd_sha256_K+ 8UL ) ) ); \
     306    20273501 :     /*                                              */ FOUR_ROUNDS( vu_add( w0c0f, vu_ld( fd_sha256_K+12UL ) ) ); \
     307    20273501 :     vu_t w1013 = NEXT_W( w0003, w0407, w080b, w0c0f ); FOUR_ROUNDS( vu_add( w1013, vu_ld( fd_sha256_K+16UL ) ) ); \
     308    20273501 :     vu_t w1417 = NEXT_W( w0407, w080b, w0c0f, w1013 ); FOUR_ROUNDS( vu_add( w1417, vu_ld( fd_sha256_K+20UL ) ) ); \
     309    20273501 :     vu_t w181b = NEXT_W( w080b, w0c0f, w1013, w1417 ); FOUR_ROUNDS( vu_add( w181b, vu_ld( fd_sha256_K+24UL ) ) ); \
     310    20273501 :     vu_t w1c1f = NEXT_W( w0c0f, w1013, w1417, w181b ); FOUR_ROUNDS( vu_add( w1c1f, vu_ld( fd_sha256_K+28UL ) ) ); \
     311    20273501 :     vu_t w2023 = NEXT_W( w1013, w1417, w181b, w1c1f ); FOUR_ROUNDS( vu_add( w2023, vu_ld( fd_sha256_K+32UL ) ) ); \
     312    20273501 :     vu_t w2427 = NEXT_W( w1417, w181b, w1c1f, w2023 ); FOUR_ROUNDS( vu_add( w2427, vu_ld( fd_sha256_K+36UL ) ) ); \
     313    20273501 :     vu_t w282b = NEXT_W( w181b, w1c1f, w2023, w2427 ); FOUR_ROUNDS( vu_add( w282b, vu_ld( fd_sha256_K+40UL ) ) ); \
     314    20273501 :     vu_t w2c2f = NEXT_W( w1c1f, w2023, w2427, w282b ); FOUR_ROUNDS( vu_add( w2c2f, vu_ld( fd_sha256_K+44UL ) ) ); \
     315    20273501 :     vu_t w3033 = NEXT_W( w2023, w2427, w282b, w2c2f ); FOUR_ROUNDS( vu_add( w3033, vu_ld( fd_sha256_K+48UL ) ) ); \
     316    20273501 :     vu_t w3437 = NEXT_W( w2427, w282b, w2c2f, w3033 ); FOUR_ROUNDS( vu_add( w3437, vu_ld( fd_sha256_K+52UL ) ) ); \
     317    20273501 :     vu_t w383b = NEXT_W( w282b, w2c2f, w3033, w3437 ); FOUR_ROUNDS( vu_add( w383b, vu_ld( fd_sha256_K+56UL ) ) ); \
     318    20273501 :     vu_t w3c3f = NEXT_W( w2c2f, w3033, w3437, w383b ); FOUR_ROUNDS( vu_add( w3c3f, vu_ld( fd_sha256_K+60UL ) ) ); \
     319    20273501 :     } while ( 0 )
     320             : #endif
     321             : 
     322             : 
     323             : void
     324             : fd_sha256_core_shaext( uint *        state,       /* 64-byte aligned, 8 entries */
     325             :                        uchar const * block,       /* ideally 128-byte aligned (but not required), 64*block_cnt in size */
     326    16373152 :                        ulong         block_cnt ) {/* positive */
     327    16373152 :   vu_t stateABCD = vu_ld( state     );
     328    16373152 :   vu_t stateEFGH = vu_ld( state+4UL );
     329             : 
     330    16373152 :   vu_t baseFEBA = vu_permute2( stateEFGH, stateABCD, 1, 0, 1, 0 );
     331    16373152 :   vu_t baseHGDC = vu_permute2( stateEFGH, stateABCD, 3, 2, 3, 2 );
     332             : 
     333    33032517 :   for( ulong b=0UL; b<block_cnt; b++ ) {
     334    16659365 :     vu_t stateFEBA = baseFEBA;
     335    16659365 :     vu_t stateHGDC = baseHGDC;
     336             : 
     337    16659365 :     vu_t w0003 = vu_bswap( vu_ldu( block+64UL*b      ) );
     338    16659365 :     vu_t w0407 = vu_bswap( vu_ldu( block+64UL*b+16UL ) );
     339    16659365 :     vu_t w080b = vu_bswap( vu_ldu( block+64UL*b+32UL ) );
     340    16659365 :     vu_t w0c0f = vu_bswap( vu_ldu( block+64UL*b+48UL ) );
     341             : 
     342    16659365 :     FULL_ROUNDS();
     343             : 
     344    16659365 :     baseFEBA = vu_add( baseFEBA, stateFEBA );
     345    16659365 :     baseHGDC = vu_add( baseHGDC, stateHGDC );
     346             : 
     347    16659365 :   }
     348             : 
     349    16373152 :   stateABCD = vu_permute2( baseFEBA, baseHGDC, 3, 2, 3, 2 );
     350    16373152 :   stateEFGH = vu_permute2( baseFEBA, baseHGDC, 1, 0, 1, 0 );
     351    16373152 :   vu_st( state,     stateABCD );
     352    16373152 :   vu_st( state+4UL, stateEFGH );
     353    16373152 : }
     354             : 
     355    16373152 : #define fd_sha256_core fd_sha256_core_shaext
     356             : 
     357             : #elif FD_SHA256_CORE_IMPL==2
     358             : 
     359             : void
     360             : fd_sha256_core_arm( uint *        state,
     361             :                     uchar const * block,
     362             :                     ulong         block_cnt );
     363             : 
     364             : #define fd_sha256_core fd_sha256_core_arm
     365             : 
     366             : #else
     367             : #error "Unsupported FD_SHA256_CORE_IMPL"
     368             : #endif
     369             : 
     370             : fd_sha256_t *
     371      963054 : fd_sha256_init( fd_sha256_t * sha ) {
     372      963054 :   sha->state[0] = FD_SHA256_INITIAL_A;
     373      963054 :   sha->state[1] = FD_SHA256_INITIAL_B;
     374      963054 :   sha->state[2] = FD_SHA256_INITIAL_C;
     375      963054 :   sha->state[3] = FD_SHA256_INITIAL_D;
     376      963054 :   sha->state[4] = FD_SHA256_INITIAL_E;
     377      963054 :   sha->state[5] = FD_SHA256_INITIAL_F;
     378      963054 :   sha->state[6] = FD_SHA256_INITIAL_G;
     379      963054 :   sha->state[7] = FD_SHA256_INITIAL_H;
     380      963054 :   sha->buf_used = 0UL;
     381      963054 :   sha->bit_cnt  = 0UL;
     382      963054 :   return sha;
     383      963054 : }
     384             : 
     385             : fd_sha256_t *
     386             : fd_sha256_append( fd_sha256_t * sha,
     387             :                   void const *  _data,
     388     2010642 :                   ulong         sz ) {
     389             : 
     390             :   /* If no data to append, we are done */
     391             : 
     392     2010642 :   if( FD_UNLIKELY( !sz ) ) return sha; /* optimize for non-trivial append */
     393             : 
     394             :   /* Unpack inputs */
     395             : 
     396     2010396 :   uint *  state    = sha->state;
     397     2010396 :   uchar * buf      = sha->buf;
     398     2010396 :   ulong   buf_used = sha->buf_used;
     399     2010396 :   ulong   bit_cnt  = sha->bit_cnt;
     400             : 
     401     2010396 :   uchar const * data = (uchar const *)_data;
     402             : 
     403             :   /* Update bit_cnt */
     404             :   /* FIXME: could accumulate bytes here and do bit conversion in append */
     405             :   /* FIXME: Overflow handling if more than 2^64 bits (unlikely) */
     406             : 
     407     2010396 :   sha->bit_cnt = bit_cnt + (sz<<3);
     408             : 
     409             :   /* Handle buffered bytes from previous appends */
     410             : 
     411     2010396 :   if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
     412             : 
     413             :     /* If the append isn't large enough to complete the current block,
     414             :        buffer these bytes too and return */
     415             : 
     416      110349 :     ulong buf_rem = FD_SHA256_PRIVATE_BUF_MAX - buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
     417      110349 :     if( FD_UNLIKELY( sz < buf_rem ) ) { /* optimize for large append */
     418       27285 :       fd_memcpy( buf + buf_used, data, sz );
     419       27285 :       sha->buf_used = buf_used + sz;
     420       27285 :       return sha;
     421       27285 :     }
     422             : 
     423             :     /* Otherwise, buffer enough leading bytes of data to complete the
     424             :        block, update the hash and then continue processing any remaining
     425             :        bytes of data. */
     426             : 
     427       83064 :     fd_memcpy( buf + buf_used, data, buf_rem );
     428       83064 :     data += buf_rem;
     429       83064 :     sz   -= buf_rem;
     430             : 
     431       83064 :     fd_sha256_core( state, buf, 1UL );
     432       83064 :     sha->buf_used = 0UL;
     433       83064 :   }
     434             : 
     435             :   /* Append the bulk of the data */
     436             : 
     437     1983111 :   ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
     438     1983111 :   if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt ); /* optimized for large append */
     439             : 
     440             :   /* Buffer any leftover bytes */
     441             : 
     442     1983111 :   buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL); /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
     443     1983111 :   if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
     444     1046052 :     fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
     445     1046052 :     sha->buf_used = buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
     446     1046052 :   }
     447             : 
     448     1983111 :   return sha;
     449     2010396 : }
     450             : 
     451             : void *
     452             : fd_sha256_fini( fd_sha256_t * sha,
     453     1023819 :                 void *        _hash ) {
     454             : 
     455             :   /* Unpack inputs */
     456             : 
     457     1023819 :   uint *  state    = sha->state;
     458     1023819 :   uchar * buf      = sha->buf;
     459     1023819 :   ulong   buf_used = sha->buf_used; /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
     460     1023819 :   ulong   bit_cnt  = sha->bit_cnt;
     461             : 
     462             :   /* Append the terminating message byte */
     463             : 
     464     1023819 :   buf[ buf_used ] = (uchar)0x80;
     465     1023819 :   buf_used++;
     466             : 
     467             :   /* If there isn't enough room to save the message length in bits at
     468             :      the end of the in progress block, clear the rest of the in progress
     469             :      block, update the hash and start a new block. */
     470             : 
     471     1023819 :   if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) { /* optimize for well aligned use of append */
     472       12342 :     fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
     473       12342 :     fd_sha256_core( state, buf, 1UL );
     474       12342 :     buf_used = 0UL;
     475       12342 :   }
     476             : 
     477             :   /* Clear in progress block up to last 64-bits, append the message
     478             :      size in bytes in the last 64-bits of the in progress block and
     479             :      update the hash to finalize it. */
     480             : 
     481     1023819 :   fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     482     1023819 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     483     1023819 :   fd_sha256_core( state, buf, 1UL );
     484             : 
     485             :   /* Unpack the result into md (annoying bswaps here) */
     486             : 
     487     1023819 :   state[0] = fd_uint_bswap( state[0] );
     488     1023819 :   state[1] = fd_uint_bswap( state[1] );
     489     1023819 :   state[2] = fd_uint_bswap( state[2] );
     490     1023819 :   state[3] = fd_uint_bswap( state[3] );
     491     1023819 :   state[4] = fd_uint_bswap( state[4] );
     492     1023819 :   state[5] = fd_uint_bswap( state[5] );
     493     1023819 :   state[6] = fd_uint_bswap( state[6] );
     494     1023819 :   state[7] = fd_uint_bswap( state[7] );
     495     1023819 :   return memcpy( _hash, state, 32 );
     496     1023819 : }
     497             : 
     498             : void *
     499             : fd_sha256_hash( void const * _data,
     500             :                 ulong        sz,
     501    30851186 :                 void *       _hash ) {
     502    30851186 :   uchar const * data = (uchar const *)_data;
     503             : 
     504             :   /* This is just the above streamlined to eliminate all the overheads
     505             :      to support incremental hashing. */
     506             : 
     507    30851186 :   uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ] __attribute__((aligned(128)));
     508    30851186 :   uint  state[8] __attribute__((aligned(32)));
     509             : 
     510    30851186 :   state[0] = FD_SHA256_INITIAL_A;
     511    30851186 :   state[1] = FD_SHA256_INITIAL_B;
     512    30851186 :   state[2] = FD_SHA256_INITIAL_C;
     513    30851186 :   state[3] = FD_SHA256_INITIAL_D;
     514    30851186 :   state[4] = FD_SHA256_INITIAL_E;
     515    30851186 :   state[5] = FD_SHA256_INITIAL_F;
     516    30851186 :   state[6] = FD_SHA256_INITIAL_G;
     517    30851186 :   state[7] = FD_SHA256_INITIAL_H;
     518             : 
     519    30851186 :   ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
     520    30851186 :   if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt );
     521             : 
     522    30851186 :   ulong buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL);
     523    30851186 :   if( FD_UNLIKELY( buf_used ) ) fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
     524    30851186 :   buf[ buf_used ] = (uchar)0x80;
     525    30851186 :   buf_used++;
     526             : 
     527    30851186 :   if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) {
     528      147874 :     fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
     529      147874 :     fd_sha256_core( state, buf, 1UL );
     530      147874 :     buf_used = 0UL;
     531      147874 :   }
     532             : 
     533    30851186 :   ulong bit_cnt = sz << 3;
     534    30851186 :   fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     535    30851186 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     536    30851186 :   fd_sha256_core( state, buf, 1UL );
     537             : 
     538    30851186 :   state[0] = fd_uint_bswap( state[0] );
     539    30851186 :   state[1] = fd_uint_bswap( state[1] );
     540    30851186 :   state[2] = fd_uint_bswap( state[2] );
     541    30851186 :   state[3] = fd_uint_bswap( state[3] );
     542    30851186 :   state[4] = fd_uint_bswap( state[4] );
     543    30851186 :   state[5] = fd_uint_bswap( state[5] );
     544    30851186 :   state[6] = fd_uint_bswap( state[6] );
     545    30851186 :   state[7] = fd_uint_bswap( state[7] );
     546    30851186 :   return memcpy( _hash, state, 32 );
     547    30851186 : }
     548             : 
     549             : 
     550             : 
     551             : #if FD_SHA256_CORE_IMPL==2
     552             : void
     553             : fd_sha256_hash_32_repeated_arm( uchar const * data,
     554             :                                 uchar *       hash,
     555             :                                 ulong         cnt );
     556             : #endif
     557             : 
     558             : void *
     559             : fd_sha256_hash_32_repeated( void const * _data,
     560             :                             void *       _hash,
     561       11943 :                             ulong        cnt ) {
     562             : #if FD_SHA256_CORE_IMPL==2
     563             :   fd_sha256_hash_32_repeated_arm( _data, _hash, cnt );
     564             :   return _hash;
     565             : #elif FD_SHA256_CORE_IMPL==1
     566             : 
     567        9785 :   uchar const * data = (uchar const *)_data;
     568        9785 :   uchar       * hash = (uchar       *)_hash;
     569             : 
     570        9785 :   vu_t       w0003 = vu_bswap( vu_ldu( data      ) );
     571        9785 :   vu_t       w0407 = vu_bswap( vu_ldu( data+16UL ) );
     572        9785 :   vb_t const w080b = vb( 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
     573        9785 :                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 );
     574        9785 :   vb_t const w0c0f = vb( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     575        9785 :                          0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 ); /* 32 bytes */
     576             : 
     577        9785 :   vu_t const initialFEBA = vu( FD_SHA256_INITIAL_F, FD_SHA256_INITIAL_E, FD_SHA256_INITIAL_B, FD_SHA256_INITIAL_A );
     578        9785 :   vu_t const initialHGDC = vu( FD_SHA256_INITIAL_H, FD_SHA256_INITIAL_G, FD_SHA256_INITIAL_D, FD_SHA256_INITIAL_C );
     579             : 
     580     3623921 :   for( ulong iter=0UL; iter<cnt; iter++ ) {
     581     3614136 :     vu_t stateFEBA = initialFEBA;
     582     3614136 :     vu_t stateHGDC = initialHGDC;
     583             : 
     584     3614136 :     FULL_ROUNDS();
     585             : 
     586     3614136 :     stateFEBA = vu_add( stateFEBA, initialFEBA );
     587     3614136 :     stateHGDC = vu_add( stateHGDC, initialHGDC );
     588             : 
     589     3614136 :     vu_t stateABCD = vu_permute2( stateFEBA, stateHGDC, 3, 2, 3, 2 );
     590     3614136 :     vu_t stateEFGH = vu_permute2( stateFEBA, stateHGDC, 1, 0, 1, 0 );
     591             : 
     592     3614136 :     w0003 = stateABCD;
     593     3614136 :     w0407 = stateEFGH;
     594     3614136 :   }
     595        9785 :   vu_stu( hash,      vu_bswap( w0003 ) );
     596        9785 :   vu_stu( hash+16UL, vu_bswap( w0407 ) );
     597        9785 : #undef NEXT_W
     598        9785 : #undef FOUR_ROUNDS
     599        9785 : #undef FULL_ROUNDS
     600             : 
     601             : #else
     602             : 
     603        2158 :   uchar const * data = (uchar const *)_data;
     604        2158 :   uchar       * hash = (uchar       *)_hash;
     605             : 
     606        2158 :   uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ] __attribute__((aligned(128)));
     607             : 
     608             :   /* Prepare padding once */
     609        2158 :   ulong buf_used = 32UL;
     610        2158 :   memcpy( buf, data, 32UL );
     611        2158 :   buf[ buf_used ] = (uchar)0x80;
     612        2158 :   buf_used++;
     613             : 
     614        2158 :   ulong bit_cnt = 32UL << 3;
     615        2158 :   memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     616        2158 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     617             : 
     618             :   /* This is just the above streamlined to eliminate all the overheads
     619             :      to support incremental hashing. */
     620     5505604 :   for( ulong iter=0UL; iter<cnt; iter++ ) {
     621             : 
     622     5503446 :     uint  state[8] __attribute__((aligned(32)));
     623             : 
     624     5503446 :     state[0] = FD_SHA256_INITIAL_A;
     625     5503446 :     state[1] = FD_SHA256_INITIAL_B;
     626     5503446 :     state[2] = FD_SHA256_INITIAL_C;
     627     5503446 :     state[3] = FD_SHA256_INITIAL_D;
     628     5503446 :     state[4] = FD_SHA256_INITIAL_E;
     629     5503446 :     state[5] = FD_SHA256_INITIAL_F;
     630     5503446 :     state[6] = FD_SHA256_INITIAL_G;
     631     5503446 :     state[7] = FD_SHA256_INITIAL_H;
     632             : 
     633     5503446 :     fd_sha256_core( state, buf, 1UL );
     634             : 
     635     5503446 :     state[0] = fd_uint_bswap( state[0] );
     636     5503446 :     state[1] = fd_uint_bswap( state[1] );
     637     5503446 :     state[2] = fd_uint_bswap( state[2] );
     638     5503446 :     state[3] = fd_uint_bswap( state[3] );
     639     5503446 :     state[4] = fd_uint_bswap( state[4] );
     640     5503446 :     state[5] = fd_uint_bswap( state[5] );
     641     5503446 :     state[6] = fd_uint_bswap( state[6] );
     642     5503446 :     state[7] = fd_uint_bswap( state[7] );
     643     5503446 :     memcpy( buf, state, 32UL );
     644     5503446 :   }
     645        2158 :   memcpy( hash, buf, 32UL );
     646        2158 : #endif
     647       11943 :   return _hash;
     648       11943 : }
     649             : 
     650             : #undef fd_sha256_core
     651             : 
     652             : #if FD_SHA256_CORE_IMPL==2
     653             : void
     654             : fd_sha256_hash_32_repeated_batch_arm( uchar const * hash_in,
     655             :                                       uchar *       hash_out,
     656             :                                       ulong         cnt,
     657             :                                       ulong         batch_cnt );
     658             : #endif
     659             : 
     660             : #if FD_HAS_AVX512
     661             : void
     662             : fd_sha256_hash_32_repeated_batch_avx512( uchar const * hash_in,
     663             :                                          uchar *       hash_out,
     664             :                                          ulong         cnt,
     665             :                                          ulong         batch_cnt );
     666             : #endif
     667             : 
     668             : void
     669             : fd_sha256_hash_32_repeated_batch( void const * _hash_in,
     670             :                                   void *       _hash_out,
     671             :                                   ulong        cnt,
     672        3000 :                                   ulong        batch_cnt ) {
     673        3000 :   uchar const * hash_in  = (uchar const *)_hash_in;
     674        3000 :   uchar       * hash_out = (uchar       *)_hash_out;
     675        3000 :   if( FD_UNLIKELY( batch_cnt>fd_sha256_simd_lane_max() ) ) FD_LOG_CRIT(( "batch_cnt %lu exceeds fd_sha256_simd_lane_max %lu", batch_cnt, fd_sha256_simd_lane_max() ));
     676             : #if FD_SHA256_CORE_IMPL==2
     677             :   fd_sha256_hash_32_repeated_batch_arm( hash_in, hash_out, cnt, batch_cnt );
     678             :   return;
     679             : #elif FD_HAS_AVX512
     680        1000 :   fd_sha256_hash_32_repeated_batch_avx512( hash_in, hash_out, cnt, batch_cnt );
     681        1000 :   return;
     682           0 : #endif
     683        3052 :   for( ulong i=0UL; i<batch_cnt; i++ ) {
     684        1052 :     fd_sha256_hash_32_repeated( hash_in+32*i, hash_out+32*i, cnt );
     685        1052 :   }
     686        2000 : }
     687             : 
     688          66 : __attribute__((weak)) ulong fd_sha256_simd_lane_min( void ) { return ULONG_MAX; }
     689        3069 : __attribute__((weak)) ulong fd_sha256_simd_lane_max( void ) { return 1UL; }
     690          51 : __attribute__((weak)) ulong fd_sha256_simd_iter_cost_q8( void ) { return 256UL; }

Generated by: LCOV version 1.14