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 */
|