LCOV - code coverage report
Current view: top level - ballet/sha256 - fd_sha256.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 288 294 98.0 %
Date: 2026-11-05 04:25:06 Functions: 12 12 100.0 %

          Line data    Source code
       1             : #include "fd_sha256.h"
       2             : #include "fd_sha256_constants.h"
       3             : 
       4             : #if FD_HAS_SHANI
       5             : #include "../../util/simd/fd_sse.h"
       6             : #endif
       7             : 
       8             : ulong
       9     1122054 : fd_sha256_align( void ) {
      10     1122054 :   return FD_SHA256_ALIGN;
      11     1122054 : }
      12             : 
      13             : ulong
      14      561015 : fd_sha256_footprint( void ) {
      15      561015 :   return FD_SHA256_FOOTPRINT;
      16      561015 : }
      17             : 
      18             : void *
      19      561018 : fd_sha256_new( void * shmem ) {
      20      561018 :   fd_sha256_t * sha = (fd_sha256_t *)shmem;
      21             : 
      22      561018 :   if( FD_UNLIKELY( !shmem ) ) {
      23           3 :     FD_LOG_WARNING(( "NULL shmem" ));
      24           3 :     return NULL;
      25           3 :   }
      26             : 
      27      561015 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_sha256_align() ) ) ) {
      28           3 :     FD_LOG_WARNING(( "misaligned shmem" ));
      29           3 :     return NULL;
      30           3 :   }
      31             : 
      32      561012 :   ulong footprint = fd_sha256_footprint();
      33             : 
      34      561012 :   fd_memset( sha, 0, footprint );
      35             : 
      36      561012 :   FD_COMPILER_MFENCE();
      37      561012 :   FD_VOLATILE( sha->magic ) = FD_SHA256_MAGIC;
      38      561012 :   FD_COMPILER_MFENCE();
      39             : 
      40      561012 :   return (void *)sha;
      41      561015 : }
      42             : 
      43             : fd_sha256_t *
      44      561018 : fd_sha256_join( void * shsha ) {
      45             : 
      46      561018 :   if( FD_UNLIKELY( !shsha ) ) {
      47           3 :     FD_LOG_WARNING(( "NULL shsha" ));
      48           3 :     return NULL;
      49           3 :   }
      50             : 
      51      561015 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shsha, fd_sha256_align() ) ) ) {
      52           3 :     FD_LOG_WARNING(( "misaligned shsha" ));
      53           3 :     return NULL;
      54           3 :   }
      55             : 
      56      561012 :   fd_sha256_t * sha = (fd_sha256_t *)shsha;
      57             : 
      58      561012 :   if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
      59           0 :     FD_LOG_WARNING(( "bad magic" ));
      60           0 :     return NULL;
      61           0 :   }
      62             : 
      63      561012 :   return sha;
      64      561012 : }
      65             : 
      66             : void *
      67          21 : fd_sha256_leave( fd_sha256_t * sha ) {
      68             : 
      69          21 :   if( FD_UNLIKELY( !sha ) ) {
      70           3 :     FD_LOG_WARNING(( "NULL sha" ));
      71           3 :     return NULL;
      72           3 :   }
      73             : 
      74          18 :   return (void *)sha;
      75          21 : }
      76             : 
      77             : void *
      78          24 : fd_sha256_delete( void * shsha ) {
      79             : 
      80          24 :   if( FD_UNLIKELY( !shsha ) ) {
      81           3 :     FD_LOG_WARNING(( "NULL shsha" ));
      82           3 :     return NULL;
      83           3 :   }
      84             : 
      85          21 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shsha, fd_sha256_align() ) ) ) {
      86           3 :     FD_LOG_WARNING(( "misaligned shsha" ));
      87           3 :     return NULL;
      88           3 :   }
      89             : 
      90          18 :   fd_sha256_t * sha = (fd_sha256_t *)shsha;
      91             : 
      92          18 :   if( FD_UNLIKELY( sha->magic!=FD_SHA256_MAGIC ) ) {
      93           0 :     FD_LOG_WARNING(( "bad magic" ));
      94           0 :     return NULL;
      95           0 :   }
      96             : 
      97          18 :   FD_COMPILER_MFENCE();
      98          18 :   FD_VOLATILE( sha->magic ) = 0UL;
      99          18 :   FD_COMPILER_MFENCE();
     100             : 
     101          18 :   return (void *)sha;
     102          18 : }
     103             : 
     104             : #ifndef FD_SHA256_CORE_IMPL
     105             : #if FD_HAS_ARM_SHA256
     106             : #define FD_SHA256_CORE_IMPL 2
     107             : #elif FD_HAS_SHANI
     108             : #define FD_SHA256_CORE_IMPL 1
     109             : #elif FD_HAS_RISCV_SHA256
     110             : #define FD_SHA256_CORE_IMPL 3
     111             : #else
     112             : #define FD_SHA256_CORE_IMPL 0
     113             : #endif
     114             : #endif
     115             : 
     116             : #if FD_SHA256_CORE_IMPL==0
     117             : 
     118             : /* The implementation below was derived from OpenSSL's SHA-256
     119             :    implementation (Apache-2.0 licensed).  See in particular:
     120             : 
     121             :     https://github.com/openssl/openssl/blob/master/crypto/sha/sha256.c
     122             : 
     123             :    (link valid circa 2022-Dec).  It has been made more strict with more
     124             :    extensive implementation documentation, has been simplified and has
     125             :    been streamlined specifically for use inside Firedancer base machine
     126             :    model (no machine specific capabilities required).
     127             : 
     128             :    In particular, fd_sha256_core_ref is based on OpenSSL's
     129             :    OPENSSL_SMALL_FOOTPRINT SHA-256 implementation (Apache licensed).
     130             :    This should work anywhere but it is not the highest performance
     131             :    implementation possible.
     132             : 
     133             :    It is also straightforward to replace these implementations with HPC
     134             :    implementations that target specific machine capabilities without
     135             :    requiring any changes to caller code. */
     136             : 
     137             : static void
     138             : fd_sha256_core_ref( uint *        state,
     139             :                     uchar const * block,
     140    14908636 :                     ulong         block_cnt ) {
     141             : 
     142             : 
     143 10062820224 : # define ROTATE     fd_uint_rotate_left
     144  1118091136 : # define Sigma0(x)  (ROTATE((x),30) ^ ROTATE((x),19) ^ ROTATE((x),10))
     145  1118091136 : # define Sigma1(x)  (ROTATE((x),26) ^ ROTATE((x),21) ^ ROTATE((x),7))
     146   838568352 : # define sigma0(x)  (ROTATE((x),25) ^ ROTATE((x),14) ^ ((x)>>3))
     147   838568352 : # define sigma1(x)  (ROTATE((x),15) ^ ROTATE((x),13) ^ ((x)>>10))
     148  1118091136 : # define Ch(x,y,z)  (((x) & (y)) ^ ((~(x)) & (z)))
     149  1118091136 : # define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
     150             : 
     151    14908636 :   uchar const * W = block;
     152    17470174 :   do {
     153    17470174 :     uint a = state[0];
     154    17470174 :     uint b = state[1];
     155    17470174 :     uint c = state[2];
     156    17470174 :     uint d = state[3];
     157    17470174 :     uint e = state[4];
     158    17470174 :     uint f = state[5];
     159    17470174 :     uint g = state[6];
     160    17470174 :     uint h = state[7];
     161             : 
     162    17470174 :     uint X[16];
     163             : 
     164    17470174 :     ulong i;
     165   296992958 :     for( i=0UL; i<16UL; i++ ) {
     166   279522784 :       X[i] = fd_uint_bswap( FD_LOAD( uint, W + i*sizeof(uint) ) );
     167   279522784 :       uint T1 = X[i] + h + Sigma1(e) + Ch(e, f, g) + fd_sha256_K[i];
     168   279522784 :       uint T2 = Sigma0(a) + Maj(a, b, c);
     169   279522784 :       h = g;
     170   279522784 :       g = f;
     171   279522784 :       f = e;
     172   279522784 :       e = d + T1;
     173   279522784 :       d = c;
     174   279522784 :       c = b;
     175   279522784 :       b = a;
     176   279522784 :       a = T1 + T2;
     177   279522784 :     }
     178   856038526 :     for( ; i<64UL; i++ ) {
     179   838568352 :       uint s0 = X[(i +  1UL) & 0x0fUL];
     180   838568352 :       uint s1 = X[(i + 14UL) & 0x0fUL];
     181   838568352 :       s0 = sigma0(s0);
     182   838568352 :       s1 = sigma1(s1);
     183   838568352 :       X[i & 0xfUL] += s0 + s1 + X[(i + 9UL) & 0xfUL];
     184   838568352 :       uint T1 = X[i & 0xfUL ] + h + Sigma1(e) + Ch(e, f, g) + fd_sha256_K[i];
     185   838568352 :       uint T2 = Sigma0(a) + Maj(a, b, c);
     186   838568352 :       h = g;
     187   838568352 :       g = f;
     188   838568352 :       f = e;
     189   838568352 :       e = d + T1;
     190   838568352 :       d = c;
     191   838568352 :       c = b;
     192   838568352 :       b = a;
     193   838568352 :       a = T1 + T2;
     194   838568352 :     }
     195             : 
     196    17470174 :     state[0] += a;
     197    17470174 :     state[1] += b;
     198    17470174 :     state[2] += c;
     199    17470174 :     state[3] += d;
     200    17470174 :     state[4] += e;
     201    17470174 :     state[5] += f;
     202    17470174 :     state[6] += g;
     203    17470174 :     state[7] += h;
     204             : 
     205    17470174 :     W += 16UL*sizeof(uint);
     206    17470174 :   } while( --block_cnt );
     207             : 
     208    14908636 : # undef ROTATE
     209    14908636 : # undef Sigma0
     210    14908636 : # undef Sigma1
     211    14908636 : # undef sigma0
     212    14908636 : # undef sigma1
     213    14908636 : # undef Ch
     214    14908636 : # undef Maj
     215             : 
     216    14908636 : }
     217             : 
     218    14908636 : #define fd_sha256_core fd_sha256_core_ref
     219             : 
     220             : #elif FD_SHA256_CORE_IMPL==1
     221             : 
     222             : /* _mm_sha256rnds2_epu32 does two rounds, one from the first uint in
     223             :    wk and one from the second.  Since wk stores four rounds worth of
     224             :    message schedule values, it makes sense for the macro to do four
     225             :    rounds at a time.  We need to permute wk in between so that the
     226             :    second call to the intrinsic will use the other values. */
     227   163313024 : #define FOUR_ROUNDS( wk ) do {                                                               \
     228   163313024 :       vu_t __wk = (wk);                                                                      \
     229   163313024 :       vu_t temp_state = stateFEBA;                                                           \
     230   163313024 :       stateFEBA = _mm_sha256rnds2_epu32( stateHGDC, stateFEBA, __wk );                       \
     231   163313024 :       stateHGDC = temp_state;                                                                \
     232   163313024 :                                                                                              \
     233   163313024 :       temp_state = stateFEBA;                                                                \
     234   163313024 :       stateFEBA = _mm_sha256rnds2_epu32( stateHGDC, stateFEBA, vu_permute( __wk, 2,3,0,1 ) );\
     235   163313024 :       stateHGDC = temp_state;                                                                \
     236   163313024 :     } while( 0 )
     237             : 
     238             : 
     239             : /* For completeness, here's the documentation for _mm_sha256msg1_epu32
     240             :    and _mm_sha256msg2_epu32 in a slightly reformatted way, where all
     241             :    values are uints, and "-" indicates a don't-care value:
     242             : 
     243             :        _mm_sha256msg1_epu32( (w[j  ], w[j+1], w[j+1], w[j+3]),
     244             :                              (w[j+4], -,      -,      -     ) )
     245             :          = ( w[j  ]+s0( w[j+1] ),  w[j+1]+s0( w[j+2] ),
     246             :              w[j+2]+s0( w[j+3] ),  w[j+3]+s0( w[j+4] ) ).
     247             : 
     248             : 
     249             :        _mm_sha256msg2_epu32( (v[j  ], v[j+1], v[j+1], v[j+3]),
     250             :                              (-,      -,      w[j-2], w[j-1]) )
     251             :          sets w[j  ] = v[j  ] + s1( w[j-2] ) and
     252             :               w[j+1] = v[j+1] + s1( w[j-1] ), and then returns
     253             : 
     254             :            ( v[j  ]+s1( w[j-2] ), v[j+1]+s1( w[j-1] ),
     255             :              v[j+2]+s1( w[j  ] ), v[j+3]+s1( w[j+1] ) )   */
     256             : 
     257             : 
     258             : /* w[i] for i>= 16 is w[i-16] + s0(w[i-15]) + w[i-7] + s1(w[i-2])
     259             :    Since our vector size is 4 uints, it's only s1 that is a little
     260             :    problematic, because it references items in the same vector.
     261             :    Thankfully, the msg2 intrinsic takes care of the complexity, but we
     262             :    need to execute it last.
     263             : 
     264             :    We get w[i-16] and s0(s[i-15]) using the msg1 intrinsic, setting j =
     265             :    i-16.  For example, to compute w1013, we pass in w0003 and w0407.
     266             :    Then we can get w[i-7] by using the alignr instruction on
     267             :    (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])
     268             :    to concatenate them and shift by one uint.  Continuing with the
     269             :    example of w1013, we need w080b and w0c0f.  We then put
     270             :              v[i] = w[i-16] + s0(w[i-15]) + w[i-7],
     271             :    and invoke the msg2 intrinsic with j=i, which gives w[i], as desired.
     272             :    Each invocation of NEXT_W computes 4 values of w. */
     273             : 
     274   122484768 : #define NEXT_W( w_minus_16, w_minus_12, w_minus_8, w_minus_4 ) (__extension__({      \
     275   122484768 :     vu_t __w_i_16_s0_i_15 = _mm_sha256msg1_epu32( w_minus_16, w_minus_12 );          \
     276   122484768 :     vu_t __w_i_7          = _mm_alignr_epi8( w_minus_4, w_minus_8, 4 );              \
     277   122484768 :     _mm_sha256msg2_epu32( vu_add( __w_i_7, __w_i_16_s0_i_15 ), w_minus_4 );          \
     278   122484768 :     }))
     279             : 
     280             : /* Zen 5's sha256rnds2 has an RTP of 2, while Zen 4's has an RTP of 1. We can
     281             :    win some performance by moving the schedule updates earlier in the loop. */
     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    10207064 : #define FULL_ROUNDS() do {                                                                                        \
     303    10207064 :     /*                                              */ FOUR_ROUNDS( vu_add( w0003, vu_ld( fd_sha256_K+ 0UL ) ) ); \
     304    10207064 :     /*                                              */ FOUR_ROUNDS( vu_add( w0407, vu_ld( fd_sha256_K+ 4UL ) ) ); \
     305    10207064 :     /*                                              */ FOUR_ROUNDS( vu_add( w080b, vu_ld( fd_sha256_K+ 8UL ) ) ); \
     306    10207064 :     /*                                              */ FOUR_ROUNDS( vu_add( w0c0f, vu_ld( fd_sha256_K+12UL ) ) ); \
     307    10207064 :     vu_t w1013 = NEXT_W( w0003, w0407, w080b, w0c0f ); FOUR_ROUNDS( vu_add( w1013, vu_ld( fd_sha256_K+16UL ) ) ); \
     308    10207064 :     vu_t w1417 = NEXT_W( w0407, w080b, w0c0f, w1013 ); FOUR_ROUNDS( vu_add( w1417, vu_ld( fd_sha256_K+20UL ) ) ); \
     309    10207064 :     vu_t w181b = NEXT_W( w080b, w0c0f, w1013, w1417 ); FOUR_ROUNDS( vu_add( w181b, vu_ld( fd_sha256_K+24UL ) ) ); \
     310    10207064 :     vu_t w1c1f = NEXT_W( w0c0f, w1013, w1417, w181b ); FOUR_ROUNDS( vu_add( w1c1f, vu_ld( fd_sha256_K+28UL ) ) ); \
     311    10207064 :     vu_t w2023 = NEXT_W( w1013, w1417, w181b, w1c1f ); FOUR_ROUNDS( vu_add( w2023, vu_ld( fd_sha256_K+32UL ) ) ); \
     312    10207064 :     vu_t w2427 = NEXT_W( w1417, w181b, w1c1f, w2023 ); FOUR_ROUNDS( vu_add( w2427, vu_ld( fd_sha256_K+36UL ) ) ); \
     313    10207064 :     vu_t w282b = NEXT_W( w181b, w1c1f, w2023, w2427 ); FOUR_ROUNDS( vu_add( w282b, vu_ld( fd_sha256_K+40UL ) ) ); \
     314    10207064 :     vu_t w2c2f = NEXT_W( w1c1f, w2023, w2427, w282b ); FOUR_ROUNDS( vu_add( w2c2f, vu_ld( fd_sha256_K+44UL ) ) ); \
     315    10207064 :     vu_t w3033 = NEXT_W( w2023, w2427, w282b, w2c2f ); FOUR_ROUNDS( vu_add( w3033, vu_ld( fd_sha256_K+48UL ) ) ); \
     316    10207064 :     vu_t w3437 = NEXT_W( w2427, w282b, w2c2f, w3033 ); FOUR_ROUNDS( vu_add( w3437, vu_ld( fd_sha256_K+52UL ) ) ); \
     317    10207064 :     vu_t w383b = NEXT_W( w282b, w2c2f, w3033, w3437 ); FOUR_ROUNDS( vu_add( w383b, vu_ld( fd_sha256_K+56UL ) ) ); \
     318    10207064 :     vu_t w3c3f = NEXT_W( w2c2f, w3033, w3437, w383b ); FOUR_ROUNDS( vu_add( w3c3f, vu_ld( fd_sha256_K+60UL ) ) ); \
     319    10207064 :     } 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     7920912 :                        ulong         block_cnt ) {/* positive */
     327     7920912 :   vu_t stateABCD = vu_ld( state     );
     328     7920912 :   vu_t stateEFGH = vu_ld( state+4UL );
     329             : 
     330     7920912 :   vu_t baseFEBA = vu_permute2( stateEFGH, stateABCD, 1, 0, 1, 0 );
     331     7920912 :   vu_t baseHGDC = vu_permute2( stateEFGH, stateABCD, 3, 2, 3, 2 );
     332             : 
     333    18127976 :   for( ulong b=0UL; b<block_cnt; b++ ) {
     334    10207064 :     vu_t stateFEBA = baseFEBA;
     335    10207064 :     vu_t stateHGDC = baseHGDC;
     336             : 
     337    10207064 :     vu_t w0003 = vu_bswap( vu_ldu( block+64UL*b      ) );
     338    10207064 :     vu_t w0407 = vu_bswap( vu_ldu( block+64UL*b+16UL ) );
     339    10207064 :     vu_t w080b = vu_bswap( vu_ldu( block+64UL*b+32UL ) );
     340    10207064 :     vu_t w0c0f = vu_bswap( vu_ldu( block+64UL*b+48UL ) );
     341             : 
     342    10207064 :     FULL_ROUNDS();
     343             : 
     344    10207064 :     baseFEBA = vu_add( baseFEBA, stateFEBA );
     345    10207064 :     baseHGDC = vu_add( baseHGDC, stateHGDC );
     346             : 
     347    10207064 :   }
     348             : 
     349     7920912 :   stateABCD = vu_permute2( baseFEBA, baseHGDC, 3, 2, 3, 2 );
     350     7920912 :   stateEFGH = vu_permute2( baseFEBA, baseHGDC, 1, 0, 1, 0 );
     351     7920912 :   vu_st( state,     stateABCD );
     352     7920912 :   vu_st( state+4UL, stateEFGH );
     353     7920912 : }
     354             : 
     355             : #undef FULL_ROUNDS
     356             : #undef NEXT_W
     357             : #undef FOUR_ROUNDS
     358             : 
     359     7920912 : #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     1252197 : fd_sha256_init( fd_sha256_t * sha ) {
     385     1252197 :   sha->state[0] = FD_SHA256_INITIAL_A;
     386     1252197 :   sha->state[1] = FD_SHA256_INITIAL_B;
     387     1252197 :   sha->state[2] = FD_SHA256_INITIAL_C;
     388     1252197 :   sha->state[3] = FD_SHA256_INITIAL_D;
     389     1252197 :   sha->state[4] = FD_SHA256_INITIAL_E;
     390     1252197 :   sha->state[5] = FD_SHA256_INITIAL_F;
     391     1252197 :   sha->state[6] = FD_SHA256_INITIAL_G;
     392     1252197 :   sha->state[7] = FD_SHA256_INITIAL_H;
     393     1252197 :   sha->buf_used = 0UL;
     394     1252197 :   sha->bit_cnt  = 0UL;
     395     1252197 :   return sha;
     396     1252197 : }
     397             : 
     398             : fd_sha256_t *
     399             : fd_sha256_append( fd_sha256_t * sha,
     400             :                   void const *  _data,
     401     2677614 :                   ulong         sz ) {
     402             : 
     403             :   /* If no data to append, we are done */
     404             : 
     405     2677614 :   if( FD_UNLIKELY( !sz ) ) return sha; /* optimize for non-trivial append */
     406             : 
     407             :   /* Unpack inputs */
     408             : 
     409     2677368 :   uint *  state    = sha->state;
     410     2677368 :   uchar * buf      = sha->buf;
     411     2677368 :   ulong   buf_used = sha->buf_used;
     412     2677368 :   ulong   bit_cnt  = sha->bit_cnt;
     413             : 
     414     2677368 :   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     2677368 :   sha->bit_cnt = bit_cnt + (sz<<3);
     421             : 
     422             :   /* Handle buffered bytes from previous appends */
     423             : 
     424     2677368 :   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      309359 :     ulong buf_rem = FD_SHA256_PRIVATE_BUF_MAX - buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
     430      309359 :     if( FD_UNLIKELY( sz < buf_rem ) ) { /* optimize for large append */
     431      142494 :       fd_memcpy( buf + buf_used, data, sz );
     432      142494 :       sha->buf_used = buf_used + sz;
     433      142494 :       return sha;
     434      142494 :     }
     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      166865 :     fd_memcpy( buf + buf_used, data, buf_rem );
     441      166865 :     data += buf_rem;
     442      166865 :     sz   -= buf_rem;
     443             : 
     444      166865 :     fd_sha256_core( state, buf, 1UL );
     445      166865 :     sha->buf_used = 0UL;
     446      166865 :   }
     447             : 
     448             :   /* Append the bulk of the data */
     449             : 
     450     2534874 :   ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
     451     2534874 :   if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt ); /* optimized for large append */
     452             : 
     453             :   /* Buffer any leftover bytes */
     454             : 
     455     2534874 :   buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL); /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
     456     2534874 :   if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
     457     1418752 :     fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
     458     1418752 :     sha->buf_used = buf_used; /* In (0,FD_SHA256_PRIVATE_BUF_MAX) */
     459     1418752 :   }
     460             : 
     461     2534874 :   return sha;
     462     2677368 : }
     463             : 
     464             : void *
     465             : fd_sha256_fini( fd_sha256_t * sha,
     466     1318026 :                 void *        _hash ) {
     467             : 
     468             :   /* Unpack inputs */
     469             : 
     470     1318026 :   uint *  state    = sha->state;
     471     1318026 :   uchar * buf      = sha->buf;
     472     1318026 :   ulong   buf_used = sha->buf_used; /* In [0,FD_SHA256_PRIVATE_BUF_MAX) */
     473     1318026 :   ulong   bit_cnt  = sha->bit_cnt;
     474             : 
     475             :   /* Append the terminating message byte */
     476             : 
     477     1318026 :   buf[ buf_used ] = (uchar)0x80;
     478     1318026 :   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     1318026 :   if( FD_UNLIKELY( buf_used > (FD_SHA256_PRIVATE_BUF_MAX-8UL) ) ) { /* optimize for well aligned use of append */
     485       16814 :     fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-buf_used );
     486       16814 :     fd_sha256_core( state, buf, 1UL );
     487       16814 :     buf_used = 0UL;
     488       16814 :   }
     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     1318026 :   fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     495     1318026 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     496     1318026 :   fd_sha256_core( state, buf, 1UL );
     497             : 
     498             :   /* Unpack the result into md (annoying bswaps here) */
     499             : 
     500     1318026 :   state[0] = fd_uint_bswap( state[0] );
     501     1318026 :   state[1] = fd_uint_bswap( state[1] );
     502     1318026 :   state[2] = fd_uint_bswap( state[2] );
     503     1318026 :   state[3] = fd_uint_bswap( state[3] );
     504     1318026 :   state[4] = fd_uint_bswap( state[4] );
     505     1318026 :   state[5] = fd_uint_bswap( state[5] );
     506     1318026 :   state[6] = fd_uint_bswap( state[6] );
     507     1318026 :   state[7] = fd_uint_bswap( state[7] );
     508     1318026 :   return memcpy( _hash, state, 32 );
     509     1318026 : }
     510             : 
     511             : void *
     512             : fd_sha256_hash( void const * _data,
     513             :                 ulong        sz,
     514    15328070 :                 void *       _hash ) {
     515    15328070 :   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    15328070 :   uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ] __attribute__((aligned(128)));
     521    15328070 :   uint  state[8] __attribute__((aligned(32)));
     522             : 
     523    15328070 :   state[0] = FD_SHA256_INITIAL_A;
     524    15328070 :   state[1] = FD_SHA256_INITIAL_B;
     525    15328070 :   state[2] = FD_SHA256_INITIAL_C;
     526    15328070 :   state[3] = FD_SHA256_INITIAL_D;
     527    15328070 :   state[4] = FD_SHA256_INITIAL_E;
     528    15328070 :   state[5] = FD_SHA256_INITIAL_F;
     529    15328070 :   state[6] = FD_SHA256_INITIAL_G;
     530    15328070 :   state[7] = FD_SHA256_INITIAL_H;
     531             : 
     532    15328070 :   ulong block_cnt = sz >> FD_SHA256_PRIVATE_LG_BUF_MAX;
     533    15328070 :   if( FD_LIKELY( block_cnt ) ) fd_sha256_core( state, data, block_cnt );
     534             : 
     535    15328070 :   ulong buf_used = sz & (FD_SHA256_PRIVATE_BUF_MAX-1UL);
     536    15328070 :   if( FD_UNLIKELY( buf_used ) ) fd_memcpy( buf, data + (block_cnt << FD_SHA256_PRIVATE_LG_BUF_MAX), buf_used );
     537    15328070 :   buf[ buf_used ] = (uchar)0x80;
     538    15328070 :   buf_used++;
     539             : 
     540    15328070 :   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    15328070 :   ulong bit_cnt = sz << 3;
     547    15328070 :   fd_memset( buf + buf_used, 0, FD_SHA256_PRIVATE_BUF_MAX-8UL-buf_used );
     548    15328070 :   FD_STORE( ulong, buf+FD_SHA256_PRIVATE_BUF_MAX-8UL, fd_ulong_bswap( bit_cnt ) );
     549    15328070 :   fd_sha256_core( state, buf, 1UL );
     550             : 
     551    15328070 :   state[0] = fd_uint_bswap( state[0] );
     552    15328070 :   state[1] = fd_uint_bswap( state[1] );
     553    15328070 :   state[2] = fd_uint_bswap( state[2] );
     554    15328070 :   state[3] = fd_uint_bswap( state[3] );
     555    15328070 :   state[4] = fd_uint_bswap( state[4] );
     556    15328070 :   state[5] = fd_uint_bswap( state[5] );
     557    15328070 :   state[6] = fd_uint_bswap( state[6] );
     558    15328070 :   state[7] = fd_uint_bswap( state[7] );
     559    15328070 :   return memcpy( _hash, state, 32 );
     560    15328070 : }
     561             : 
     562             : #undef fd_sha256_core

Generated by: LCOV version 1.14