crypto_sign_init_first_pass_custom_hash,
crypto_sign_public_key_custom_hash,
crypto_check_init_custom_hash —
public key signatures with custom hash
functions
#include
<monocypher.h>
void
crypto_sign_init_first_pass_custom_hash(
crypto_sign_ctx_abstract
*ctx,
const uint8_t secret_key[32],
const uint8_t public_key[32],
const crypto_sign_vtable *hash);
void
crypto_sign_public_key_custom_hash(
uint8_t
public_key[32],
const uint8_t
secret_key[32],
const crypto_sign_vtable
*hash);
void
crypto_check_init_custom_hash(
crypto_sign_ctx_abstract
*ctx,
const uint8_t signature[64],
const uint8_t public_key[32],
const crypto_sign_vtable *hash);
These functions are variants of the
crypto_sign_init_first_pass(3monocypher)
family of functions: They provide the ability to replace the EdDSA hash
function with any user-provided hash function.
This is a highly advanced feature. Interoperability
of public key signatures with other cryptographic libraries can normally be
achieved by using
crypto_ed25519_sign(3monocypher)
or
crypto_ed25519_sign_init_first_pass(3monocypher)
already. This interface is exposed only for completeness and to handle special
situations (e.g. to use the hash function of the future winner of the NIST
lightweight crypto competition on a device with highly constrained resources
or taking advantage of hardware support for cryptographic hash functions).
Whenever possible, these functions should be avoided.
To make available a custom hash algorithm for use with these functions, a
crypto_sign_vtable structure must be
provided. It is defined as:
typedef struct {
void (*hash)(uint8_t hash[64], const uint8_t *message,
size_t message_size);
void (*init )(void *ctx);
void (*update)(void *ctx, const uint8_t *message,
size_t message_size);
void (*final )(void *ctx, uint8_t hash[64]);
size_t ctx_size;
} crypto_sign_vtable;
The context argument to the functions shall be referred to as “outer
signing context”. The outer signing context must contain a
crypto_sign_ctx_abstract as
its first member. Other than that, the outer
signing context may be defined freely. Logically, it is required to contain
some kind of hash context as well, else it cannot work as a custom hash
function.
Because the calling code cannot know the real type of the outer signing context,
it is cast to
void * when calling the hash
functions in the vtable, but the
ctx argument
to the functions in the vtable is always guaranteed to be the outer signing
context.
The hash functions must not fail. If they somehow can fail, they have no way to
propagate its error status, and thus the only ways to handle errors are to
either assume an error never occurs (if reasonable), or to induce a crash in
the code when an error occurs.
The fields of
crypto_sign_vtable are:
-
-
- hash
- Function that computes a 64-byte hash for a given message
and writes the computed hash to hash. The
output length must be exactly 64 bytes. This
will normally be constructed using the functions that provide the
init,
update and
final members.
-
-
- init
- Function that initialises the hash context of an outer
signing context.
-
-
- update
- Function that updates the hash context of an outer signing
context. It must be able to handle message sizes of at least 32
bytes.
-
-
- final
- Function that finalises the hash context of an outer
signing context and writes the computed hash to
hash. The output length
must be exactly 64 bytes. This function
should wipe the hash context with
crypto_wipe(3monocypher)
if it contains pointers to objects outside the outer signing context.
Monocypher takes care of wiping the outer signing context.
-
-
- ctx_size
- The size of the outer signing context as determined by
sizeof().
The functions indicated in the
crypto_sign_vtable must be thread-safe if any
of Monocypher's signing functions are accessed from multiple threads.
After calling
crypto_sign_init_first_pass_custom_hash() or
crypto_check_init_custom_hash(), the
crypto_sign_update(3monocypher),
crypto_sign_final(3monocypher),
crypto_sign_init_second_pass(3monocypher),
crypto_check_update(3monocypher),
and
crypto_check_final(3monocypher)
functions can be used as usual. They will call into the hash vtable as
required. The same security considerations and semantics apply.
These functions return nothing.
Defining and using a custom implementation of SHA-512 and crudely checking its
results against
crypto_ed25519_sign(3monocypher):
struct outer_ctx {
crypto_sign_ctx_abstract sctx;
SHA2_CTX hash_ctx;
};
static void
my_hash(uint8_t hash[64], const uint8_t *msg, size_t len)
{
SHA2_CTX ctx;
SHA512Init(&ctx);
SHA512Update(&ctx, msg, len);
SHA512Final(hash, &ctx);
}
static void
my_init(void *ctx)
{
struct outer_ctx *octx = (struct outer_ctx *)ctx;
SHA512Init(&octx->hash_ctx);
}
static void
my_update(void *ctx, const uint8_t *msg, size_t len)
{
struct outer_ctx *octx = (struct outer_ctx *)ctx;
SHA512Update(&octx->hash_ctx, msg, len);
}
static void
my_final(void *ctx, uint8_t *hash)
{
struct outer_ctx *octx = (struct outer_ctx *)ctx;
SHA512Final(hash, &octx->hash_ctx);
}
static const crypto_sign_vtable my_vtable = {
my_hash,
my_init,
my_update,
my_final,
sizeof(struct outer_ctx)
};
int
main(void)
{
uint8_t theirs[64], mine[64];
uint8_t sk[32] = {0x01, 0x02, 0x03, 0x04};
const uint8_t msg[] = {
0x00, 0x01, 0x02, 0x04
};
crypto_ed25519_sign(theirs, sk, NULL, msg, sizeof(msg));
struct outer_ctx ctx;
crypto_sign_ctx_abstract *actx = (crypto_sign_ctx_abstract*)&ctx;
crypto_sign_init_first_pass_custom_hash(actx,
sk, NULL, &my_vtable);
crypto_wipe(sk, sizeof(sk));
crypto_sign_update( actx, msg, sizeof(msg));
crypto_sign_init_second_pass(actx);
crypto_sign_update( actx, msg, sizeof(msg));
crypto_sign_final( actx, mine);
if (crypto_verify64(theirs, mine) != 0) {
fprintf(stderr, "theirs != mine\n");
return 1;
}
puts("ok");
return 0;
}
crypto_blake2b(3monocypher),
crypto_sha512(3monocypher),
crypto_sign(3monocypher),
crypto_sign_init_first_pass(3monocypher),
crypto_wipe(3monocypher),
intro(3monocypher)
The
crypto_sign_init_first_pass_custom_hash(),
crypto_sign_public_key_custom_hash(),
crypto_check_init_first_pass_custom_hash()
functions first appeared in Monocypher 3.0.0.