LCOV - code coverage report
Current view: top level - ballet/sha256 - fd_sha256.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 66 66 100.0 %
Date: 2026-11-05 04:25:06 Functions: 18 1470 1.2 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_ballet_sha256_fd_sha256_h
       2             : #define HEADER_fd_src_ballet_sha256_fd_sha256_h
       3             : 
       4             : /* fd_sha256 provides APIs for SHA-256 hashing of messages. */
       5             : 
       6             : #include "../fd_ballet_base.h"
       7             : 
       8             : /* FD_SHA256_{ALIGN,FOOTPRINT} describe the alignment and footprint needed
       9             :    for a memory region to hold a fd_sha256_t.  ALIGN is a positive
      10             :    integer power of 2.  FOOTPRINT is a multiple of align.  ALIGN is
      11             :    recommended to be at least double cache line to mitigate various
      12             :    kinds of false sharing.  These are provided to facilitate compile
      13             :    time declarations. */
      14             : 
      15     1122054 : #define FD_SHA256_ALIGN     (128UL)
      16      561015 : #define FD_SHA256_FOOTPRINT (128UL)
      17             : 
      18             : /* FD_SHA256_{LG_HASH_SZ,HASH_SZ} describe the size of a SHA256 hash
      19             :    in bytes.  HASH_SZ==2^LG_HASH_SZ==32. */
      20             : 
      21             : #define FD_SHA256_LG_HASH_SZ (5)
      22      561273 : #define FD_SHA256_HASH_SZ    (32UL) /* == 2^FD_SHA256_LG_HASH_SZ, explicit to workaround compiler limitations */
      23             : 
      24             : /* FD_SHA256_{LG_BLOCK_SZ,BLOCK_SZ} describe the size of a SHA256
      25             :    hash block in byte.  BLOCK_SZ==2^LG_BLOCK_SZ==64. */
      26             : 
      27    55724783 : #define FD_SHA256_LG_BLOCK_SZ (6)
      28   137672260 : #define FD_SHA256_BLOCK_SZ    (64UL) /* == 2^FD_SHA256_LG_BLOCK_SZ, explicit to workaround compiler limitations */
      29             : 
      30             : /* A fd_sha256_t should be treated as an opaque handle of a sha256
      31             :    calculation state.  (It technically isn't here facilitate compile
      32             :    time declarations of fd_sha256_t memory.) */
      33             : 
      34      561012 : #define FD_SHA256_MAGIC (0xF17EDA2CE54A2560) /* FIREDANCE SHA256 V0 */
      35             : 
      36             : /* FD_SHA256_PRIVATE_{LG_BUF_MAX,BUF_MAX} describe the size of the
      37             :    internal buffer used by the sha256 computation object.  This is for
      38             :    internal use only.  BUF_MAX==2^LG_BUF_MAX==2*FD_SHA256_HASH_SZ==64. */
      39             : 
      40    55724783 : #define FD_SHA256_PRIVATE_LG_BUF_MAX FD_SHA256_LG_BLOCK_SZ
      41    98616670 : #define FD_SHA256_PRIVATE_BUF_MAX    FD_SHA256_BLOCK_SZ
      42             : 
      43             : struct __attribute__((aligned(FD_SHA256_ALIGN))) fd_sha256_private {
      44             : 
      45             :   /* This point is 128-byte aligned */
      46             : 
      47             :   uchar buf[ FD_SHA256_PRIVATE_BUF_MAX ];
      48             : 
      49             :   /* This point is 64-byte aligned */
      50             : 
      51             :   uint  state[ FD_SHA256_HASH_SZ / sizeof(uint) ];
      52             : 
      53             :   /* This point is 32-byte aligned */
      54             : 
      55             :   ulong magic;    /* ==FD_SHA256_MAGIC */
      56             :   ulong buf_used; /* Number of buffered bytes, in [0,FD_SHA256_BUF_MAX) */
      57             :   ulong bit_cnt;  /* How many bits have been appended total */
      58             : 
      59             :   /* Padding to 128-byte here */
      60             : };
      61             : 
      62             : typedef struct fd_sha256_private fd_sha256_t;
      63             : 
      64             : FD_PROTOTYPES_BEGIN
      65             : 
      66             : /* fd_sha256_{align,footprint,new,join,leave,delete} usage is identical to
      67             :    that of their fd_sha512 counterparts.  See ../sha512/fd_sha512.h */
      68             : 
      69             : FD_FN_CONST ulong
      70             : fd_sha256_align( void );
      71             : 
      72             : FD_FN_CONST ulong
      73             : fd_sha256_footprint( void );
      74             : 
      75             : void *
      76             : fd_sha256_new( void * shmem );
      77             : 
      78             : fd_sha256_t *
      79             : fd_sha256_join( void * shsha );
      80             : 
      81             : void *
      82             : fd_sha256_leave( fd_sha256_t * sha );
      83             : 
      84             : void *
      85             : fd_sha256_delete( void * shsha );
      86             : 
      87             : /* fd_sha256_init starts a sha256 calculation.  sha is assumed to be a
      88             :    current local join to a sha256 calculation state with no other
      89             :    concurrent operation that would modify the state while this is
      90             :    executing.  Any preexisting state for an in-progress or recently
      91             :    completed calculation will be discarded.  Returns sha (on return, sha
      92             :    will have the state of a new in-progress calculation). */
      93             : 
      94             : fd_sha256_t *
      95             : fd_sha256_init( fd_sha256_t * sha );
      96             : 
      97             : /* fd_sha256_append adds sz bytes locally pointed to by data an
      98             :    in-progress sha256 calculation.  sha, data and sz are assumed to be
      99             :    valid (i.e. sha is a current local join to a sha256 calculation state
     100             :    with no other concurrent operations that would modify the state while
     101             :    this is executing, data points to the first of the sz bytes and will
     102             :    be unmodified while this is running with no interest retained after
     103             :    return ... data==NULL is fine if sz==0).  Returns sha (on return, sha
     104             :    will have the updated state of the in-progress calculation).
     105             : 
     106             :    It does not matter how the user group data bytes for a sha256
     107             :    calculation; the final hash will be identical.  It is preferable for
     108             :    performance to try to append as many bytes as possible as a time
     109             :    though.  It is also preferable for performance if sz is a multiple of
     110             :    64 for all but the last append (it is also preferable if sz is less
     111             :    than 56 for the last append). */
     112             : 
     113             : fd_sha256_t *
     114             : fd_sha256_append( fd_sha256_t * sha,
     115             :                   void const *  data,
     116             :                   ulong         sz );
     117             : 
     118             : /* fd_sha256_fini finishes a sha256 calculation.  sha and hash are
     119             :    assumed to be valid (i.e. sha is a local join to a sha256 calculation
     120             :    state that has an in-progress calculation with no other concurrent
     121             :    operations that would modify the state while this is executing and
     122             :    hash points to the first byte of a 32-byte memory region where the
     123             :    result of the calculation should be stored).  Returns hash (on
     124             :    return, there will be no calculation in-progress on sha and 32-byte
     125             :    buffer pointed to by hash will be populated with the calculation
     126             :    result). */
     127             : /* FIXME: THIS SHOULD PROBABLY RETURN A FD_SHA256_T */
     128             : 
     129             : void *
     130             : fd_sha256_fini( fd_sha256_t * sha,
     131             :                 void *        hash );
     132             : 
     133             : /* fd_sha256_hash is a streamlined implementation of:
     134             : 
     135             :      fd_sha256_t sha[1];
     136             :      return fd_sha256_fini( fd_sha256_append( fd_sha256_init( sha ), data, sz ), hash )
     137             : 
     138             :    This can be faster for small messages because it can eliminate
     139             :    function call overheads, branches, copies and data marshalling under
     140             :    the hood (things like binary Merkle tree construction were designed
     141             :    do lots of such operations). */
     142             : /* FIXME: ADD NEW/JOIN/LEAVE/DELETE TO DOCUMENTATION */
     143             : /* FIXME: PROBABLY SHOULD HAVE AN ABORT API */
     144             : /* FIXME: UPDATE OTHER HASH FUNCTIONS SIMILARLY */
     145             : 
     146             : void *
     147             : fd_sha256_hash( void const * data,
     148             :                 ulong        sz,
     149             :                 void *       hash );
     150             : 
     151             : FD_PROTOTYPES_END
     152             : 
     153             : #if 0 /* SHA256 batch API details */
     154             : 
     155             : /* FD_SHA256_BATCH_{ALIGN,FOOTPRINT} return the alignment and footprint
     156             :    in bytes required for a region of memory to can hold the state of an
     157             :    in-progress set of SHA-256 calculations.  ALIGN will be an integer
     158             :    power of 2 and FOOTPRINT will be a multiple of ALIGN.  These are to
     159             :    facilitate compile time declarations. */
     160             : 
     161             : #define FD_SHA256_BATCH_ALIGN     ...
     162             : #define FD_SHA256_BATCH_FOOTPRINT ...
     163             : 
     164             : /* FD_SHA256_BATCH_MAX returns the batch size used under the hood.
     165             :    Will be positive.  Users should not normally need use this for
     166             :    anything. */
     167             : 
     168             : #define FD_SHA256_BATCH_MAX       ...
     169             : 
     170             : /* A fd_sha256_batch_t is an opaque handle for a set of SHA-256
     171             :    calculations. */
     172             : 
     173             : struct fd_sha256_private_batch;
     174             : typedef struct fd_sha256_private_batch fd_sha256_batch_t;
     175             : 
     176             : /* fd_sha256_batch_{align,footprint} return
     177             :    FD_SHA256_BATCH_{ALIGN,FOOTPRINT} respectively. */
     178             : 
     179             : ulong fd_sha256_batch_align    ( void );
     180             : ulong fd_sha256_batch_footprint( void );
     181             : 
     182             : /* fd_sha256_batch_init starts a new batch of SHA-256 calculations.  The
     183             :    state of the in-progress calculation will be held in the memory
     184             :    region whose first byte in the local address space is pointed to by
     185             :    mem.  The region should have the appropriate alignment and footprint
     186             :    and should not be read, changed or deleted until fini or abort is
     187             :    called on the in-progress calculation.
     188             : 
     189             :    Returns a handle to the in-progress batch calculation.  As this is
     190             :    used in HPC contexts, does no input validation. */
     191             : 
     192             : fd_sha256_batch_t *
     193             : fd_sha256_batch_init( void * mem );
     194             : 
     195             : /* fd_sha256_batch_add adds the sz byte message whose first byte in the
     196             :    local address space is pointed to by data to the in-progress batch
     197             :    calculation whose handle is batch.  The result of the calculation
     198             :    will be stored at the 32-byte memory region whose first byte in the
     199             :    local address space is pointed to by hash.
     200             : 
     201             :    There are _no_ alignment restrictions on data and hash and _no_
     202             :    restrictions on sz.  After a message is added, that message should
     203             :    not be changed or deleted until the fini or abort is called on the
     204             :    in-progress calculation.  Likewise, the hash memory region shot not
     205             :    be read, written or deleted until the calculation has completed.
     206             : 
     207             :    Messages can overlap and/or be added to a batch multiple times.  Each
     208             :    hash location added to a batch should not overlap any other hash
     209             :    location of calculation state or message region.  (Hash reuse /
     210             :    overlap have indeterminant but non-crashing behavior as the
     211             :    implementation under the hood is free to execute the elements of the
     212             :    batch in whatever order it sees fit and potentially do those
     213             :    calculations incrementally / in the background / ... as the batch is
     214             :    assembled.)
     215             : 
     216             :    Depending on the implementation, it might help performance to cluster
     217             :    adds of similar sized messages together.  Likewise, it can be
     218             :    advantageous to use aligned message regions, aligned hash regions and
     219             :    messages sizes that are a multiple of a SHA block size.  None of this
     220             :    is required though.
     221             : 
     222             :    Returns batch (which will still be an in progress batch calculation).
     223             :    As this is used in HPC contexts, does no input validation. */
     224             : 
     225             : fd_sha256_batch_t *
     226             : fd_sha256_batch_add( fd_sha256_batch_t * batch,
     227             :                      void const *        data,
     228             :                      ulong               sz,
     229             :                      void *              hash );
     230             : 
     231             : /* fd_sha256_batch_fini finishes a set of SHA-256 calculations.  On
     232             :    return, all the hash memory regions will be populated with the
     233             :    corresponding message hash.  Returns a pointer to the memory region
     234             :    used to hold the calculation state (contents undefined) and the
     235             :    calculation will no longer be in progress.  As this is used in HPC
     236             :    contexts, does no input validation. */
     237             : 
     238             : void *
     239             : fd_sha256_batch_fini( fd_sha256_batch_t * batch );
     240             : 
     241             : /* fd_sha256_batch_abort aborts an in-progress set of SHA-256
     242             :    calculations.  There is no guarantee which individual messages (if
     243             :    any) had their hashes computed and the contents of the hash memory
     244             :    regions is undefined.  Returns a pointer to the memory region used to
     245             :    hold the calculation state (contents undefined) and the calculation
     246             :    will no longer be in progress.  As this is used in HPC contexts, does
     247             :    no input validation. */
     248             : 
     249             : void *
     250             : fd_sha256_batch_abort( fd_sha256_batch_t * batch );
     251             : 
     252             : #endif
     253             : 
     254             : #ifndef FD_SHA256_BATCH_IMPL
     255             : #if FD_HAS_AVX512
     256             : #define FD_SHA256_BATCH_IMPL 2
     257             : #elif FD_HAS_AVX && !defined(__tune_znver1__) && !defined(__tune_znver2__) && !defined(__tune_znver3__)
     258             : #define FD_SHA256_BATCH_IMPL 1
     259             : #else
     260             : #define FD_SHA256_BATCH_IMPL 0
     261             : #endif
     262             : #endif
     263             : 
     264             : #if FD_SHA256_BATCH_IMPL==0 /* Reference batching implementation */
     265             : 
     266             : #define FD_SHA256_BATCH_ALIGN     (1UL)
     267             : #define FD_SHA256_BATCH_FOOTPRINT (1UL)
     268             : #define FD_SHA256_BATCH_MAX       (1UL)
     269             : 
     270             : typedef uchar fd_sha256_batch_t;
     271             : 
     272             : FD_PROTOTYPES_BEGIN
     273             : 
     274             : FD_FN_CONST static inline ulong fd_sha256_batch_align    ( void ) { return alignof(fd_sha256_batch_t); }
     275             : FD_FN_CONST static inline ulong fd_sha256_batch_footprint( void ) { return sizeof (fd_sha256_batch_t); }
     276             : 
     277             : static inline fd_sha256_batch_t * fd_sha256_batch_init( void * mem ) { return (fd_sha256_batch_t *)mem; }
     278             : 
     279             : static inline fd_sha256_batch_t *
     280             : fd_sha256_batch_add( fd_sha256_batch_t * batch,
     281             :                      void const *        data,
     282             :                      ulong               sz,
     283             :                      void *              hash ) {
     284             :   fd_sha256_hash( data, sz, hash );
     285             :   return batch;
     286             : }
     287             : 
     288             : static inline void * fd_sha256_batch_fini ( fd_sha256_batch_t * batch ) { return (void *)batch; }
     289             : static inline void * fd_sha256_batch_abort( fd_sha256_batch_t * batch ) { return (void *)batch; }
     290             : 
     291             : FD_PROTOTYPES_END
     292             : 
     293             : #elif FD_SHA256_BATCH_IMPL==1 /* AVX accelerated batching implementation */
     294             : 
     295             : #define FD_SHA256_BATCH_ALIGN     (128UL)
     296             : #define FD_SHA256_BATCH_FOOTPRINT (256UL)
     297     1386908 : #define FD_SHA256_BATCH_MAX       (8UL)
     298             : 
     299             : /* This is exposed here to facilitate inlining various operations */
     300             : 
     301             : struct __attribute__((aligned(FD_SHA256_BATCH_ALIGN))) fd_sha256_private_batch {
     302             :   void const * data[ FD_SHA256_BATCH_MAX ]; /* AVX aligned */
     303             :   ulong        sz  [ FD_SHA256_BATCH_MAX ]; /* AVX aligned */
     304             :   void *       hash[ FD_SHA256_BATCH_MAX ]; /* AVX aligned */
     305             :   ulong        cnt;
     306             : };
     307             : 
     308             : typedef struct fd_sha256_private_batch fd_sha256_batch_t;
     309             : 
     310             : FD_PROTOTYPES_BEGIN
     311             : 
     312             : /* Internal use only */
     313             : 
     314             : void
     315             : fd_sha256_private_batch_avx( ulong          batch_cnt,    /* In [1,FD_SHA256_BATCH_MAX] */
     316             :                              void const *   batch_data,   /* Indexed [0,FD_SHA256_BATCH_MAX), aligned 32,
     317             :                                                              only [0,batch_cnt) used, essentially a msg_t const * const * */
     318             :                              ulong const *  batch_sz,     /* Indexed [0,FD_SHA256_BATCH_MAX), aligned 32,
     319             :                                                              only [0,batch_cnt) used */
     320             :                              void * const * batch_hash ); /* Indexed [0,FD_SHA256_BATCH_MAX), aligned 32,
     321             :                                                              only [0,batch_cnt) used */
     322             : 
     323           2 : FD_FN_CONST static inline ulong fd_sha256_batch_align    ( void ) { return alignof(fd_sha256_batch_t); }
     324           2 : FD_FN_CONST static inline ulong fd_sha256_batch_footprint( void ) { return sizeof (fd_sha256_batch_t); }
     325             : 
     326             : static inline fd_sha256_batch_t *
     327     1525120 : fd_sha256_batch_init( void * mem ) {
     328     1525120 :   fd_sha256_batch_t * batch = (fd_sha256_batch_t *)mem;
     329     1525120 :   batch->cnt = 0UL;
     330     1525120 :   return batch;
     331     1525120 : }
     332             : 
     333             : static inline fd_sha256_batch_t *
     334             : fd_sha256_batch_add( fd_sha256_batch_t * batch,
     335             :                      void const *        data,
     336             :                      ulong               sz,
     337    14968388 :                      void *              hash ) {
     338    14968388 :   ulong batch_cnt = batch->cnt;
     339    14968388 :   batch->data[ batch_cnt ] = data;
     340    14968388 :   batch->sz  [ batch_cnt ] = sz;
     341    14968388 :   batch->hash[ batch_cnt ] = hash;
     342    14968388 :   batch_cnt++;
     343    14968388 :   if( FD_UNLIKELY( batch_cnt==FD_SHA256_BATCH_MAX ) ) {
     344     1676678 :     fd_sha256_private_batch_avx( batch_cnt, batch->data, batch->sz, batch->hash );
     345     1676678 :     batch_cnt = 0UL;
     346     1676678 :   }
     347    14968388 :   batch->cnt = batch_cnt;
     348    14968388 :   return batch;
     349    14968388 : }
     350             : 
     351             : static inline void *
     352     1523052 : fd_sha256_batch_fini( fd_sha256_batch_t * batch ) {
     353     1523052 :   ulong batch_cnt = batch->cnt;
     354     1523052 :   if( FD_LIKELY( batch_cnt ) ) fd_sha256_private_batch_avx( batch_cnt, batch->data, batch->sz, batch->hash );
     355     1523052 :   return (void *)batch;
     356     1523052 : }
     357             : 
     358             : static inline void *
     359        2068 : fd_sha256_batch_abort( fd_sha256_batch_t * batch ) {
     360        2068 :   return (void *)batch;
     361        2068 : }
     362             : 
     363             : FD_PROTOTYPES_END
     364             : 
     365             : #elif FD_SHA256_BATCH_IMPL==2 /* AVX-512 accelerated batching implementation */
     366             : 
     367             : #define FD_SHA256_BATCH_ALIGN     (128UL)
     368             : #define FD_SHA256_BATCH_FOOTPRINT (512UL)
     369      573228 : #define FD_SHA256_BATCH_MAX       (16UL)
     370             : 
     371             : /* This is exposed here to facilitate inlining various operations */
     372             : 
     373             : struct __attribute__((aligned(FD_SHA256_BATCH_ALIGN))) fd_sha256_private_batch {
     374             :   void const * data[ FD_SHA256_BATCH_MAX ]; /* AVX aligned */
     375             :   ulong        sz  [ FD_SHA256_BATCH_MAX ]; /* AVX aligned */
     376             :   void *       hash[ FD_SHA256_BATCH_MAX ]; /* AVX aligned */
     377             :   ulong        cnt;
     378             : };
     379             : 
     380             : typedef struct fd_sha256_private_batch fd_sha256_batch_t;
     381             : 
     382             : FD_PROTOTYPES_BEGIN
     383             : 
     384             : /* Internal use only */
     385             : 
     386             : void
     387             : fd_sha256_private_batch_avx512( ulong          batch_cnt,    /* In [1,FD_SHA256_BATCH_MAX] */
     388             :                                 void const *   batch_data,   /* Indexed [0,FD_SHA256_BATCH_MAX), aligned 32,
     389             :                                                                 only [0,batch_cnt) used, essentially a msg_t const * const * */
     390             :                                 ulong const *  batch_sz,     /* Indexed [0,FD_SHA256_BATCH_MAX), aligned 32,
     391             :                                                                 only [0,batch_cnt) used */
     392             :                                 void * const * batch_hash ); /* Indexed [0,FD_SHA256_BATCH_MAX), aligned 32,
     393             :                                                                 only [0,batch_cnt) used */
     394             : 
     395           1 : FD_FN_CONST static inline ulong fd_sha256_batch_align    ( void ) { return alignof(fd_sha256_batch_t); }
     396           1 : FD_FN_CONST static inline ulong fd_sha256_batch_footprint( void ) { return sizeof (fd_sha256_batch_t); }
     397             : 
     398             : static inline fd_sha256_batch_t *
     399      669671 : fd_sha256_batch_init( void * mem ) {
     400      669671 :   fd_sha256_batch_t * batch = (fd_sha256_batch_t *)mem;
     401      669671 :   batch->cnt = 0UL;
     402      669671 :   return batch;
     403      669671 : }
     404             : 
     405             : static inline fd_sha256_batch_t *
     406             : fd_sha256_batch_add( fd_sha256_batch_t * batch,
     407             :                      void const *        data,
     408             :                      ulong               sz,
     409     7516970 :                      void *              hash ) {
     410     7516970 :   ulong batch_cnt = batch->cnt;
     411     7516970 :   batch->data[ batch_cnt ] = data;
     412     7516970 :   batch->sz  [ batch_cnt ] = sz;
     413     7516970 :   batch->hash[ batch_cnt ] = hash;
     414     7516970 :   batch_cnt++;
     415     7516970 :   if( FD_UNLIKELY( batch_cnt==FD_SHA256_BATCH_MAX ) ) {
     416      397513 :     fd_sha256_private_batch_avx512( batch_cnt, batch->data, batch->sz, batch->hash );
     417      397513 :     batch_cnt = 0UL;
     418      397513 :   }
     419     7516970 :   batch->cnt = batch_cnt;
     420     7516970 :   return batch;
     421     7516970 : }
     422             : 
     423             : static inline void *
     424      668637 : fd_sha256_batch_fini( fd_sha256_batch_t * batch ) {
     425      668637 :   ulong batch_cnt = batch->cnt;
     426      668637 :   if( FD_LIKELY( batch_cnt ) ) fd_sha256_private_batch_avx512( batch_cnt, batch->data, batch->sz, batch->hash );
     427      668637 :   return (void *)batch;
     428      668637 : }
     429             : 
     430             : static inline void *
     431        1034 : fd_sha256_batch_abort( fd_sha256_batch_t * batch ) {
     432        1034 :   return (void *)batch;
     433        1034 : }
     434             : 
     435             : FD_PROTOTYPES_END
     436             : 
     437             : #else
     438             : #error "Unsupported FD_SHA256_BATCH_IMPL"
     439             : #endif
     440             : 
     441             : #endif /* HEADER_fd_src_ballet_sha256_fd_sha256_h */

Generated by: LCOV version 1.14