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:

  1. one call to EverCrypt_Hash_create_in
  2. one call to EverCrypt_Hash_init
  3. any number of calls to: EverCrypt_Hash_update (passing data exactly of the right block size for the chosen algorithm) or EverCrypt_Hash_update_multi (passing a multiple of the block size)
  4. one call to EverCrypt_Hash_update_last (data strictly smaller than the block size)
  5. one call to EverCrypt_Hash_finish
  6. 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.