Hashing (EverCrypt_Hash.h
)¶
This API is:
- agile
- multiplexing: portable C (all); SHAEXT (SHA2-224, SHA2-256)
- stateful
Possible values for the agility argument (Hacl_Spec.h
) :
#define Spec_Hash_Definitions_SHA2_224 0
#define Spec_Hash_Definitions_SHA2_256 1
#define Spec_Hash_Definitions_SHA2_384 2
#define Spec_Hash_Definitions_SHA2_512 3
#define Spec_Hash_Definitions_SHA1 4
#define Spec_Hash_Definitions_MD5 5
#define Spec_Hash_Definitions_Blake2S 6
#define Spec_Hash_Definitions_Blake2B 7
Supported values for the agility argument: all
Block-based API¶
The block-based functions require the client to follow this exact state machine:
- one call to
EverCrypt_Hash_create_in
- one call to
EverCrypt_Hash_init
- any number of calls to:
EverCrypt_Hash_update
(passing data exactly of the right block size for the chosen algorithm) orEverCrypt_Hash_update_multi
(passing a multiple of the block size) - one call to
EverCrypt_Hash_update_last
(data strictly smaller than the block size) - one call to
EverCrypt_Hash_finish
- one call to
EverCrypt_Hash_free
Clients may jump to state 2 at any point before state 6.
As evidenced by the state machine, this API requires clients to buffer data and
chunk it along the block size (“block-based”). Furthermore, this API does
not allow feeding more data into the hash function after update_last
has
been called: the client must either proceed with finish
or reset the state
with init
.
Warning
This API is error-prone and is not recommended for unverified clients. We advise clients use the streaming API described below.
Streaming API¶
The streaming hash API wraps the block-based API with an internal buffer (at the expense of an extra indirection) and relieves the client from having to perform modulo computations and block-size management. Furthermore, the block-based API allows extracting intermediary hashes without invalidating the state, meaning clients can compute a hash, then later feed more data into the hash function (at the expense of a state copy).
Clients can allocate state via create_in
. This is a non-faillible function
and as such does not return an error code. This is possible because i) we always
have a fallback portable C implementation available for all algorithms and ii)
we do not yet model allocation failures.
Hacl_Streaming_Functor_state_s___EverCrypt_Hash_state_s____
*EverCrypt_Hash_Incremental_create_in(Spec_Hash_Definitions_hash_alg a);
Clients can feed an arbitrary amount of data via update
:
void
EverCrypt_Hash_Incremental_update(
Hacl_Streaming_Functor_state_s___EverCrypt_Hash_state_s____ *p,
uint8_t *data,
uint32_t len
);
A hash can be extracted at any time by the client without invalidating the state:
void
EverCrypt_Hash_Incremental_finish_md5(
Hacl_Streaming_Functor_state_s___EverCrypt_Hash_state_s____ *p,
uint8_t *dst
);
Once done, clients should use free
which frees all internal buffers and
underlying block-based state:
void
EverCrypt_Hash_Incremental_free(Hacl_Streaming_Functor_state_s___EverCrypt_Hash_state_s____ *s);
Note
There is no streaming HACL* API for hashes, i.e. clients must go through agility and multiplexing to enjoy the streaming hash API.
One-shot API¶
If all data is available at once, clients can use the (slightly more efficient),
agile, multiplexing EverCrypt_Hash_hash
function.
void
EverCrypt_Hash_hash(
Spec_Hash_Definitions_hash_alg a,
uint8_t *dst,
uint8_t *input,
uint32_t len
);
This function merely dispatches onto one of the numerous non-agile specialized variants. As such, the cost of agility is one test.
For SHA2-256 and SHA2-224, the EverCrypt API provides non-agile, multiplexing variants:
void EverCrypt_Hash_hash_256(uint8_t *input, uint32_t input_len, uint8_t *dst);
For other hash algorithms, for which only one implementation (portable C) is currently available, clients can use the non-agile, non-multiplexing HACL Hash API.