]> git.codecow.com Git - Monocypher.git/commitdiff
Enabled cohabitation of several EdDSA instances
authorLoup Vaillant <loup@loup-vaillant.fr>
Sat, 30 Nov 2019 19:36:28 +0000 (20:36 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Sat, 30 Nov 2019 21:00:01 +0000 (22:00 +0100)
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
src/monocypher.c
src/monocypher.h
src/optional/ed25519.c [moved from src/optional/sha512.c with 73% similarity]
src/optional/ed25519.h [new file with mode: 0644]
src/optional/sha512.h [deleted file]
tests/formal-analysis.sh
tests/test.c
tests/test.sh

index 282352262c083aa10537746201b663aa6ceb4d32..58b9d0c7d74a67524a5ba5a00df46ba9addadd85 100644 (file)
--- 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
index f6e827a7b06c08e3a3720b385d1328662f364a04..d1bbadbd42c3a9d0dcf97a5852923b3da4f1b6ed 100644 (file)
@@ -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);
 }
 
 ////////////////////
index d2c8ed9729a05888c40f841acc5d142377639023..0b9cec9d89c92e9bc7564ded355df9380cbb74a2 100644 (file)
@@ -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 ///
similarity index 73%
rename from src/optional/sha512.c
rename to src/optional/ed25519.c
index 9afaeb962f44408b7c96b3a1e5666b2dbbce6e7d..ec7fe5d8479fd5205cf362c3012762c305b65f9d 100644 (file)
@@ -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 (file)
index 0000000..fa40cb7
--- /dev/null
@@ -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 (file)
index 78f850f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Monocypher version __git__
-
-#ifndef SHA512_H
-#define SHA512_H
-
-#include <stddef.h>
-#include <inttypes.h>
-
-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
index 963cef24d6984b63e0b2f9f3e406df81af81e528..93b4ef94eccf5fe3c64c706a85615ae11d6a67df 100755 (executable)
@@ -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
index 3e40d9d431ad20e4fbb37b03b2e555396d2f0841..7b6dcb7b6e14ec738c20d2b57b53f4a4073c7c31 100644 (file)
@@ -2,7 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #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");
index 510efc603ea4c55dcc3ab1cfddc2a8f991c217c4..86d8d35195adbf3e62a6dd4c6299837985ec015f 100755 (executable)
@@ -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"