Enabled cohabitation of several EdDSA instances
EdDSA can now use a custom hash! And that hash is not set in stone at
compile time, it can be decided at runtime! It was done inheritance and
subtype polymorphism. Don't worry, we are still using pure C.
Custom hashes are defined through vtables. The vtable contains function
pointers, an offset, and a size. (We need the size to wipe the context,
and the offset to find the location of the hash context inside the
signing context.)
An abstract signing context is defined. It is not instantiated
directly. It is instead the first member of the specialised signing
context. The incremental interface takes pointers to abstract contexts,
but actually requires specialised contexts.
By default, we use the Blake2b specialised context. The incremental
interface doesn't change, except for the need to give it a specialised
context instead of the old crypto_sign_ctx. To enable the use of
different contexts, 3 "custom_hash" functions have been added:
crypto_sign_public_key_custom_hash
crypto_sign_init_first_pass_custom_hash
crypto_check_init_custom_hash
They take a vtable as an additional parameter.
Ed25519 uses the custom hash interface to provide the following:
crypto_ed25519_public_key
crypto_ed25519_sign
crypto_ed25519_check
crypto_ed25519_sign_init_first_pass
crypto_ed25519_check_init
To use them, we just have to add
ed25519.h and
ed25519.c to the project.
Note a slight orthogonality violation. The following work with any
specialised context:
crypto_sign_update
crypto_sign_final
crypto_check_init
crypto_check_update
crypto_check_final
But the following requires a *Blake2b* signing context:
crypto_sign_init_second_pass
crypto_sign_init_first_pass
This lets us preserve the old function names (making it easier to update
user code), and maybe conveys that Blake2b remains the default hash.
---
Overall, I think we did pretty good: only 3 additional functions in the
main library (and a fourth exported symbol), and we spare the user the
pain of juggling with two contexts instead of just one. The only
drawback are slightly breaking compatibility in the incremental
interface, and requiring an explicit cast to avoid compiler warnings.