LCOV - code coverage report
Current view: top level - ballet/sha256 - fd_sha256.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 446 454 98.2 %
Date: 2026-10-22 04:28:21 Functions: 22 22 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     1121784 : fd_sha256_align( void ) {
      11     1121784 :   return FD_SHA256_ALIGN;
      12     1121784 : }
      13             : 
      14             : ulong
      15      560880 : fd_sha256_footprint( void ) {
      16      560880 :   return FD_SHA256_FOOTPRINT;
      17      560880 : }
      18             : 
      19             : void *
      20      560883 : fd_sha256_new( void * shmem ) {
      21      560883 :   fd_sha256_t * sha = (fd_sha256_t *)shmem;
      22             : 
      23      560883 :   if( FD_UNLIKELY( !shmem ) ) {
      24           3 :     FD_LOG_WARNING(( "NULL shmem" ));
      25           3 :     return NULL;
      26           3 :   }
      27             : 
      28      560880 :   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      560877 :   ulong footprint = fd_sha256_footprint();
      34             : 
      35      560877 :   fd_memset( sha, 0, footprint );
      36             : 
      37      560877 :   FD_COMPILER_MFENCE();
      38      560877 :   FD_VOLATILE( sha->magic ) = FD_SHA256_MAGIC;
      39      560877 :   FD_COMPILER_MFENCE();
      40             : 
      41      560877 :   return (void *)sha;
      42      560880 : }
      43             : 
      44             : fd_sha256_t *
      45      560883 : fd_sha256_join( void * shsha ) {
      46             : 
      47      560883 :   if( FD_UNLIKELY( !shsha ) ) {
      48           3 :     FD_LOG_WARNING(( "NULL shsha" ));
      49           3 :     return NULL;
      50           3 :   }
      51             : 
      52      560880 :   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      560877 :   fd_sha256_t * sha = (fd_sha256_t *)shsha;
      58             : 
      59      560877 :   if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
      60           0 :     FD_LOG_WARNING(( "bad magic" ));
      61           0 :     return NULL;
      62           0 :   }
      63             : 
      64      560877 :   return sha;
      65      560877 : }
      66             : 
      67             : void *
      68          21 : fd_sha256_leave( fd_sha256_t * sha ) {
      69             : 
      70          21 :   if( FD_UNLIKELY( !sha ) ) {
      71           3 :     FD_LOG_WARNING(( "NULL sha" ));
      72           3 :     return NULL;
      73           3 :   }
      74             : 
      75          18 :   return (void *)sha;
      76          21 : }
      77             : 
      78             : void *
      79          24 : fd_sha256_delete( void * shsha ) {
      80             : 
      81          24 :   if( FD_UNLIKELY( !shsha ) ) {
      82           3 :     FD_LOG_WARNING(( "NULL shsha" ));
      83           3 :     return NULL;
      84           3 :   }
      85             : 
      86          21 :   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          18 :   fd_sha256_t * sha = (fd_sha256_t *)shsha;
      92             : 
      93          18 :   if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
      94           0 :     FD_LOG_WARNING(( "bad magic" ));
      95           0 :     return NULL;
      96           0 :   }
      97             : 
      98          18 :   FD_COMPILER_MFENCE();
      99          18 :   FD_VOLATILE( sha->magic ) = 0UL;
     100          18 :   FD_COMPILER_MFENCE();
     101             : 
     102          18 :   return (void *)sha;
     103          18 : }
     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             : #elif FD_HAS_RISCV_SHA256
     111             : #define FD_SHA256_CORE_IMPL 3
     112             : #else
     113             : #define FD_SHA256_CORE_IMPL 0
     114             : #endif
     115             : #endif
     116             : 
     117             : #if FD_SHA256_CORE_IMPL==0
     118             : 
     119             : /* The implementation below was derived from OpenSSL's SHA-256
     120             :    implementation (Apache-2.0 licensed).  See in particular:
     121             : 
     122             :     https://github.com/openssl/openssl/blob/master/crypto/sha/sha256.c
     123             : 
     124             :    (link valid circa 2022-Dec).  It has been made more strict with more
     125             :    extensive implementation documentation, has been simplified and has
     126             :    been streamlined specifically for use inside Firedancer base machine
     127             :    model (no machine specific capabilities required).
     128             : 
     129             :    In particular, fd_sha256_core_ref is based on OpenSSL's
     130             :    OPENSSL_SMALL_FOOTPRINT SHA-256 implementation (Apache licensed).
     131             :    This should work anywhere but it is not the highest performance
     132             :    implementation possible.
     133             : 
     134             :    It is also straightforward to replace these implementations with HPC
     135             :    implementations that target specific machine capabilities without
     136             :    requiring any changes to caller code. */
     137             : 
     138             : static void
     139             : fd_sha256_core_ref( uint *        state,
     140             :                     uchar const * block,
     141    23291929 :                     ulong         block_cnt ) {
     142             : 
     143             : 
     144 14882770368 : # define ROTATE     fd_uint_rotate_left
     145  1653641152 : # define Sigma0(x)  (ROTATE((x),30) ^ ROTATE((x),19) ^ ROTATE((x),10))
     146  1653641152 : # define Sigma1(x)  (ROTATE((x),26) ^ ROTATE((x),21) ^ ROTATE((x),7))
     147  1240230864 : # define sigma0(x)  (ROTATE((x),25) ^ ROTATE((x),14) ^ ((x)>>3))
     148  1240230864 : # define sigma1(x)  (ROTATE((x),15) ^ ROTATE((x),13) ^ ((x)>>10))
     149  1653641152 : # define Ch(x,y,z)  (((x) & (y)) ^ ((~(x)) & (z)))
     150  1653641152 : # define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
     151             : 
     152    23291929 :   uchar const * W = block;
     153    25838143 :   do {
     154    25838143 :     uint a = state[0];
     155    25838143 :     uint b = state[1];
     156    25838143 :     uint c = state[2];
     157    25838143 :     uint d = state[3];
     158    25838143 :     uint e = state[4];
     159    25838143 :     uint f = state[5];
     160    25838143 :     uint g = state[6];
     161    25838143 :     uint h = state[7];
     162             : 
     163    25838143 :     uint X[16];
     164             : 
     165    25838143 :     ulong i;
     166   439248431 :     for( i=0UL; i<16UL; i++ ) {
     167   413410288 :       X[i] = fd_uint_bswap( FD_LOAD( uint, W + i*sizeof(uint) ) );
     168   413410288 :       uint T1 = X[i] + h + Sigma1(e) + Ch(e, f, g) + fd_sha256_K[i];
     169   413410288 :       uint T2 = Sigma0(a) + Maj(a, b, c);
     170   413410288 :       h = g;
     171   413410288 :       g = f;
     172   413410288 :       f = e;
     173   413410288 :       e = d + T1;
     174   413410288 :       d = c;
     175   413410288 :       c = b;
     176   413410288 :       b = a;
     177   413410288 :       a = T1 + T2;
     178   413410288 :     }
     179  1266069007 :     for( ; i<64UL; i++ ) {
     180  1240230864 :       uint s0 = X[(i +  1UL) & 0x0fUL];
     181  1240230864 :       uint s1 = X[(i + 14UL) & 0x0fUL];
     182  1240230864 :       s0 = sigma0(s0);
     183  1240230864 :       s1 = sigma1(s1);
     184  1240230864 :       X[i & 0xfUL] += s0 + s1 + X[(i + 9UL) & 0xfUL];
     185  1240230864 :       uint T1 = X[i & 0xfUL ] + h + Sigma1(e) + Ch(e, f, g) + fd_sha256_K[i];
     186  1240230864 :       uint T2 = Sigma0(a) + Maj(a, b, c);
     187  1240230864 :       h = g;
     188  1240230864 :       g = f;
     189  1240230864 :       f = e;
     190  1240230864 :       e = d + T1;
     191  1240230864 :       d = c;
     192  1240230864 :       c = b;
     193  1240230864 :       b = a;
     194  1240230864 :       a = T1 + T2;
     195  1240230864 :     }
     196             : 
     197    25838143 :     state[0] += a;
     198    25838143 :     state[1] += b;
     199    25838143 :     state[2] += c;
     200    25838143 :     state[3] += d;
     201    25838143 :     state[4] += e;
     202    25838143 :     state[5] += f;
     203    25838143 :     state[6] += g;
     204    25838143 :     state[7] += h;
     205             : 
     206    25838143 :     W += 16UL*sizeof(uint);
     207    25838143 :   } while( --block_cnt );
     208             : 
     209    23291929 : # undef ROTATE
     210    23291929 : # undef Sigma0
     211    23291929 : # undef Sigma1
     212    23291929 : # undef sigma0
     213    23291929 : # undef sigma1
     214    23291929 : # undef Ch
     215    23291929 : # undef Maj
     216             : 
     217    23291929 : }
     218             : 
     219    23291929 : #define fd_sha256_core fd_sha256_core_ref
     220             : 
     221             : #elif FD_SHA256_CORE_IMPL==1
     222             : 
     223             : /* _mm_sha256rnds2_epu32 does two rounds, one from the first uint in
     224             :    wk and one from the second.  Since wk stores four rounds worth of
     225             :    message schedule values, it makes sense for the macro to do four
     226             :    rounds at a time.  We need to permute wk in between so that the
     227             :    second call to the intrinsic will use the other values. */
     228   250407568 : #define FOUR_ROUNDS_STATE( stateFEBA, stateHGDC, wk ) do {                                   \
     229   250407568 :       vu_t __wk = (wk);                                                                      \
     230   250407568 :       vu_t temp_state = stateFEBA;                                                           \
     231   250407568 :       stateFEBA = _mm_sha256rnds2_epu32( stateHGDC, stateFEBA, __wk );                       \
     232   250407568 :       stateHGDC = temp_state;                                                                \
     233   250407568 :                                                                                              \
     234   250407568 :       temp_state = stateFEBA;                                                                \
     235   250407568 :       stateFEBA = _mm_sha256rnds2_epu32( stateHGDC, stateFEBA, vu_permute( __wk, 2,3,0,1 ) );\
     236   250407568 :       stateHGDC = temp_state;                                                                \
     237   250407568 :     } while( 0 )
     238             : 
     239   247881296 : #define FOUR_ROUNDS( wk ) FOUR_ROUNDS_STATE( stateFEBA, stateHGDC, wk )
     240             : 
     241             : 
     242             : /* For completeness, here's the documentation for _mm_sha256msg1_epu32
     243             :    and _mm_sha256msg2_epu32 in a slightly reformatted way, where all
     244             :    values are uints, and "-" indicates a don't-care value:
     245             : 
     246             :        _mm_sha256msg1_epu32( (w[j  ], w[j+1], w[j+1], w[j+3]),
     247             :                              (w[j+4], -,      -,      -     ) )
     248             :          = ( w[j  ]+s0( w[j+1] ),  w[j+1]+s0( w[j+2] ),
     249             :              w[j+2]+s0( w[j+3] ),  w[j+3]+s0( w[j+4] ) ).
     250             : 
     251             : 
     252             :        _mm_sha256msg2_epu32( (v[j  ], v[j+1], v[j+1], v[j+3]),
     253             :                              (-,      -,      w[j-2], w[j-1]) )
     254             :          sets w[j  ] = v[j  ] + s1( w[j-2] ) and
     255             :               w[j+1] = v[j+1] + s1( w[j-1] ), and then returns
     256             : 
     257             :            ( v[j  ]+s1( w[j-2] ), v[j+1]+s1( w[j-1] ),
     258             :              v[j+2]+s1( w[j  ] ), v[j+3]+s1( w[j+1] ) )   */
     259             : 
     260             : 
     261             : /* w[i] for i>= 16 is w[i-16] + s0(w[i-15]) + w[i-7] + s1(w[i-2])
     262             :    Since our vector size is 4 uints, it's only s1 that is a little
     263             :    problematic, because it references items in the same vector.
     264             :    Thankfully, the msg2 intrinsic takes care of the complexity, but we
     265             :    need to execute it last.
     266             : 
     267             :    We get w[i-16] and s0(s[i-15]) using the msg1 intrinsic, setting j =
     268             :    i-16.  For example, to compute w1013, we pass in w0003 and w0407.
     269             :    Then we can get w[i-7] by using the alignr instruction on
     270             :    (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])
     271             :    to concatenate them and shift by one uint.  Continuing with the
     272             :    example of w1013, we need w080b and w0c0f.  We then put
     273             :              v[i] = w[i-16] + s0(w[i-15]) + w[i-7],
     274             :    and invoke the msg2 intrinsic with j=i, which gives w[i], as desired.
     275             :    Each invocation of NEXT_W computes 4 values of w. */
     276             : 
     277   187805676 : #define NEXT_W( w_minus_16, w_minus_12, w_minus_8, w_minus_4 ) (__extension__({      \
     278   187805676 :     vu_t __w_i_16_s0_i_15 = _mm_sha256msg1_epu32( w_minus_16, w_minus_12 );          \
     279   187805676 :     vu_t __w_i_7          = _mm_alignr_epi8( w_minus_4, w_minus_8, 4 );              \
     280   187805676 :     _mm_sha256msg2_epu32( vu_add( __w_i_7, __w_i_16_s0_i_15 ), w_minus_4 );          \
     281   187805676 :     }))
     282             : 
     283             : /* Zen 5's sha256rnds2 has an RTP of 2, while Zen 4's has an RTP of 1. We can
     284             :    win some performance by moving the schedule updates earlier in the loop,
     285             :    which improves the speed by around 1M hashes/s for the repeated hashing. */
     286             : #ifdef __znver5__
     287             : #define FULL_ROUNDS() do {                                                                                        \
     288             :     vu_t w1013 = NEXT_W( w0003, w0407, w080b, w0c0f ); FOUR_ROUNDS( vu_add( w0003, vu_ld( fd_sha256_K+ 0UL ) ) ); \
     289             :     vu_t w1417 = NEXT_W( w0407, w080b, w0c0f, w1013 ); FOUR_ROUNDS( vu_add( w0407, vu_ld( fd_sha256_K+ 4UL ) ) ); \
     290             :     vu_t w181b = NEXT_W( w080b, w0c0f, w1013, w1417 ); FOUR_ROUNDS( vu_add( w080b, vu_ld( fd_sha256_K+ 8UL ) ) ); \
     291             :     vu_t w1c1f = NEXT_W( w0c0f, w1013, w1417, w181b ); FOUR_ROUNDS( vu_add( w0c0f, vu_ld( fd_sha256_K+12UL ) ) ); \
     292             :     vu_t w2023 = NEXT_W( w1013, w1417, w181b, w1c1f ); FOUR_ROUNDS( vu_add( w1013, vu_ld( fd_sha256_K+16UL ) ) ); \
     293             :     vu_t w2427 = NEXT_W( w1417, w181b, w1c1f, w2023 ); FOUR_ROUNDS( vu_add( w1417, vu_ld( fd_sha256_K+20UL ) ) ); \
     294             :     vu_t w282b = NEXT_W( w181b, w1c1f, w2023, w2427 ); FOUR_ROUNDS( vu_add( w181b, vu_ld( fd_sha256_K+24UL ) ) ); \
     295             :     vu_t w2c2f = NEXT_W( w1c1f, w2023, w2427, w282b ); FOUR_ROUNDS( vu_add( w1c1f, vu_ld( fd_sha256_K+28UL ) ) ); \
     296             :     vu_t w3033 = NEXT_W( w2023, w2427, w282b, w2c2f ); FOUR_ROUNDS( vu_add( w2023, vu_ld( fd_sha256_K+32UL ) ) ); \
     297             :     vu_t w3437 = NEXT_W( w2427, w282b, w2c2f, w3033 ); FOUR_ROUNDS( vu_add( w2427, vu_ld( fd_sha256_K+36UL ) ) ); \
     298             :     vu_t w383b = NEXT_W( w282b, w2c2f, w3033, w3437 ); FOUR_ROUNDS( vu_add( w282b, vu_ld( fd_sha256_K+40UL ) ) ); \
     299             :     vu_t w3c3f = NEXT_W( w2c2f, w3033, w3437, w383b ); FOUR_ROUNDS( vu_add( w2c2f, vu_ld( fd_sha256_K+44UL ) ) ); \
     300             :     /*                                              */ FOUR_ROUNDS( vu_add( w3033, vu_ld( fd_sha256_K+48UL ) ) ); \
     301             :     /*                                              */ FOUR_ROUNDS( vu_add( w3437, vu_ld( fd_sha256_K+52UL ) ) ); \
     302             :     /*                                              */ FOUR_ROUNDS( vu_add( w383b, vu_ld( fd_sha256_K+56UL ) ) ); \
     303             :     /*                                              */ FOUR_ROUNDS( vu_add( w3c3f, vu_ld( fd_sha256_K+60UL ) ) ); \
     304             :     } while ( 0 )
     305             : #else
     306    15492581 : #define FULL_ROUNDS() do {                                                                                        \
     307    15492581 :     /*                                              */ FOUR_ROUNDS( vu_add( w0003, vu_ld( fd_sha256_K+ 0UL ) ) ); \
     308    15492581 :     /*                                              */ FOUR_ROUNDS( vu_add( w0407, vu_ld( fd_sha256_K+ 4UL ) ) ); \
     309    15492581 :     /*                                              */ FOUR_ROUNDS( vu_add( w080b, vu_ld( fd_sha256_K+ 8UL ) ) ); \
     310    15492581 :     /*                                              */ FOUR_ROUNDS( vu_add( w0c0f, vu_ld( fd_sha256_K+12UL ) ) ); \
     311    15492581 :     vu_t w1013 = NEXT_W( w0003, w0407, w080b, w0c0f ); FOUR_ROUNDS( vu_add( w1013, vu_ld( fd_sha256_K+16UL ) ) ); \
     312    15492581 :     vu_t w1417 = NEXT_W( w0407, w080b, w0c0f, w1013 ); FOUR_ROUNDS( vu_add( w1417, vu_ld( fd_sha256_K+20UL ) ) ); \
     313    15492581 :     vu_t w181b = NEXT_W( w080b, w0c0f, w1013, w1417 ); FOUR_ROUNDS( vu_add( w181b, vu_ld( fd_sha256_K+24UL ) ) ); \
     314    15492581 :     vu_t w1c1f = NEXT_W( w0c0f, w1013, w1417, w181b ); FOUR_ROUNDS( vu_add( w1c1f, vu_ld( fd_sha256_K+28UL ) ) ); \
     315    15492581 :     vu_t w2023 = NEXT_W( w1013, w1417, w181b, w1c1f ); FOUR_ROUNDS( vu_add( w2023, vu_ld( fd_sha256_K+32UL ) ) ); \
     316    15492581 :     vu_t w2427 = NEXT_W( w1417, w181b, w1c1f, w2023 ); FOUR_ROUNDS( vu_add( w2427, vu_ld( fd_sha256_K+36UL ) ) ); \
     317    15492581 :     vu_t w282b = NEXT_W( w181b, w1c1f, w2023, w2427 ); FOUR_ROUNDS( vu_add( w282b, vu_ld( fd_sha256_K+40UL ) ) ); \
     318    15492581 :     vu_t w2c2f = NEXT_W( w1c1f, w2023, w2427, w282b ); FOUR_ROUNDS( vu_add( w2c2f, vu_ld( fd_sha256_K+44UL ) ) ); \
     319    15492581 :     vu_t w3033 = NEXT_W( w2023, w2427, w282b, w2c2f ); FOUR_ROUNDS( vu_add( w3033, vu_ld( fd_sha256_K+48UL ) ) ); \
     320    15492581 :     vu_t w3437 = NEXT_W( w2427, w282b, w2c2f, w3033 ); FOUR_ROUNDS( vu_add( w3437, vu_ld( fd_sha256_K+52UL ) ) ); \
     321    15492581 :     vu_t w383b = NEXT_W( w282b, w2c2f, w3033, w3437 ); FOUR_ROUNDS( vu_add( w383b, vu_ld( fd_sha256_K+56UL ) ) ); \
     322    15492581 :     vu_t w3c3f = NEXT_W( w2c2f, w3033, w3437, w383b ); FOUR_ROUNDS( vu_add( w3c3f, vu_ld( fd_sha256_K+60UL ) ) ); \
     323    15492581 :     } while ( 0 )
     324             : #endif
     325             : 
     326             : 
     327             : void
     328             : fd_sha256_core_shaext( uint *        state,       /* 64-byte aligned, 8 entries */
     329             :                        uchar const * block,       /* ideally 128-byte aligned (but not required), 64*block_cnt in size */
     330     9755588 :                        ulong         block_cnt ) {/* positive */
     331     9755588 :   vu_t stateABCD = vu_ld( state     );
     332     9755588 :   vu_t stateEFGH = vu_ld( state+4UL );
     333             : 
     334     9755588 :   vu_t baseFEBA = vu_permute2( stateEFGH, stateABCD, 1, 0, 1, 0 );
     335     9755588 :   vu_t baseHGDC = vu_permute2( stateEFGH, stateABCD, 3, 2, 3, 2 );
     336             : 
     337    21789666 :   for( ulong b=0UL; b<block_cnt; b++ ) {
     338    12034078 :     vu_t stateFEBA = baseFEBA;
     339    12034078 :     vu_t stateHGDC = baseHGDC;
     340             : 
     341    12034078 :     vu_t w0003 = vu_bswap( vu_ldu( block+64UL*b      ) );
     342    12034078 :     vu_t w0407 = vu_bswap( vu_ldu( block+64UL*b+16UL ) );
     343    12034078 :     vu_t w080b = vu_bswap( vu_ldu( block+64UL*b+32UL ) );
     344    12034078 :     vu_t w0c0f = vu_bswap( vu_ldu( block+64UL*b+48UL ) );
     345             : 
     346    12034078 :     FULL_ROUNDS();
     347             : 
     348    12034078 :     baseFEBA = vu_add( baseFEBA, stateFEBA );
     349    12034078 :     baseHGDC = vu_add( baseHGDC, stateHGDC );
     350             : 
     351    12034078 :   }
     352             : 
     353     9755588 :   stateABCD = vu_permute2( baseFEBA, baseHGDC, 3, 2, 3, 2 );
     354     9755588 :   stateEFGH = vu_permute2( baseFEBA, baseHGDC, 1, 0, 1, 0 );
     355     9755588 :   vu_st( state,     stateABCD );
     356     9755588 :   vu_st( state+4UL, stateEFGH );
     357     9755588 : }
     358             : 
     359     9755588 : #define fd_sha256_core fd_sha256_core_shaext
     360             : 
     361             : #elif FD_SHA256_CORE_IMPL==2
     362             : 
     363             : void
     364             : fd_sha256_core_arm( uint *        state,
     365             :                     uchar const * block,
     366             :                     ulong         block_cnt );
     367             : 
     368             : #define fd_sha256_core fd_sha256_core_arm
     369             : 
     370             : #elif FD_SHA256_CORE_IMPL==3
     371             : 
     372             : void
     373             : fd_sha256_core_riscv( uint *        state,
     374             :                       uchar const * block,
     375             :                       ulong         block_cnt );
     376             : 
     377             : #define fd_sha256_core fd_sha256_core_riscv
     378             : 
     379             : #else
     380             : #error "Unsupported FD_SHA256_CORE_IMPL"
     381             : #endif
     382             : 
     383             : fd_sha256_t *
     384     1173378 : fd_sha256_init( fd_sha256_t * sha ) {
     385     1173378 :   sha->state[0] = FD_SHA256_INITIAL_A;
     386     1173378 :   sha->state[1] = FD_SHA256_INITIAL_B;
     387     1173378 :   sha->state[2] = FD_SHA256_INITIAL_C;
     388     1173378 :   sha->state[3] = FD_SHA256_INITIAL_D;
     389     1173378 :   sha->state[4] = FD_SHA256_INITIAL_E;
     390     1173378 :   sha->state[5] = FD_SHA256_INITIAL_F;
     391     1173378 :   sha->state[6] = FD_SHA256_INITIAL_G;
     392     1173378 :   sha->state[7] = FD_SHA256_INITIAL_H;
     393     1173378 :   sha->buf_used = 0UL;
     394     1173378 :   sha->bit_cnt  = 0UL;
     395     1173378 :   return sha;
     396     1173378 : }
     397             : 
     398             : fd_sha256_t *
     399             : fd_sha256_append( fd_sha256_t * sha,
     400             :                   void const *  _data,
     401     2455107 :                   ulong         sz ) {
     402             : 
     403             :   /* If no data to append, we are done */
     404             : 
     405     2455107 :   if( FD_UNLIKELY( !sz ) ) return sha; /* optimize for non-trivial append */
     406             : 
     407             :   /* Unpack inputs */
     408             : 
     409     2454861 :   uint *  state    = sha->state;
     410     2454861 :   uchar * buf      = sha->buf;
     411     2454861 :   ulong   buf_used = sha->buf_used;
     412     2454861 :   ulong   bit_cnt  = sha->bit_cnt;
     413             : 
     414     2454861 :   uchar const * data = (uchar const *)_data;
     415             : 
     416             :   /* Update bit_cnt */
     417             :   /* FIXME: could accumulate bytes here and do bit conversion in append */
     418             :   /* FIXME: Overflow handling if more than 2^64 bits (unlikely) */
     419             : 
     420     2454861 :   sha->bit_cnt = bit_cnt + (sz<<3);
     421             : 
     422             :   /* Handle buffered bytes from previous appends */
     423             : 
     424     2454861 :   if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
     425             : 
     426             :     /* If the append isn't large enough to complete the current block,
     427             :        buffer these bytes too and return */
     428             : 
     429      165920 :     ulong buf_rem = FD_SHA256_PRIVATE_BUF_MAX - buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
     430      165920 :     if( FD_UNLIKELY( sz < buf_rem ) ) { /* optimize for large append */
     431       49454 :       fd_memcpy( buf + buf_used, data, sz );
     432       49454 :       sha->buf_used = buf_used + sz;
     433       49454 :       return sha;
     434       49454 :     }
     435             : 
     436             :     /* Otherwise, buffer enough leading bytes of data to complete the
     437             :        block, update the hash and then continue processing any remaining
     438             :        bytes of data. */
     439             : 
     440      116466 :     fd_memcpy( buf + buf_used, data, buf_rem );
     441      116466 :     data += buf_rem;
     442      116466 :     sz   -= buf_rem;
     443             : 
     444      116466 :     fd_sha256_core( state, buf, 1UL );
     445      116466 :     sha->buf_used = 0UL;
     446      116466 :   }
     447             : 
     448             :   /* Append the bulk of the data */
     449             : 
     450     2405407 :   ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
     451     2405407 :   if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt ); /* optimized for large append */
     452             : 
     453             :   /* Buffer any leftover bytes */
     454             : 
     455     2405407 :   buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL); /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
     456     2405407 :   if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
     457     1289552 :     fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
     458     1289552 :     sha->buf_used = buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
     459     1289552 :   }
     460             : 
     461     2405407 :   return sha;
     462     2454861 : }
     463             : 
     464             : void *
     465             : fd_sha256_fini( fd_sha256_t * sha,
     466     1239192 :                 void *        _hash ) {
     467             : 
     468             :   /* Unpack inputs */
     469             : 
     470     1239192 :   uint *  state    = sha->state;
     471     1239192 :   uchar * buf      = sha->buf;
     472     1239192 :   ulong   buf_used = sha->buf_used; /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
     473     1239192 :   ulong   bit_cnt  = sha->bit_cnt;
     474             : 
     475             :   /* Append the terminating message byte */
     476             : 
     477     1239192 :   buf[ buf_used ] = (uchar)0x80;
     478     1239192 :   buf_used++;
     479             : 
     480             :   /* If there isn't enough room to save the message length in bits at
     481             :      the end of the in progress block, clear the rest of the in progress
     482             :      block, update the hash and start a new block. */
     483             : 
     484     1239192 :   if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) { /* optimize for well aligned use of append */
     485       16897 :     fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
     486       16897 :     fd_sha256_core( state, buf, 1UL );
     487       16897 :     buf_used = 0UL;
     488       16897 :   }
     489             : 
     490             :   /* Clear in progress block up to last 64-bits, append the message
     491             :      size in bytes in the last 64-bits of the in progress block and
     492             :      update the hash to finalize it. */
     493             : 
     494     1239192 :   fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     495     1239192 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     496     1239192 :   fd_sha256_core( state, buf, 1UL );
     497             : 
     498             :   /* Unpack the result into md (annoying bswaps here) */
     499             : 
     500     1239192 :   state[0] = fd_uint_bswap( state[0] );
     501     1239192 :   state[1] = fd_uint_bswap( state[1] );
     502     1239192 :   state[2] = fd_uint_bswap( state[2] );
     503     1239192 :   state[3] = fd_uint_bswap( state[3] );
     504     1239192 :   state[4] = fd_uint_bswap( state[4] );
     505     1239192 :   state[5] = fd_uint_bswap( state[5] );
     506     1239192 :   state[6] = fd_uint_bswap( state[6] );
     507     1239192 :   state[7] = fd_uint_bswap( state[7] );
     508     1239192 :   return memcpy( _hash, state, 32 );
     509     1239192 : }
     510             : 
     511             : void *
     512             : fd_sha256_hash( void const * _data,
     513             :                 ulong        sz,
     514    19912784 :                 void *       _hash ) {
     515    19912784 :   uchar const * data = (uchar const *)_data;
     516             : 
     517             :   /* This is just the above streamlined to eliminate all the overheads
     518             :      to support incremental hashing. */
     519             : 
     520    19912784 :   uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ] __attribute__((aligned(128)));
     521    19912784 :   uint  state[8] __attribute__((aligned(32)));
     522             : 
     523    19912784 :   state[0] = FD_SHA256_INITIAL_A;
     524    19912784 :   state[1] = FD_SHA256_INITIAL_B;
     525    19912784 :   state[2] = FD_SHA256_INITIAL_C;
     526    19912784 :   state[3] = FD_SHA256_INITIAL_D;
     527    19912784 :   state[4] = FD_SHA256_INITIAL_E;
     528    19912784 :   state[5] = FD_SHA256_INITIAL_F;
     529    19912784 :   state[6] = FD_SHA256_INITIAL_G;
     530    19912784 :   state[7] = FD_SHA256_INITIAL_H;
     531             : 
     532    19912784 :   ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
     533    19912784 :   if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt );
     534             : 
     535    19912784 :   ulong buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL);
     536    19912784 :   if( FD_UNLIKELY( buf_used ) ) fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
     537    19912784 :   buf[ buf_used ] = (uchar)0x80;
     538    19912784 :   buf_used++;
     539             : 
     540    19912784 :   if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) {
     541      164258 :     fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
     542      164258 :     fd_sha256_core( state, buf, 1UL );
     543      164258 :     buf_used = 0UL;
     544      164258 :   }
     545             : 
     546    19912784 :   ulong bit_cnt = sz << 3;
     547    19912784 :   fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     548    19912784 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     549    19912784 :   fd_sha256_core( state, buf, 1UL );
     550             : 
     551    19912784 :   state[0] = fd_uint_bswap( state[0] );
     552    19912784 :   state[1] = fd_uint_bswap( state[1] );
     553    19912784 :   state[2] = fd_uint_bswap( state[2] );
     554    19912784 :   state[3] = fd_uint_bswap( state[3] );
     555    19912784 :   state[4] = fd_uint_bswap( state[4] );
     556    19912784 :   state[5] = fd_uint_bswap( state[5] );
     557    19912784 :   state[6] = fd_uint_bswap( state[6] );
     558    19912784 :   state[7] = fd_uint_bswap( state[7] );
     559    19912784 :   return memcpy( _hash, state, 32 );
     560    19912784 : }
     561             : 
     562             : 
     563             : 
     564             : #if FD_SHA256_CORE_IMPL==2
     565             : void
     566             : fd_sha256_hash_32_repeated_arm( uchar const * data,
     567             :                                 uchar *       hash,
     568             :                                 ulong         cnt );
     569             : #elif FD_SHA256_CORE_IMPL==3
     570             : void
     571             : fd_sha256_hash_32_repeated_riscv( uchar const * data,
     572             :                                   uchar *       hash,
     573             :                                   ulong         cnt );
     574             : #endif
     575             : 
     576             : void *
     577             : fd_sha256_hash_32_repeated( void const * _data,
     578             :                             void *       _hash,
     579       11111 :                             ulong        cnt ) {
     580             : #if FD_SHA256_CORE_IMPL==2
     581             :   fd_sha256_hash_32_repeated_arm( _data, _hash, cnt );
     582             :   return _hash;
     583             : #elif FD_SHA256_CORE_IMPL==3
     584             :   fd_sha256_hash_32_repeated_riscv( _data, _hash, cnt );
     585             :   return _hash;
     586             : #elif FD_SHA256_CORE_IMPL==1
     587             : 
     588        9025 :   uchar const * data = (uchar const *)_data;
     589        9025 :   uchar       * hash = (uchar       *)_hash;
     590             : 
     591        9025 :   vu_t       w0003 = vu_bswap( vu_ldu( data      ) );
     592        9025 :   vu_t       w0407 = vu_bswap( vu_ldu( data+16UL ) );
     593        9025 :   vb_t const w080b = vb( 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
     594        9025 :                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 );
     595        9025 :   vb_t const w0c0f = vb( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     596        9025 :                          0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 ); /* 32 bytes */
     597             : 
     598        9025 :   vu_t const initialFEBA = vu( FD_SHA256_INITIAL_F, FD_SHA256_INITIAL_E, FD_SHA256_INITIAL_B, FD_SHA256_INITIAL_A );
     599        9025 :   vu_t const initialHGDC = vu( FD_SHA256_INITIAL_H, FD_SHA256_INITIAL_G, FD_SHA256_INITIAL_D, FD_SHA256_INITIAL_C );
     600             : 
     601     3467528 :   for( ulong iter=0UL; iter<cnt; iter++ ) {
     602     3458503 :     vu_t stateFEBA = initialFEBA;
     603     3458503 :     vu_t stateHGDC = initialHGDC;
     604             : 
     605     3458503 :     FULL_ROUNDS();
     606             : 
     607     3458503 :     stateFEBA = vu_add( stateFEBA, initialFEBA );
     608     3458503 :     stateHGDC = vu_add( stateHGDC, initialHGDC );
     609             : 
     610     3458503 :     vu_t stateABCD = vu_permute2( stateFEBA, stateHGDC, 3, 2, 3, 2 );
     611     3458503 :     vu_t stateEFGH = vu_permute2( stateFEBA, stateHGDC, 1, 0, 1, 0 );
     612             : 
     613     3458503 :     w0003 = stateABCD;
     614     3458503 :     w0407 = stateEFGH;
     615     3458503 :   }
     616        9025 :   vu_stu( hash,      vu_bswap( w0003 ) );
     617        9025 :   vu_stu( hash+16UL, vu_bswap( w0407 ) );
     618             : 
     619             : #else
     620             : 
     621        2086 :   uchar const * data = (uchar const *)_data;
     622        2086 :   uchar       * hash = (uchar       *)_hash;
     623             : 
     624        2086 :   uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ] __attribute__((aligned(128)));
     625             : 
     626             :   /* Prepare padding once */
     627        2086 :   ulong buf_used = 32UL;
     628        2086 :   memcpy( buf, data, 32UL );
     629        2086 :   buf[ buf_used ] = (uchar)0x80;
     630        2086 :   buf_used++;
     631             : 
     632        2086 :   ulong bit_cnt = 32UL << 3;
     633        2086 :   memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     634        2086 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     635             : 
     636             :   /* This is just the above streamlined to eliminate all the overheads
     637             :      to support incremental hashing. */
     638     5498092 :   for( ulong iter=0UL; iter<cnt; iter++ ) {
     639             : 
     640     5496006 :     uint  state[8] __attribute__((aligned(32)));
     641             : 
     642     5496006 :     state[0] = FD_SHA256_INITIAL_A;
     643     5496006 :     state[1] = FD_SHA256_INITIAL_B;
     644     5496006 :     state[2] = FD_SHA256_INITIAL_C;
     645     5496006 :     state[3] = FD_SHA256_INITIAL_D;
     646     5496006 :     state[4] = FD_SHA256_INITIAL_E;
     647     5496006 :     state[5] = FD_SHA256_INITIAL_F;
     648     5496006 :     state[6] = FD_SHA256_INITIAL_G;
     649     5496006 :     state[7] = FD_SHA256_INITIAL_H;
     650             : 
     651     5496006 :     fd_sha256_core( state, buf, 1UL );
     652             : 
     653     5496006 :     state[0] = fd_uint_bswap( state[0] );
     654     5496006 :     state[1] = fd_uint_bswap( state[1] );
     655     5496006 :     state[2] = fd_uint_bswap( state[2] );
     656     5496006 :     state[3] = fd_uint_bswap( state[3] );
     657     5496006 :     state[4] = fd_uint_bswap( state[4] );
     658     5496006 :     state[5] = fd_uint_bswap( state[5] );
     659     5496006 :     state[6] = fd_uint_bswap( state[6] );
     660     5496006 :     state[7] = fd_uint_bswap( state[7] );
     661     5496006 :     memcpy( buf, state, 32UL );
     662     5496006 :   }
     663        2086 :   memcpy( hash, buf, 32UL );
     664        2086 : #endif
     665       11111 :   return _hash;
     666       11111 : }
     667             : 
     668             : #undef fd_sha256_core
     669             : 
     670             : #if FD_SHA256_CORE_IMPL==1
     671             : 
     672             : /* A single repeated hash chain is bound by the sha256rnds2 dependency
     673             :    chain.  The kernels below run 2-5 independent chains, issuing each
     674             :    step for every chain in turn so their rounds overlap.  Every chain
     675             :    has its own named registers (suffix _<lane>).  Zen 4 M hashes/s by
     676             :    chain count: 1: 31.1, 2: 58.9, 3: 74.8, 4: 80.1, 5: 79.6 (6+ spill
     677             :    heavily and get slower). */
     678             : 
     679     1393184 : #define EACH2( M, ... ) M( 0, __VA_ARGS__ ) M( 1, __VA_ARGS__ )
     680     1209746 : #define EACH3( M, ... ) EACH2( M, __VA_ARGS__ ) M( 2, __VA_ARGS__ )
     681      531304 : #define EACH4( M, ... ) EACH3( M, __VA_ARGS__ ) M( 3, __VA_ARGS__ )
     682      213076 : #define EACH5( M, ... ) EACH4( M, __VA_ARGS__ ) M( 4, __VA_ARGS__ )
     683             : 
     684             : #define X_LOAD( l, in )                                        \
     685        1867 :   vu_t w0003_##l = vu_bswap( vu_ldu( (in)+32UL*(l)      ) );   \
     686        1867 :   vu_t w0407_##l = vu_bswap( vu_ldu( (in)+32UL*(l)+16UL ) );
     687             : #define X_INIT( l, _ )                                         \
     688      157892 :   vu_t feba_##l  = initialFEBA; vu_t hgdc_##l  = initialHGDC;  \
     689      157892 :   vu_t w080b_##l = w080b;       vu_t w0c0f_##l = w0c0f;
     690     2526272 : #define X_R( l, w, k ) FOUR_ROUNDS_STATE( feba_##l, hgdc_##l, vu_add( w##_##l, vu_ld( fd_sha256_K+(k) ) ) );
     691     1894704 : #define X_W( l, d, a, b, c, e ) vu_t d##_##l = NEXT_W( a##_##l, b##_##l, c##_##l, e##_##l );
     692             : #define X_FINI( l, _ )                                                                       \
     693      157892 :   feba_##l  = vu_add( feba_##l, initialFEBA ); hgdc_##l = vu_add( hgdc_##l, initialHGDC ); \
     694      157892 :   w0003_##l = vu_permute2( feba_##l, hgdc_##l, 3, 2, 3, 2 );                                 \
     695      157892 :   w0407_##l = vu_permute2( feba_##l, hgdc_##l, 1, 0, 1, 0 );
     696             : #define X_STORE( l, out )                                      \
     697        1867 :   vu_stu( (out)+32UL*(l),      vu_bswap( w0003_##l ) );        \
     698        1867 :   vu_stu( (out)+32UL*(l)+16UL, vu_bswap( w0407_##l ) );
     699             : 
     700         547 : #define REPEATED_MULTI( EACH ) do {                                                                              \
     701         547 :     vu_t const w080b = vu( 0x80000000U, 0U, 0U, 0U   );                                                         \
     702         547 :     vu_t const w0c0f = vu( 0U,          0U, 0U, 256U ); /* 32 bytes */                                          \
     703         547 :     vu_t const initialFEBA = vu( FD_SHA256_INITIAL_F, FD_SHA256_INITIAL_E, FD_SHA256_INITIAL_B, FD_SHA256_INITIAL_A ); \
     704         547 :     vu_t const initialHGDC = vu( FD_SHA256_INITIAL_H, FD_SHA256_INITIAL_G, FD_SHA256_INITIAL_D, FD_SHA256_INITIAL_C ); \
     705        1867 :     EACH( X_LOAD, in )                                                                                           \
     706       46950 :     for( ulong iter=0UL; iter<cnt; iter++ ) {                                                                    \
     707      157892 :       EACH( X_INIT, _ )                                                                                          \
     708      157892 :       /*                                                  */ EACH( X_R, w0003,  0 );                             \
     709      157892 :       /*                                                  */ EACH( X_R, w0407,  4 );                             \
     710      157892 :       /*                                                  */ EACH( X_R, w080b,  8 );                             \
     711      157892 :       /*                                                  */ EACH( X_R, w0c0f, 12 );                             \
     712      157892 :       EACH( X_W, w1013, w0003, w0407, w080b, w0c0f ); EACH( X_R, w1013, 16 );                              \
     713      157892 :       EACH( X_W, w1417, w0407, w080b, w0c0f, w1013 ); EACH( X_R, w1417, 20 );                              \
     714      157892 :       EACH( X_W, w181b, w080b, w0c0f, w1013, w1417 ); EACH( X_R, w181b, 24 );                              \
     715      157892 :       EACH( X_W, w1c1f, w0c0f, w1013, w1417, w181b ); EACH( X_R, w1c1f, 28 );                              \
     716      157892 :       EACH( X_W, w2023, w1013, w1417, w181b, w1c1f ); EACH( X_R, w2023, 32 );                              \
     717      157892 :       EACH( X_W, w2427, w1417, w181b, w1c1f, w2023 ); EACH( X_R, w2427, 36 );                              \
     718      157892 :       EACH( X_W, w282b, w181b, w1c1f, w2023, w2427 ); EACH( X_R, w282b, 40 );                              \
     719      157892 :       EACH( X_W, w2c2f, w1c1f, w2023, w2427, w282b ); EACH( X_R, w2c2f, 44 );                              \
     720      157892 :       EACH( X_W, w3033, w2023, w2427, w282b, w2c2f ); EACH( X_R, w3033, 48 );                              \
     721      157892 :       EACH( X_W, w3437, w2427, w282b, w2c2f, w3033 ); EACH( X_R, w3437, 52 );                              \
     722      157892 :       EACH( X_W, w383b, w282b, w2c2f, w3033, w3437 ); EACH( X_R, w383b, 56 );                              \
     723      157892 :       EACH( X_W, w3c3f, w2c2f, w3033, w3437, w383b ); EACH( X_R, w3c3f, 60 );                              \
     724      157892 :       EACH( X_FINI, _ )                                                                                          \
     725       46403 :     }                                                                                                            \
     726        1867 :     EACH( X_STORE, out )                                                                                         \
     727         547 :   } while( 0 )
     728             : 
     729      183438 : static void fd_sha256_hash_32_repeated_x2( uchar const * in, uchar * out, ulong cnt ) { REPEATED_MULTI( EACH2 ); }
     730      678442 : static void fd_sha256_hash_32_repeated_x3( uchar const * in, uchar * out, ulong cnt ) { REPEATED_MULTI( EACH3 ); }
     731      318228 : static void fd_sha256_hash_32_repeated_x4( uchar const * in, uchar * out, ulong cnt ) { REPEATED_MULTI( EACH4 ); }
     732      213076 : static void fd_sha256_hash_32_repeated_x5( uchar const * in, uchar * out, ulong cnt ) { REPEATED_MULTI( EACH5 ); }
     733             : 
     734             : #undef REPEATED_MULTI
     735             : #undef X_STORE
     736             : #undef X_FINI
     737             : #undef X_W
     738             : #undef X_R
     739             : #undef X_INIT
     740             : #undef X_LOAD
     741             : #undef EACH5
     742             : #undef EACH4
     743             : #undef EACH3
     744             : #undef EACH2
     745             : 
     746             : static void
     747             : fd_sha256_hash_32_repeated_shani( uchar const * in,
     748             :                                   uchar *       out,
     749             :                                   ulong         cnt,
     750         557 :                                   ulong         lane_cnt ) {
     751             :   /* Split into the fewest groups of at most 5 chains, of near equal
     752             :      size (e.g. 4+3 beats 5+2). */
     753         557 :   ulong grp_cnt = (lane_cnt+4UL)/5UL;
     754        1173 :   while( lane_cnt ) {
     755         616 :     ulong k = (lane_cnt+grp_cnt-1UL)/grp_cnt;
     756         616 :     switch( k ) {
     757          83 :     case 5UL: fd_sha256_hash_32_repeated_x5( in, out, cnt ); break;
     758         129 :     case 4UL: fd_sha256_hash_32_repeated_x4( in, out, cnt ); break;
     759         266 :     case 3UL: fd_sha256_hash_32_repeated_x3( in, out, cnt ); break;
     760          69 :     case 2UL: fd_sha256_hash_32_repeated_x2( in, out, cnt ); break;
     761          69 :     default:  fd_sha256_hash_32_repeated   ( in, out, cnt ); break;
     762         616 :     }
     763         616 :     in += 32UL*k; out += 32UL*k; lane_cnt -= k; grp_cnt--;
     764         616 :   }
     765         557 : }
     766             : 
     767             : #undef NEXT_W
     768             : #undef FOUR_ROUNDS
     769             : #undef FOUR_ROUNDS_STATE
     770             : #undef FULL_ROUNDS
     771             : 
     772             : #endif
     773             : 
     774             : #if FD_SHA256_CORE_IMPL==2
     775             : void
     776             : fd_sha256_hash_32_repeated_batch_arm( uchar const * hash_in,
     777             :                                       uchar *       hash_out,
     778             :                                       ulong         cnt,
     779             :                                       ulong         batch_cnt );
     780             : #endif
     781             : 
     782             : #if FD_HAS_AVX512
     783             : void
     784             : fd_sha256_hash_32_repeated_batch_avx512( uchar const * hash_in,
     785             :                                          uchar *       hash_out,
     786             :                                          ulong         cnt,
     787             :                                          ulong         batch_cnt );
     788             : #endif
     789             : 
     790             : /* x86 lane policy.  AVX512_LANE_MIN is the batch width at which the
     791             :    16 lane AVX-512 kernel beats running the lanes as interleaved SHA-NI
     792             :    chains (or serially without SHA-NI).  On Zen 4 SHA-NI wins at every
     793             :    width (16 lanes: 80 vs 66 M hashes/s). */
     794             : 
     795             : #if FD_SHA256_CORE_IMPL==1 || (FD_SHA256_CORE_IMPL==0 && FD_HAS_AVX512)
     796             : #define X86_BATCH 1
     797             : #if !FD_HAS_AVX512
     798             : #define AVX512_LANE_MIN (ULONG_MAX)
     799             : #elif FD_SHA256_CORE_IMPL==1 && defined(__znver4__)
     800             : #define AVX512_LANE_MIN (ULONG_MAX)
     801             : #elif defined(__znver5__)
     802             : #define AVX512_LANE_MIN (6UL) /* Zen 5 has high AVX-512 throughput */
     803             : #else
     804        1359 : #define AVX512_LANE_MIN (8UL) /* Baseline 1 IPC AVX-512 needs more batching to win against SHA-NI */
     805             : #endif
     806             : #endif
     807             : 
     808             : void
     809             : fd_sha256_hash_32_repeated_batch( void const * _hash_in,
     810             :                                   void *       _hash_out,
     811             :                                   ulong        cnt,
     812        3255 :                                   ulong        batch_cnt ) {
     813        3255 :   uchar const * hash_in  = (uchar const *)_hash_in;
     814        3255 :   uchar       * hash_out = (uchar       *)_hash_out;
     815        3255 :   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() ));
     816             : #if FD_SHA256_CORE_IMPL==2
     817             :   fd_sha256_hash_32_repeated_batch_arm( hash_in, hash_out, cnt, batch_cnt );
     818             :   return;
     819             : #elif defined(X86_BATCH)
     820             : # if FD_HAS_AVX512
     821        1205 :   if( batch_cnt>=AVX512_LANE_MIN ) {
     822         648 :     fd_sha256_hash_32_repeated_batch_avx512( hash_in, hash_out, cnt, batch_cnt );
     823         648 :     return;
     824         648 :   }
     825         557 : # endif
     826         557 : # if FD_SHA256_CORE_IMPL==1
     827         557 :   fd_sha256_hash_32_repeated_shani( hash_in, hash_out, cnt, batch_cnt );
     828         557 :   return;
     829           0 : # endif
     830           0 : #endif
     831        3078 :   for( ulong i=0UL; i<batch_cnt; i++ ) {
     832        1028 :     fd_sha256_hash_32_repeated( hash_in+32*i, hash_out+32*i, cnt );
     833        1028 :   }
     834        2050 : }
     835             : 
     836             : #ifdef X86_BATCH
     837             : 
     838             : ulong
     839         105 : fd_sha256_simd_lane_min( void ) {
     840         105 : # if FD_SHA256_CORE_IMPL==1
     841         105 :   return fd_ulong_min( 2UL, AVX512_LANE_MIN );
     842             : # else
     843             :   return AVX512_LANE_MIN;
     844             : # endif
     845         105 : }
     846             : 
     847        1310 : ulong fd_sha256_simd_lane_max( void ) { return 16UL; }
     848             : 
     849             : ulong
     850          49 : fd_sha256_simd_iter_cost_q8( ulong lane_cnt ) {
     851          49 :   if( lane_cnt>=AVX512_LANE_MIN ) return 1357UL; /* 5.3x on Zen 5: 16 lanes at 96.5 M hashes/s vs 31.7 M hashes/s single lane with SHA-NI */
     852          32 : # if FD_SHA256_CORE_IMPL==1
     853             :   /* Zen 4, per group of k interleaved chains: 256*k*rate(1)/rate(k) */
     854          32 :   static ushort const group_cost_q8[6] = { 0, 256, 273, 322, 398, 495 };
     855          32 :   ulong cost    = 0UL;
     856          32 :   ulong grp_cnt = (lane_cnt+4UL)/5UL;
     857          68 :   while( lane_cnt ) {
     858          36 :     ulong k = (lane_cnt+grp_cnt-1UL)/grp_cnt;
     859          36 :     cost += group_cost_q8[ k ]; lane_cnt -= k; grp_cnt--;
     860          36 :   }
     861          32 :   return fd_ulong_max( cost, 256UL );
     862             : # else
     863             :   return fd_ulong_max( lane_cnt, 1UL )*256UL;
     864             : # endif
     865          49 : }
     866             : 
     867             : #undef AVX512_LANE_MIN
     868             : #undef X86_BATCH
     869             : 
     870             : #else
     871             : 
     872         208 : __attribute__((weak)) ulong fd_sha256_simd_lane_min( void ) { return ULONG_MAX; }
     873        2260 : __attribute__((weak)) ulong fd_sha256_simd_lane_max( void ) { return 1UL; }
     874           2 : __attribute__((weak)) ulong fd_sha256_simd_iter_cost_q8( ulong lane_cnt ) { return fd_ulong_max( lane_cnt, 1UL )*256UL; }
     875             : 
     876             : #endif

Generated by: LCOV version 1.14