From 630dc848a57a4dd5b4cc6074379a57e9c02dbaf9 Mon Sep 17 00:00:00 2001 From: Loup Vaillant Date: Sat, 30 Nov 2019 20:36:28 +0100 Subject: [PATCH] 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. --- makefile | 20 ++-- src/monocypher.c | 140 ++++++++++++++++----------- src/monocypher.h | 60 ++++++++---- src/optional/{sha512.c => ed25519.c} | 79 +++++++++++++-- src/optional/ed25519.h | 65 +++++++++++++ src/optional/sha512.h | 24 ----- tests/formal-analysis.sh | 16 +-- tests/test.c | 61 +++++++----- tests/test.sh | 2 +- 9 files changed, 313 insertions(+), 154 deletions(-) rename src/optional/{sha512.c => ed25519.c} (73%) create mode 100644 src/optional/ed25519.h delete mode 100644 src/optional/sha512.h diff --git a/makefile b/makefile index 2823522..58b9d0c 100644 --- a/makefile +++ b/makefile @@ -8,10 +8,8 @@ SONAME=libmonocypher.so.3 VERSION=__git__ -ifeq ($(findstring -DED25519_SHA512, $(CFLAGS)),) -LINK_SHA512= -else -LINK_SHA512=lib/sha512.o +ifdef LINK_ED25519 +LINK_ED25519=lib/ed25519.o endif .PHONY: all library static-library dynamic-library \ @@ -90,24 +88,24 @@ test test-legacy speed speed-sodium speed-tweetnacl speed-hydrogen speed-c25519: ./$< # Monocypher libraries -lib/libmonocypher.a: lib/monocypher.o $(LINK_SHA512) +lib/libmonocypher.a: lib/monocypher.o $(LINK_ED25519) ar cr $@ $^ lib/libmonocypher.so: lib/$(SONAME) @mkdir -p $(@D) ln -sf `basename $<` $@ -lib/$(SONAME): lib/monocypher.o $(LINK_SHA512) +lib/$(SONAME): lib/monocypher.o $(LINK_ED25519) @mkdir -p $(@D) $(CC) $(CFLAGS) -shared -Wl,-soname,$(SONAME) -o $@ $^ -lib/sha512.o : src/optional/sha512.c src/optional/sha512.h +lib/ed25519.o : src/optional/ed25519.c src/optional/ed25519.h lib/chacha20.o : src/deprecated/chacha20.c src/deprecated/chacha20.h lib/aead-incr.o : src/deprecated/aead-incr.c src/deprecated/aead-incr.h lib/monocypher.o: src/monocypher.c src/monocypher.h -lib/monocypher.o lib/sha512.o lib/chacha20.o lib/aead-incr.o: +lib/monocypher.o lib/ed25519.o lib/chacha20.o lib/aead-incr.o: @mkdir -p $(@D) $(CC) $(CFLAGS) -I src -I src/optional -fPIC -c -o $@ $< # Test & speed libraries -TEST_COMMON = tests/utils.h src/monocypher.h src/optional/sha512.h +TEST_COMMON = tests/utils.h src/monocypher.h src/optional/ed25519.h TEST_LEGACY = $(TEST_COMMON) src/deprecated/chacha20.h src/deprecated/aead-incr.h SPEED = tests/speed lib/utils.o :tests/utils.c @@ -160,9 +158,9 @@ lib/speed-c25519.o:$(SPEED)/speed-c25519.c \ # test & speed executables TEST_OBJ= lib/utils.o lib/monocypher.o -test.out : lib/test.o $(TEST_OBJ) lib/sha512.o +test.out : lib/test.o $(TEST_OBJ) lib/ed25519.o test-legacy.out: lib/test-legacy.o $(TEST_OBJ) lib/chacha20.o lib/aead-incr.o -speed.out : lib/speed.o $(TEST_OBJ) lib/sha512.o +speed.out : lib/speed.o $(TEST_OBJ) lib/ed25519.o test.out test-legacy.out speed.out: $(CC) $(CFLAGS) -I src -I src/optional -o $@ $^ speed-sodium.out: lib/speed-sodium.o lib/utils.o diff --git a/src/monocypher.c b/src/monocypher.c index f6e827a..d1bbadb 100644 --- a/src/monocypher.c +++ b/src/monocypher.c @@ -5,22 +5,6 @@ ///////////////// /// Utilities /// ///////////////// - -// By default, EdDSA signatures use Blake2b. SHA-512 is provided as an -// option for full ed25519 compatibility. To use with SHA-512, compile -// with option -DED25519_SHA512 and include "sha512.h". -#ifdef ED25519_SHA512 - #define HASH crypto_sha512 -#else - #define HASH crypto_blake2b -#endif -#define COMBINE1(x, y) x ## y -#define COMBINE2(x, y) COMBINE1(x, y) -#define HASH_CTX COMBINE2(HASH, _ctx) -#define HASH_INIT COMBINE2(HASH, _init) -#define HASH_UPDATE COMBINE2(HASH, _update) -#define HASH_FINAL COMBINE2(HASH, _final) - #define FOR_T(type, i, start, end) for (type i = (start); i < (end); i++) #define FOR(i, start, end) FOR_T(size_t, i, start, end) #define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx))) @@ -644,6 +628,14 @@ void crypto_blake2b(u8 hash[64], const u8 *message, size_t message_size) crypto_blake2b_general(hash, 64, 0, 0, message, message_size); } +const crypto_hash_vtable crypto_blake2b_vtable = { + (void (*)(u8*, const u8*, size_t) )crypto_blake2b, + (void (*)(void*) )crypto_blake2b_init, + (void (*)(void*, const u8*, size_t))crypto_blake2b_update, + (void (*)(void*, u8*) )crypto_blake2b_final, + offsetof(crypto_sign_blake2b_ctx, hash), + sizeof (crypto_sign_blake2b_ctx), +}; //////////////// /// Argon2 i /// @@ -1902,10 +1894,12 @@ static void ge_scalarmult_base(ge *p, const u8 scalar[32]) WIPE_BUFFER(s_scalar); } -void crypto_sign_public_key(u8 public_key[32], const u8 secret_key[32]) +void crypto_sign_public_key_custom_hash(u8 public_key[32], + const u8 secret_key[32], + const crypto_hash_vtable *hash) { u8 a[64]; - HASH(a, secret_key, 32); + hash->hash(a, secret_key, 32); trim_scalar(a); ge A; ge_scalarmult_base(&A, a); @@ -1914,17 +1908,25 @@ void crypto_sign_public_key(u8 public_key[32], const u8 secret_key[32]) WIPE_CTX(&A); } -void crypto_sign_init_first_pass(crypto_sign_ctx *ctx, - const u8 secret_key[32], - const u8 public_key[32]) +void crypto_sign_public_key(u8 public_key[32], const u8 secret_key[32]) { + crypto_sign_public_key_custom_hash(public_key, secret_key, + &crypto_blake2b_vtable); +} + +void crypto_sign_init_first_pass_custom_hash(crypto_sign_ctx_abstract *ctx, + const u8 secret_key[32], + const u8 public_key[32], + const crypto_hash_vtable *hash) +{ + ctx->hash = hash; // set vtable u8 *a = ctx->buf; u8 *prefix = ctx->buf + 32; - HASH(a, secret_key, 32); + ctx->hash->hash(a, secret_key, 32); trim_scalar(a); if (public_key == 0) { - crypto_sign_public_key(ctx->pk, secret_key); + crypto_sign_public_key_custom_hash(ctx->pk, secret_key, ctx->hash); } else { FOR (i, 0, 32) { ctx->pk[i] = public_key[i]; @@ -1935,20 +1937,29 @@ void crypto_sign_init_first_pass(crypto_sign_ctx *ctx, // An actual random number would work just fine, and would save us // the trouble of hashing the message twice. If we did that // however, the user could fuck it up and reuse the nonce. - HASH_INIT (&ctx->hash); - HASH_UPDATE(&ctx->hash, prefix , 32); + ctx->hash->init ((char*)ctx + ctx->hash->offset); + ctx->hash->update((char*)ctx + ctx->hash->offset, prefix , 32); +} + +void crypto_sign_init_first_pass(crypto_sign_ctx_abstract *ctx, + const u8 secret_key[32], + const u8 public_key[32]) +{ + crypto_sign_init_first_pass_custom_hash(ctx, secret_key, public_key, + &crypto_blake2b_vtable); } -void crypto_sign_update(crypto_sign_ctx *ctx, const u8 *msg, size_t msg_size) +void crypto_sign_update(crypto_sign_ctx_abstract *ctx, + const u8 *msg, size_t msg_size) { - HASH_UPDATE(&ctx->hash, msg, msg_size); + ctx->hash->update((char*)ctx + ctx->hash->offset, msg, msg_size); } -void crypto_sign_init_second_pass(crypto_sign_ctx *ctx) +void crypto_sign_init_second_pass(crypto_sign_ctx_abstract *ctx) { u8 *r = ctx->buf + 32; u8 *half_sig = ctx->buf + 64; - HASH_FINAL(&ctx->hash, r); + ctx->hash->final((char*)ctx + ctx->hash->offset, r); reduce(r); // first half of the signature = "random" nonce times the base point @@ -1959,25 +1970,25 @@ void crypto_sign_init_second_pass(crypto_sign_ctx *ctx) // Hash R, the public key, and the message together. // It cannot be done in parallel with the first hash. - HASH_INIT (&ctx->hash); - HASH_UPDATE(&ctx->hash, half_sig, 32); - HASH_UPDATE(&ctx->hash, ctx->pk , 32); + ctx->hash->init ((char*)ctx + ctx->hash->offset); + ctx->hash->update((char*)ctx + ctx->hash->offset, half_sig, 32); + ctx->hash->update((char*)ctx + ctx->hash->offset, ctx->pk , 32); } -void crypto_sign_final(crypto_sign_ctx *ctx, u8 signature[64]) +void crypto_sign_final(crypto_sign_ctx_abstract *ctx, u8 signature[64]) { u8 *a = ctx->buf; u8 *r = ctx->buf + 32; u8 *half_sig = ctx->buf + 64; u8 h_ram[64]; - HASH_FINAL(&ctx->hash, h_ram); + ctx->hash->final((char*)ctx + ctx->hash->offset, h_ram); reduce(h_ram); FOR (i, 0, 32) { signature[i] = half_sig[i]; } mul_add(signature + 32, h_ram, a, r); // s = h_ram * a + r - WIPE_CTX(ctx); WIPE_BUFFER(h_ram); + crypto_wipe(ctx, ctx->hash->ctx_size); } void crypto_sign(u8 signature[64], @@ -1985,37 +1996,49 @@ void crypto_sign(u8 signature[64], const u8 public_key[32], const u8 *message, size_t message_size) { - crypto_sign_ctx ctx; - crypto_sign_init_first_pass (&ctx, secret_key, public_key); - crypto_sign_update (&ctx, message, message_size); - crypto_sign_init_second_pass(&ctx); - crypto_sign_update (&ctx, message, message_size); - crypto_sign_final (&ctx, signature); + crypto_sign_blake2b_ctx ctx; + crypto_sign_ctx_abstract *ctx_ptr = (void*)&ctx; + crypto_sign_init_first_pass (ctx_ptr, secret_key, public_key); + crypto_sign_update (ctx_ptr, message, message_size); + crypto_sign_init_second_pass(ctx_ptr); + crypto_sign_update (ctx_ptr, message, message_size); + crypto_sign_final (ctx_ptr, signature); } -void crypto_check_init(crypto_check_ctx *ctx, - const u8 signature[64], - const u8 public_key[32]) +void crypto_check_init_custom_hash(crypto_check_ctx_abstract *ctx, + const u8 signature[64], + const u8 public_key[32], + const crypto_hash_vtable *hash) { - FOR (i, 0, 64) { ctx->sig[i] = signature [i]; } + ctx->hash = hash; // set vtable + FOR (i, 0, 64) { ctx->buf[i] = signature [i]; } FOR (i, 0, 32) { ctx->pk [i] = public_key[i]; } - HASH_INIT (&ctx->hash); - HASH_UPDATE(&ctx->hash, signature , 32); - HASH_UPDATE(&ctx->hash, public_key, 32); + ctx->hash->init ((char*)ctx + ctx->hash->offset); + ctx->hash->update((char*)ctx + ctx->hash->offset, signature , 32); + ctx->hash->update((char*)ctx + ctx->hash->offset, public_key, 32); +} + +void crypto_check_init(crypto_check_ctx_abstract *ctx, + const u8 signature[64], + const u8 public_key[32]) +{ + crypto_check_init_custom_hash(ctx, signature, public_key, + &crypto_blake2b_vtable); } -void crypto_check_update(crypto_check_ctx *ctx, const u8 *msg, size_t msg_size) +void crypto_check_update(crypto_check_ctx_abstract *ctx, + const u8 *msg, size_t msg_size) { - HASH_UPDATE(&ctx->hash, msg , msg_size); + ctx->hash->update((char*)ctx + ctx->hash->offset, msg, msg_size); } -int crypto_check_final(crypto_check_ctx *ctx) +int crypto_check_final(crypto_check_ctx_abstract *ctx) { ge A; u8 *h_ram = ctx->pk; // save stack space u8 *R_check = ctx->pk; // save stack space - u8 *R = ctx->sig; // R - u8 *s = ctx->sig + 32; // s + u8 *R = ctx->buf; // R + u8 *s = ctx->buf + 32; // s ge *diff = &A; // -A is overwritten... if (ge_frombytes_neg_vartime(&A, ctx->pk) || is_above_L(s)) { // prevent s malleability @@ -2023,7 +2046,7 @@ int crypto_check_final(crypto_check_ctx *ctx) } { u8 tmp[64]; - HASH_FINAL(&ctx->hash, tmp); + ctx->hash->final((char*)ctx + ctx->hash->offset, tmp); reduce(tmp); FOR (i, 0, 32) { // the extra copy saves 32 bytes of stack h_ram[i] = tmp[i]; @@ -2039,10 +2062,11 @@ int crypto_check(const u8 signature[64], const u8 public_key[32], const u8 *message, size_t message_size) { - crypto_check_ctx ctx; - crypto_check_init(&ctx, signature, public_key); - crypto_check_update(&ctx, message, message_size); - return crypto_check_final(&ctx); + crypto_check_blake2b_ctx ctx; + crypto_check_ctx_abstract *ctx_ptr = (void*)&ctx; + crypto_check_init(ctx_ptr, signature, public_key); + crypto_check_update(ctx_ptr, message, message_size); + return crypto_check_final(ctx_ptr); } //////////////////// diff --git a/src/monocypher.h b/src/monocypher.h index d2c8ed9..0b9cec9 100644 --- a/src/monocypher.h +++ b/src/monocypher.h @@ -32,22 +32,27 @@ typedef struct { } crypto_blake2b_ctx; // Signatures (EdDSA) -#ifdef ED25519_SHA512 - #include "sha512.h" - typedef crypto_sha512_ctx crypto_hash_ctx; -#else - typedef crypto_blake2b_ctx crypto_hash_ctx; -#endif typedef struct { - crypto_hash_ctx hash; + 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); + ptrdiff_t offset; + size_t ctx_size; +} crypto_hash_vtable; + +typedef struct { + const crypto_hash_vtable *hash; uint8_t buf[96]; uint8_t pk [32]; -} crypto_sign_ctx; +} crypto_sign_ctx_abstract; +typedef crypto_sign_ctx_abstract crypto_check_ctx_abstract; + typedef struct { - crypto_hash_ctx hash; - uint8_t sig[64]; - uint8_t pk [32]; -} crypto_check_ctx; + crypto_sign_ctx_abstract ctx; + crypto_blake2b_ctx hash; +} crypto_sign_blake2b_ctx; +typedef crypto_sign_blake2b_ctx crypto_check_blake2b_ctx; //////////////////////////// /// High level interface /// @@ -118,6 +123,9 @@ void crypto_blake2b_final (crypto_blake2b_ctx *ctx, uint8_t *hash); void crypto_blake2b_general_init(crypto_blake2b_ctx *ctx, size_t hash_size, const uint8_t *key, size_t key_size); +// vtable for signatures +extern const crypto_hash_vtable crypto_blake2b_vtable; + // Password key derivation (Argon2 i) // ---------------------------------- @@ -161,23 +169,35 @@ int crypto_check(const uint8_t signature [64], const uint8_t *message, size_t message_size); // Incremental interface for signatures (2 passes) -void crypto_sign_init_first_pass(crypto_sign_ctx *ctx, +void crypto_sign_init_first_pass(crypto_sign_ctx_abstract *ctx, const uint8_t secret_key[32], const uint8_t public_key[32]); -void crypto_sign_update(crypto_sign_ctx *ctx, +void crypto_sign_update(crypto_sign_ctx_abstract *ctx, const uint8_t *message, size_t message_size); -void crypto_sign_init_second_pass(crypto_sign_ctx *ctx); +void crypto_sign_init_second_pass(crypto_sign_ctx_abstract *ctx); // use crypto_sign_update() again. -void crypto_sign_final(crypto_sign_ctx *ctx, uint8_t signature[64]); +void crypto_sign_final(crypto_sign_ctx_abstract *ctx, uint8_t signature[64]); // Incremental interface for verification (1 pass) -void crypto_check_init (crypto_check_ctx *ctx, +void crypto_check_init (crypto_check_ctx_abstract *ctx, const uint8_t signature[64], const uint8_t public_key[32]); -void crypto_check_update(crypto_check_ctx *ctx, +void crypto_check_update(crypto_check_ctx_abstract *ctx, const uint8_t *message, size_t message_size); -int crypto_check_final (crypto_check_ctx *ctx); - +int crypto_check_final (crypto_check_ctx_abstract *ctx); + +// Custom hash interface +void crypto_sign_public_key_custom_hash(uint8_t public_key[32], + const uint8_t secret_key[32], + const crypto_hash_vtable *hash); +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_hash_vtable *hash); +void crypto_check_init_custom_hash(crypto_check_ctx_abstract *ctx, + const uint8_t signature[64], + const uint8_t public_key[32], + const crypto_hash_vtable *hash); //////////////////////////// /// Low level primitives /// diff --git a/src/optional/sha512.c b/src/optional/ed25519.c similarity index 73% rename from src/optional/sha512.c rename to src/optional/ed25519.c index 9afaeb9..ec7fe5d 100644 --- a/src/optional/sha512.c +++ b/src/optional/ed25519.c @@ -1,7 +1,10 @@ // Monocypher version __git__ -#include "sha512.h" +#include "ed25519.h" +///////////////// +/// Utilities /// +///////////////// #define FOR(i, min, max) for (size_t i = min; i < max; i++) #define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx))) #define MIN(a, b) ((a) <= (b) ? (a) : (b)) @@ -33,14 +36,9 @@ static void store64_be(u8 out[8], u64 in) out[7] = in & 0xff; } -static void crypto_wipe(void *secret, size_t size) -{ - volatile u8 *v_secret = (u8*)secret; - FOR (i, 0, size) { - v_secret[i] = 0; - } -} - +/////////////// +/// SHA 512 /// +/////////////// static u64 rot(u64 x, int c ) { return (x >> c) | (x << (64 - c)); } static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); } static u64 maj(u64 x, u64 y, u64 z) { return (x & y) ^ ( x & z) ^ (y & z); } @@ -206,3 +204,66 @@ void crypto_sha512(u8 *hash, const u8 *message, size_t message_size) crypto_sha512_update(&ctx, message, message_size); crypto_sha512_final (&ctx, hash); } + +const crypto_hash_vtable crypto_sha512_vtable = { + (void (*)(u8*, const u8*, size_t) )crypto_sha512, + (void (*)(void*) )crypto_sha512_init, + (void (*)(void*, const u8*, size_t))crypto_sha512_update, + (void (*)(void*, u8*) )crypto_sha512_final, + offsetof(crypto_sign_sha512_ctx, hash), + sizeof (crypto_sign_sha512_ctx), +}; + +/////////////// +/// Ed25519 /// +/////////////// + +void crypto_ed25519_public_key(u8 public_key[32], + const u8 secret_key[32]) +{ + crypto_sign_public_key_custom_hash(public_key, secret_key, + &crypto_sha512_vtable); +} + +void crypto_ed25519_sign_init_first_pass(crypto_sign_ctx_abstract *ctx, + const u8 secret_key[32], + const u8 public_key[32]) +{ + crypto_sign_init_first_pass_custom_hash(ctx, secret_key, public_key, + &crypto_sha512_vtable); +} + +void crypto_ed25519_check_init(crypto_check_ctx_abstract *ctx, + const u8 signature[64], + const u8 public_key[32]) +{ + crypto_check_init_custom_hash(ctx, signature, public_key, + &crypto_sha512_vtable); +} + +void crypto_ed25519_sign(u8 signature [64], + const u8 secret_key[32], + const u8 public_key[32], + const u8 *message, size_t message_size) +{ + crypto_sign_sha512_ctx ctx; + crypto_sign_ctx_abstract *ctx_ptr = (void*)&ctx; + crypto_ed25519_sign_init_first_pass(ctx_ptr, secret_key, public_key); + crypto_sign_update (ctx_ptr, message, message_size); + crypto_sign_init_second_pass (ctx_ptr); + crypto_sign_update (ctx_ptr, message, message_size); + crypto_sign_final (ctx_ptr, signature); + +} + +int crypto_ed25519_check(const u8 signature [64], + const u8 public_key[32], + const u8 *message, size_t message_size) +{ + crypto_check_sha512_ctx ctx; + crypto_check_ctx_abstract *ctx_ptr = (void*)&ctx; + crypto_ed25519_check_init(ctx_ptr, signature, public_key); + crypto_check_update(ctx_ptr, message, message_size); + return crypto_check_final(ctx_ptr); +} + diff --git a/src/optional/ed25519.h b/src/optional/ed25519.h new file mode 100644 index 0000000..fa40cb7 --- /dev/null +++ b/src/optional/ed25519.h @@ -0,0 +1,65 @@ +// Monocypher version __git__ + +#ifndef ED25519_H +#define ED25519_H + +#include "monocypher.h" + +//////////////////////// +/// Type definitions /// +//////////////////////// + +// Do not rely on the size or content on any of those types, +// they may change without notice. +typedef struct { + uint64_t w[80]; // work area + uint64_t hash[8]; + uint64_t input[16]; + uint64_t input_size[2]; + size_t input_idx; +} crypto_sha512_ctx; + +typedef struct { + crypto_sign_ctx_abstract ctx; + crypto_sha512_ctx hash; +} crypto_sign_sha512_ctx; +typedef crypto_sign_sha512_ctx crypto_check_sha512_ctx; + +// SHA 512 +// ------- +void crypto_sha512_init (crypto_sha512_ctx *ctx); +void crypto_sha512_update(crypto_sha512_ctx *ctx, + const uint8_t *message, size_t message_size); +void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]); +void crypto_sha512(uint8_t *out,const uint8_t *message, size_t message_size); + +// vtable for signatures +extern const crypto_hash_vtable crypto_sha512_vtable; + + +// Ed25519 +// ------- + +// Generate public key +void crypto_ed25519_public_key(uint8_t public_key[32], + const uint8_t secret_key[32]); + +// Direct interface +void crypto_ed25519_sign(uint8_t signature [64], + const uint8_t secret_key[32], + const uint8_t public_key[32], // optional, may be 0 + const uint8_t *message, size_t message_size); +int crypto_ed25519_check(const uint8_t signature [64], + const uint8_t public_key[32], + const uint8_t *message, size_t message_size); + +// Init functions for the incremental interface +void crypto_ed25519_sign_init_first_pass(crypto_sign_ctx_abstract *ctx, + const uint8_t secret_key[32], + const uint8_t public_key[32]); +void crypto_ed25519_check_init(crypto_check_ctx_abstract *ctx, + const uint8_t signature[64], + const uint8_t public_key[32]); + + +#endif // ED25519_H diff --git a/src/optional/sha512.h b/src/optional/sha512.h deleted file mode 100644 index 78f850f..0000000 --- a/src/optional/sha512.h +++ /dev/null @@ -1,24 +0,0 @@ -// Monocypher version __git__ - -#ifndef SHA512_H -#define SHA512_H - -#include -#include - -typedef struct { - uint64_t w[80]; // work area - uint64_t hash[8]; - uint64_t input[16]; - uint64_t input_size[2]; - size_t input_idx; -} crypto_sha512_ctx; - -void crypto_sha512_init (crypto_sha512_ctx *ctx); -void crypto_sha512_update(crypto_sha512_ctx *ctx, - const uint8_t *message, size_t message_size); -void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]); - -void crypto_sha512(uint8_t *out,const uint8_t *message, size_t message_size); - -#endif // SHA512_H diff --git a/tests/formal-analysis.sh b/tests/formal-analysis.sh index 963cef2..93b4ef9 100755 --- a/tests/formal-analysis.sh +++ b/tests/formal-analysis.sh @@ -1,12 +1,12 @@ #! /bin/sh mkdir -p tests/formal-analysis -cp src/monocypher.c \ - src/monocypher.h \ - src/optional/sha512.h \ - src/optional/sha512.c \ - tests/utils.h \ - tests/utils.c \ - tests/test.c \ - tests/vectors.h \ +cp src/monocypher.c \ + src/monocypher.h \ + src/optional/ed25519.h \ + src/optional/ed25519.c \ + tests/utils.h \ + tests/utils.c \ + tests/test.c \ + tests/vectors.h \ tests/formal-analysis diff --git a/tests/test.c b/tests/test.c index 3e40d9d..7b6dcb7 100644 --- a/tests/test.c +++ b/tests/test.c @@ -2,7 +2,7 @@ #include #include #include "monocypher.h" -#include "sha512.h" +#include "ed25519.h" #include "utils.h" #include "vectors.h" @@ -137,17 +137,33 @@ static void edDSA_pk(const vector in[], vector *out) crypto_sign_public_key(out->buf, in->buf); } -#ifdef ED25519_SHA512 -static void (*ed_25519)(const vector[], vector*) = edDSA; +static void ed_25519(const vector in[], vector *out) +{ + const vector *secret_k = in; + const vector *public_k = in + 1; + const vector *msg = in + 2; + u8 out2[64]; + + // Sign with cached public key, then by reconstructing the key + crypto_ed25519_sign(out->buf, secret_k->buf, public_k->buf, + msg->buf, msg->size); + crypto_ed25519_sign(out2 , secret_k->buf, 0, + msg->buf, msg->size); + // Compare signatures (must be the same) + if (memcmp(out->buf, out2, out->size)) { + printf("FAILURE: reconstructing public key" + " yields different signature\n"); + } +} static void ed_25519_check(const vector in[], vector *out) { const vector *public_k = in; const vector *msg = in + 1; const vector *sig = in + 2; - out->buf[0] = crypto_check(sig->buf, public_k->buf, msg->buf, msg->size); + out->buf[0] = crypto_ed25519_check(sig->buf, public_k->buf, + msg->buf, msg->size); } -#endif static void iterate_x25519(u8 k[32], u8 u[32]) { @@ -559,23 +575,25 @@ static int p_eddsa_incremental() u8 sig_mono[64]; crypto_sign(sig_mono, sk, pk, message, MESSAGE_SIZE); u8 sig_incr[64]; { - crypto_sign_ctx ctx; - crypto_sign_init_first_pass (&ctx, sk, pk); - crypto_sign_update (&ctx, message , i); - crypto_sign_update (&ctx, message + i, MESSAGE_SIZE - i); - crypto_sign_init_second_pass(&ctx); - crypto_sign_update (&ctx, message , i); - crypto_sign_update (&ctx, message + i, MESSAGE_SIZE - i); - crypto_sign_final (&ctx, sig_incr); + crypto_sign_blake2b_ctx ctx; + crypto_sign_ctx_abstract *ctx_ptr = (void*)&ctx; + crypto_sign_init_first_pass (ctx_ptr, sk, pk); + crypto_sign_update (ctx_ptr, message , i); + crypto_sign_update (ctx_ptr, message + i, MESSAGE_SIZE - i); + crypto_sign_init_second_pass(ctx_ptr); + crypto_sign_update (ctx_ptr, message , i); + crypto_sign_update (ctx_ptr, message + i, MESSAGE_SIZE - i); + crypto_sign_final (ctx_ptr, sig_incr); } status |= memcmp(sig_mono, sig_incr, 64); status |= crypto_check(sig_mono, pk, message, MESSAGE_SIZE); { - crypto_check_ctx ctx; - crypto_check_init (&ctx, sig_incr, pk); - crypto_check_update(&ctx, message , i); - crypto_check_update(&ctx, message + i, MESSAGE_SIZE - i); - status |= crypto_check_final(&ctx); + crypto_check_blake2b_ctx ctx; + crypto_check_ctx_abstract*ctx_ptr=(void*)&ctx; + crypto_check_init (ctx_ptr, sig_incr, pk); + crypto_check_update(ctx_ptr, message , i); + crypto_check_update(ctx_ptr, message + i, MESSAGE_SIZE - i); + status |= crypto_check_final(ctx_ptr); } } printf("%s: EdDSA (incremental)\n", status != 0 ? "FAILED" : "OK"); @@ -644,13 +662,10 @@ int main(int argc, char *argv[]) status |= TEST(x25519 , 2); status |= TEST(x25519_pk , 1); status |= TEST(key_exchange , 2); -#ifdef ED25519_SHA512 - status |= TEST(ed_25519 , 3); - status |= TEST(ed_25519_check, 3); -#else status |= TEST(edDSA , 3); status |= TEST(edDSA_pk , 1); -#endif + status |= TEST(ed_25519 , 3); + status |= TEST(ed_25519_check, 3); status |= test_x25519(); printf("\nProperty based tests"); diff --git a/tests/test.sh b/tests/test.sh index 510efc6..86d8d35 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -3,7 +3,7 @@ set -e make clean; make test -make clean; make test CFLAGS="-DED25519_SHA512 -DBLAKE2_NO_UNROLLING -O3" +make clean; make test CFLAGS="-DBLAKE2_NO_UNROLLING -O3" make clean; make test CC="clang -std=c99" CFLAGS="-g -fsanitize=address" make clean; make test CC="clang -std=c99" CFLAGS="-g -fsanitize=memory" make clean; make test CC="clang -std=c99" CFLAGS="-g -fsanitize=undefined" -- 2.47.3