LCOV - code coverage report
Current view: top level - ballet/sha512 - fd_sha512.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 62 72 86.1 %
Date: 2024-11-13 11:58:15 Functions: 5 2135 0.2 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_ballet_sha512_fd_sha512_h
       2             : #define HEADER_fd_src_ballet_sha512_fd_sha512_h
       3             : 
       4             : /* fd_sha512 provides APIs for SHA-512 hashing of messages. */
       5             : 
       6             : #include "../fd_ballet_base.h"
       7             : 
       8             : /* FD_SHA512_{ALIGN,FOOTPRINT} describe the alignment and footprint needed
       9             :    for a memory region to hold a fd_sha512_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          27 : #define FD_SHA512_ALIGN     (128UL)
      16          15 : #define FD_SHA512_FOOTPRINT (256UL)
      17             : 
      18             : #define FD_SHA384_ALIGN     FD_SHA512_ALIGN
      19             : #define FD_SHA384_FOOTPRINT FD_SHA512_FOOTPRINT
      20             : 
      21             : /* FD_SHA512_{LG_HASH_SZ,HASH_SZ} describe the size of a SHA512 hash
      22             :    in bytes.  HASH_SZ==2^LG_HASH_SZ==64. */
      23             : 
      24             : #define FD_SHA512_LG_HASH_SZ (6)
      25     3487533 : #define FD_SHA512_HASH_SZ    (64UL) /* == 2^FD_SHA512_LG_HASH_SZ, explicit to workaround compiler limitations */
      26             : 
      27             : /* FD_SHA512_{LG_BLOCK_SZ,BLOCK_SZ} describe the size of a SHA512
      28             :    hash block in byte.  BLOCK_SZ==2^LG_BLOCK_SZ==128. */
      29             : 
      30             : #define FD_SHA512_LG_BLOCK_SZ (7)
      31           0 : #define FD_SHA512_BLOCK_SZ    (128UL) /* == 2^FD_SHA512_LG_BLOCK_SZ, explicit to workaround compiler limitations */
      32             : 
      33             : /* FD_SHA384_HASH_SZ describes the size of a SHA384 hash in bytes. */
      34             : 
      35           0 : #define FD_SHA384_HASH_SZ    (48UL)
      36             : 
      37             : /* FD_SHA384_{LG_BLOCK_SZ,BLOCK_SZ} are identical to their SHA512
      38             :    variants.  (SHA384 uses the same internal state as SHA512) */
      39             : 
      40             : #define FD_SHA384_LG_BLOCK_SZ FD_SHA512_LG_BLOCK_SZ
      41           0 : #define FD_SHA384_BLOCK_SZ    FD_SHA512_BLOCK_SZ
      42             : 
      43             : /* A fd_sha512_t should be treated as an opaque handle of a sha512
      44             :    calculation state.  (It technically isn't here facilitate compile
      45             :    time declarations of fd_sha512_t memory.) */
      46             : 
      47        2364 : #define FD_SHA512_MAGIC (0xF17EDA2CE54A5120) /* FIREDANCE SHA512 V0 */
      48             : 
      49             : /* FD_SHA512_PRIVATE_{LG_BUF_MAX,BUF_MAX} describe the size of the
      50             :    internal buffer used by the sha512 computation object.  This is for
      51             :    internal use only.  BUF_MAX==2^LG_BUF_MAX==2*FD_SHA512_HASH_SZ==128. */
      52             : 
      53    47030820 : #define FD_SHA512_PRIVATE_LG_BUF_MAX (7)
      54   116511135 : #define FD_SHA512_PRIVATE_BUF_MAX    (128UL) /* == 2^FD_SHA512_PRIVATE_LG_BUF_MAX, explicit to workaround compiler limitations */
      55             : 
      56             : struct __attribute__((aligned(FD_SHA512_ALIGN))) fd_sha512_private {
      57             : 
      58             :   /* This point is 128-byte aligned */
      59             : 
      60             :   uchar buf[ FD_SHA512_PRIVATE_BUF_MAX ]; /* Buffered message bytes (these have not been added to the hash yet),
      61             :                                              indexed [0,buf_used) */
      62             : 
      63             :   /* This point is 128-byte aligned */
      64             : 
      65             :   ulong state[ FD_SHA512_HASH_SZ / sizeof(ulong) ]; /* Current state of the hash */
      66             : 
      67             :   /* This point is 64-byte aligned */
      68             : 
      69             :   ulong magic;      /* ==FD_SHA512_MAGIC */
      70             :   ulong buf_used;   /* Number of buffered bytes, in [0,FD_SHA512_PRIVATE_BUF_MAX) */
      71             :   ulong bit_cnt_lo; /* How many bits have been appended total (lower 64-bit) */
      72             :   ulong bit_cnt_hi; /* "                                      (upper 64-bit) */
      73             : 
      74             :   /* Padding to 128-byte here */
      75             : };
      76             : 
      77             : typedef struct fd_sha512_private fd_sha512_t;
      78             : 
      79             : typedef struct fd_sha512_private fd_sha384_t;
      80             : 
      81             : FD_PROTOTYPES_BEGIN
      82             : 
      83             : /* fd_sha512_{align,footprint} give the needed alignment and footprint
      84             :    of a memory region suitable to hold a sha512 calculation state.
      85             :    Declaration / aligned_alloc / fd_alloca friendly (e.g. a memory
      86             :    region declared as "fd_sha512_t _sha[1];", or created by
      87             :    "aligned_alloc(alignof(fd_sha512_t),sizeof(fd_sha512_t))" or created
      88             :    by "fd_alloca(alignof(fd_sha512_t),sizeof(fd_sha512_t))" will all
      89             :    automatically have the needed alignment and footprint).
      90             :    fd_sha512_{align,footprint} return the same value as
      91             :    FD_SHA512_{ALIGN,FOOTPRINT}.
      92             : 
      93             :    fd_sha512_new formats memory region with suitable alignment and
      94             :    footprint suitable for holding a sha512 calculation state.  Assumes
      95             :    shmem points on the caller to the first byte of the memory region
      96             :    owned by the caller to use.  Returns shmem on success and NULL on
      97             :    failure (logs details).  The memory region will be owned by the state
      98             :    on successful return.  The caller is not joined on return.
      99             : 
     100             :    fd_sha512_join joins the caller to a sha512 calculation state.
     101             :    Assumes shsha points to the first byte of the memory region holding
     102             :    the state.  Returns a local handle to the join on success (this is
     103             :    not necessarily a simple cast of the address) and NULL on failure
     104             :    (logs details).
     105             : 
     106             :    fd_sha512_leave leaves the caller's current local join to a sha512
     107             :    calculation state.  Returns a pointer to the memory region holding
     108             :    the state on success (this is not necessarily a simple cast of the
     109             :    address) and NULL on failure (logs details).  The caller is not
     110             :    joined on successful return.
     111             : 
     112             :    fd_sha512_delete unformats a memory region that holds a sha512
     113             :    calculation state.  Assumes shsha points on the caller to the first
     114             :    byte of the memory region holding the state and that nobody is
     115             :    joined.  Returns a pointer to the memory region on success and NULL
     116             :    on failure (logs details).  The caller has ownership of the memory
     117             :    region on successful return. */
     118             : 
     119             : FD_FN_CONST ulong
     120             : fd_sha512_align( void );
     121             : 
     122             : FD_FN_CONST ulong
     123             : fd_sha512_footprint( void );
     124             : 
     125             : #define fd_sha384_align     fd_sha512_align
     126             : #define fd_sha384_footprint fd_sha512_footprint
     127             : 
     128             : void *
     129             : fd_sha512_new( void * shmem );
     130             : 
     131             : fd_sha512_t *
     132             : fd_sha512_join( void * shsha );
     133             : 
     134             : void *
     135             : fd_sha512_leave( fd_sha512_t * sha );
     136             : 
     137             : void *
     138             : fd_sha512_delete( void * shsha );
     139             : 
     140           0 : #define fd_sha384_new    fd_sha512_new
     141           0 : #define fd_sha384_join   fd_sha512_join
     142             : #define fd_sha384_leave  fd_sha512_leave
     143             : #define fd_sha384_delete fd_sha512_delete
     144             : 
     145             : /* fd_sha512_init starts a sha512 calculation.  sha is assumed to be a
     146             :    current local join to a sha512 calculation state with no other
     147             :    concurrent operation that would modify the state while this is
     148             :    executing.  Any preexisting state for an in-progress or recently
     149             :    completed calculation will be discarded.  Returns sha (on return, sha
     150             :    will have the state of a new in-progress calculation). */
     151             : 
     152             : fd_sha512_t *
     153             : fd_sha512_init( fd_sha512_t * sha );
     154             : 
     155             : fd_sha512_t *
     156             : fd_sha384_init( fd_sha512_t * sha );
     157             : 
     158             : /* fd_sha512_append adds sz bytes locally pointed to by data an
     159             :    in-progress sha512 calculation.  sha, data and sz are assumed to be
     160             :    valid (i.e. sha is a current local join to a sha512 calculation state
     161             :    with no other concurrent operations that would modify the state while
     162             :    this is executing, data points to the first of the sz bytes and will
     163             :    be unmodified while this is running with no interest retained after
     164             :    return ... data==NULL is fine if sz==0).  Returns sha (on return, sha
     165             :    will have the updated state of the in-progress calculation).
     166             : 
     167             :    It does not matter how the user group data bytes for a sha512
     168             :    calculation; the final hash will be identical.  It is preferable for
     169             :    performance to try to append as many bytes as possible as a time
     170             :    though.  It is also preferable for performance if sz is a multiple of
     171             :    128 for all but the last append (it is also preferable if sz is less
     172             :    than 112 for the last append). */
     173             : 
     174             : fd_sha512_t *
     175             : fd_sha512_append( fd_sha512_t * sha,
     176             :                   void const *  data,
     177             :                   ulong         sz );
     178             : 
     179           0 : #define fd_sha384_append fd_sha512_append
     180             : 
     181             : /* fd_sha512_fini finishes a a sha512 calculation.  sha and hash are
     182             :    assumed to be valid (i.e. sha is a local join to a sha512 calculation
     183             :    state that has an in-progress calculation with no other concurrent
     184             :    operations that would modify the state while this is executing and
     185             :    hash points to the first byte of a 64-byte memory region where the
     186             :    result of the calculation should be stored).  Returns hash (on
     187             :    return, there will be no calculation in-progress on sha and 64-byte
     188             :    buffer pointed to by hash will be populated with the calculation
     189             :    result). */
     190             : 
     191             : void *
     192             : fd_sha512_fini( fd_sha512_t * sha,
     193             :                 void *        hash );
     194             : 
     195             : /* fd_sha512_clear safely clears after a sha512 calculation.
     196             :    sha is assumed to be a current local join to a sha512 calculation
     197             :    state.  Any preexisting state for an in-progress or recently
     198             :    completed calculation will be discarded. */
     199             : 
     200             : static inline void
     201     1759947 : fd_sha512_clear( fd_sha512_t * sha ) {
     202     1759947 :   fd_sha512_init( sha );
     203     1759947 :   fd_memset_explicit( sha->buf, 0, FD_SHA512_PRIVATE_BUF_MAX );
     204     1759947 : }
     205             : 
     206             : void *
     207             : fd_sha384_fini( fd_sha384_t * sha,
     208             :                 void *        hash );
     209             : 
     210             : /* fd_sha512_hash is a streamlined implementation of:
     211             : 
     212             :      fd_sha512_t sha[1];
     213             :      return fd_sha512_fini( fd_sha512_append( fd_sha512_init( sha ), data, sz ), hash )
     214             : 
     215             :    This can be faster for small messages because it can eliminate
     216             :    function call overheads, branches, copies and data marshalling under
     217             :    the hood (things like binary Merkle tree construction were designed
     218             :    do lots of such operations). */
     219             : 
     220             : void *
     221             : fd_sha512_hash( void const * data,
     222             :                 ulong        sz,
     223             :                 void *       hash );
     224             : 
     225             : void *
     226             : fd_sha384_hash( void const * data,
     227             :                 ulong        sz,
     228             :                 void *       hash );
     229             : 
     230             : FD_PROTOTYPES_END
     231             : 
     232             : /* See fd_sha256.h for details on how use the batching API */
     233             : 
     234             : #ifndef FD_SHA512_BATCH_IMPL
     235             : #if FD_HAS_AVX512
     236             : #define FD_SHA512_BATCH_IMPL 2
     237             : #elif FD_HAS_AVX
     238             : #define FD_SHA512_BATCH_IMPL 1
     239             : #else
     240             : #define FD_SHA512_BATCH_IMPL 0
     241             : #endif
     242             : #endif
     243             : 
     244             : #if FD_SHA512_BATCH_IMPL==0 /* Reference batching implementation */
     245             : 
     246             : #define FD_SHA512_BATCH_ALIGN     (1UL)
     247             : #define FD_SHA512_BATCH_FOOTPRINT (1UL)
     248             : #define FD_SHA512_BATCH_MAX       (1UL)
     249             : 
     250             : typedef uchar fd_sha512_batch_t;
     251             : 
     252             : FD_PROTOTYPES_BEGIN
     253             : 
     254             : FD_FN_CONST static inline ulong fd_sha512_batch_align    ( void ) { return alignof(fd_sha512_batch_t); }
     255             : FD_FN_CONST static inline ulong fd_sha512_batch_footprint( void ) { return sizeof (fd_sha512_batch_t); }
     256             : 
     257             : static inline fd_sha512_batch_t * fd_sha512_batch_init( void * mem ) { return (fd_sha512_batch_t *)mem; }
     258             : 
     259             : static inline fd_sha512_batch_t *
     260             : fd_sha512_batch_add( fd_sha512_batch_t * batch,
     261             :                      void const *        data,
     262             :                      ulong               sz,
     263             :                      void *              hash ) {
     264             :   fd_sha512_hash( data, sz, hash );
     265             :   return batch;
     266             : }
     267             : 
     268             : static inline void * fd_sha512_batch_fini ( fd_sha512_batch_t * batch ) { return (void *)batch; }
     269             : static inline void * fd_sha512_batch_abort( fd_sha512_batch_t * batch ) { return (void *)batch; }
     270             : 
     271             : FD_PROTOTYPES_END
     272             : 
     273             : #elif FD_SHA512_BATCH_IMPL==1 /* AVX accelerated batching implementation */
     274             : 
     275             : #define FD_SHA512_BATCH_ALIGN     (128UL)
     276             : #define FD_SHA512_BATCH_FOOTPRINT (128UL)
     277             : #define FD_SHA512_BATCH_MAX       (4UL)
     278             : 
     279             : /* This is exposed here to facilitate inlining various operations */
     280             : 
     281             : struct __attribute__((aligned(FD_SHA512_BATCH_ALIGN))) fd_sha512_private_batch {
     282             :   void const * data[ FD_SHA512_BATCH_MAX ]; /* AVX aligned */
     283             :   ulong        sz  [ FD_SHA512_BATCH_MAX ]; /* AVX aligned */
     284             :   void *       hash[ FD_SHA512_BATCH_MAX ]; /* AVX aligned */
     285             :   ulong        cnt;
     286             : };
     287             : 
     288             : typedef struct fd_sha512_private_batch fd_sha512_batch_t;
     289             : 
     290             : FD_PROTOTYPES_BEGIN
     291             : 
     292             : /* Internal use only */
     293             : 
     294             : void
     295             : fd_sha512_private_batch_avx( ulong          batch_cnt,    /* In [1,FD_SHA512_BATCH_MAX] */
     296             :                              void const *   batch_data,   /* Indexed [0,FD_SHA512_BATCH_MAX), aligned 32,
     297             :                                                              only [0,batch_cnt) used, essentially a msg_t const * const * */
     298             :                              ulong const *  batch_sz,     /* Indexed [0,FD_SHA512_BATCH_MAX), aligned 32,
     299             :                                                              only [0,batch_cnt) used */
     300             :                              void * const * batch_hash ); /* Indexed [0,FD_SHA512_BATCH_MAX), aligned 32,
     301             :                                                              only [0,batch_cnt) used */
     302             : 
     303           0 : FD_FN_CONST static inline ulong fd_sha512_batch_align    ( void ) { return alignof(fd_sha512_batch_t); }
     304           0 : FD_FN_CONST static inline ulong fd_sha512_batch_footprint( void ) { return sizeof (fd_sha512_batch_t); }
     305             : 
     306             : static inline fd_sha512_batch_t *
     307     1223104 : fd_sha512_batch_init( void * mem ) {
     308     1223104 :   fd_sha512_batch_t * batch = (fd_sha512_batch_t *)mem;
     309     1223104 :   batch->cnt = 0UL;
     310     1223104 :   return batch;
     311     1223104 : }
     312             : 
     313             : static inline fd_sha512_batch_t *
     314             : fd_sha512_batch_add( fd_sha512_batch_t * batch,
     315             :                      void const *        data,
     316             :                      ulong               sz,
     317    13973832 :                      void *              hash ) {
     318    13973832 :   ulong batch_cnt = batch->cnt;
     319    13973832 :   batch->data[ batch_cnt ] = data;
     320    13973832 :   batch->sz  [ batch_cnt ] = sz;
     321    13973832 :   batch->hash[ batch_cnt ] = hash;
     322    13973832 :   batch_cnt++;
     323    13973832 :   if( FD_UNLIKELY( batch_cnt==FD_SHA512_BATCH_MAX ) ) {
     324     3035264 :     fd_sha512_private_batch_avx( batch_cnt, batch->data, batch->sz, batch->hash );
     325     3035264 :     batch_cnt = 0UL;
     326     3035264 :   }
     327    13973832 :   batch->cnt = batch_cnt;
     328    13973832 :   return batch;
     329    13973832 : }
     330             : 
     331             : static inline void *
     332     1214858 : fd_sha512_batch_fini( fd_sha512_batch_t * batch ) {
     333     1214858 :   ulong batch_cnt = batch->cnt;
     334     1214858 :   if( FD_LIKELY( batch_cnt ) ) fd_sha512_private_batch_avx( batch_cnt, batch->data, batch->sz, batch->hash );
     335     1214858 :   return (void *)batch;
     336     1214858 : }
     337             : 
     338             : static inline void *
     339        8246 : fd_sha512_batch_abort( fd_sha512_batch_t * batch ) {
     340        8246 :   return (void *)batch;
     341        8246 : }
     342             : 
     343             : FD_PROTOTYPES_END
     344             : 
     345             : #elif FD_SHA512_BATCH_IMPL==2 /* AVX-512 accelerated batching implementation */
     346             : 
     347             : #define FD_SHA512_BATCH_ALIGN     (128UL)
     348             : #define FD_SHA512_BATCH_FOOTPRINT (256UL)
     349             : #define FD_SHA512_BATCH_MAX       (8UL)
     350             : 
     351             : /* This is exposed here to facilitate inlining various operations */
     352             : 
     353             : struct __attribute__((aligned(FD_SHA512_BATCH_ALIGN))) fd_sha512_private_batch {
     354             :   void const * data[ FD_SHA512_BATCH_MAX ]; /* AVX-512 aligned */
     355             :   ulong        sz  [ FD_SHA512_BATCH_MAX ]; /* AVX-512 aligned */
     356             :   void *       hash[ FD_SHA512_BATCH_MAX ]; /* AVX-512 aligned */
     357             :   ulong        cnt;
     358             : };
     359             : 
     360             : typedef struct fd_sha512_private_batch fd_sha512_batch_t;
     361             : 
     362             : FD_PROTOTYPES_BEGIN
     363             : 
     364             : /* Internal use only */
     365             : 
     366             : void
     367             : fd_sha512_private_batch_avx512( ulong          batch_cnt,    /* In [1,FD_SHA512_BATCH_MAX] */
     368             :                                 void const *   batch_data,   /* Indexed [0,FD_SHA512_BATCH_MAX), aligned 64,
     369             :                                                                 only [0,batch_cnt) used, essentially a msg_t const * const * */
     370             :                                 ulong const *  batch_sz,     /* Indexed [0,FD_SHA512_BATCH_MAX), aligned 64,
     371             :                                                                 only [0,batch_cnt) used */
     372             :                                 void * const * batch_hash ); /* Indexed [0,FD_SHA512_BATCH_MAX), aligned 64,
     373             :                                                                 only [0,batch_cnt) used */
     374             : 
     375           0 : FD_FN_CONST static inline ulong fd_sha512_batch_align    ( void ) { return alignof(fd_sha512_batch_t); }
     376           0 : FD_FN_CONST static inline ulong fd_sha512_batch_footprint( void ) { return sizeof (fd_sha512_batch_t); }
     377             : 
     378             : static inline fd_sha512_batch_t *
     379      611552 : fd_sha512_batch_init( void * mem ) {
     380      611552 :   fd_sha512_batch_t * batch = (fd_sha512_batch_t *)mem;
     381      611552 :   batch->cnt = 0UL;
     382      611552 :   return batch;
     383      611552 : }
     384             : 
     385             : static inline fd_sha512_batch_t *
     386             : fd_sha512_batch_add( fd_sha512_batch_t * batch,
     387             :                      void const *        data,
     388             :                      ulong               sz,
     389     6986916 :                      void *              hash ) {
     390     6986916 :   ulong batch_cnt = batch->cnt;
     391     6986916 :   batch->data[ batch_cnt ] = data;
     392     6986916 :   batch->sz  [ batch_cnt ] = sz;
     393     6986916 :   batch->hash[ batch_cnt ] = hash;
     394     6986916 :   batch_cnt++;
     395     6986916 :   if( FD_UNLIKELY( batch_cnt==FD_SHA512_BATCH_MAX ) ) {
     396      605937 :     fd_sha512_private_batch_avx512( batch_cnt, batch->data, batch->sz, batch->hash );
     397      605937 :     batch_cnt = 0UL;
     398      605937 :   }
     399     6986916 :   batch->cnt = batch_cnt;
     400     6986916 :   return batch;
     401     6986916 : }
     402             : 
     403             : static inline void *
     404      607429 : fd_sha512_batch_fini( fd_sha512_batch_t * batch ) {
     405      607429 :   ulong batch_cnt = batch->cnt;
     406      607429 :   if( FD_LIKELY( batch_cnt ) ) fd_sha512_private_batch_avx512( batch_cnt, batch->data, batch->sz, batch->hash );
     407      607429 :   return (void *)batch;
     408      607429 : }
     409             : 
     410             : static inline void *
     411        4123 : fd_sha512_batch_abort( fd_sha512_batch_t * batch ) {
     412        4123 :   return (void *)batch;
     413        4123 : }
     414             : 
     415             : FD_PROTOTYPES_END
     416             : 
     417             : #else
     418             : #error "Unsupported FD_SHA512_BATCH_IMPL"
     419             : #endif
     420             : 
     421             : #endif /* HEADER_fd_src_ballet_sha512_fd_sha512_h */

Generated by: LCOV version 1.14