]> git.codecow.com Git - Monocypher.git/commitdiff
Added Ed25519ph
authorLoup Vaillant <loup@loup-vaillant.fr>
Thu, 12 Jan 2023 17:15:27 +0000 (18:15 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Thu, 12 Jan 2023 17:15:27 +0000 (18:15 +0100)
Not sure this is such a good idea, considering how niche Ed25519ph is.
Yet someone recently paid me handsomely for the functionality, sparking
the recent overhaul of the EdDSA API that made it simpler and more
flexible than ever.

And now implementing Ed25519ph has become so cheap that I felt like
thanking them by adding it upstream.

src/optional/monocypher-ed25519.c
src/optional/monocypher-ed25519.h
tests/gen/makefile
tests/gen/vectors/ed_25519ph [new file with mode: 0644]
tests/test.c

index 497464603faefeb03db5c04a5b453bbb3b883b10..d175fb6cd912dec46c955eedcdf9383aa48ee59c 100644 (file)
@@ -354,7 +354,8 @@ void crypto_ed25519_key_pair(u8 secret_key[64], u8 public_key[32], u8 seed[32])
 static void hash_reduce(u8 h[32],
                         const u8 *a, size_t a_size,
                         const u8 *b, size_t b_size,
-                        const u8 *c, size_t c_size)
+                        const u8 *c, size_t c_size,
+                        const u8 *d, size_t d_size)
 {
        u8 hash[64];
        crypto_sha512_ctx ctx;
@@ -362,23 +363,26 @@ static void hash_reduce(u8 h[32],
        crypto_sha512_update(&ctx, a, a_size);
        crypto_sha512_update(&ctx, b, b_size);
        crypto_sha512_update(&ctx, c, c_size);
+       crypto_sha512_update(&ctx, d, d_size);
        crypto_sha512_final (&ctx, hash);
        crypto_eddsa_reduce(h, hash);
 }
 
-void crypto_ed25519_sign(u8 signature [64], const u8 secret_key[32],
-                         const u8 *message, size_t message_size)
+static void ed25519_dom_sign(u8 signature [64], const u8 secret_key[32],
+                             const u8 *dom,     size_t dom_size,
+                             const u8 *message, size_t message_size)
 {
        u8 a[64];  // secret scalar and prefix
        u8 r[32];  // secret deterministic "random" nonce
        u8 h[32];  // publically verifiable hash of the message (not wiped)
        u8 R[32];  // first half of the signature (allows overlapping inputs)
+       const u8 *pk = secret_key + 32;
 
        crypto_sha512(a, secret_key, 32);
        crypto_eddsa_trim_scalar(a, a);
-       hash_reduce(r, a + 32, 32, message, message_size, 0, 0);
+       hash_reduce(r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
        crypto_eddsa_scalarbase(R, r);
-       hash_reduce(h, R, 32, secret_key + 32, 32, message, message_size);
+       hash_reduce(h, dom, dom_size, R, 32, pk, 32, message, message_size);
        COPY(signature, R, 32);
        crypto_eddsa_mul_add(signature + 32, h, a, r);
 
@@ -386,14 +390,38 @@ void crypto_ed25519_sign(u8 signature [64], const u8 secret_key[32],
        WIPE_BUFFER(r);
 }
 
-int crypto_ed25519_check(const u8  signature[64], const u8 public_key[32],
+void crypto_ed25519_sign(u8 signature [64], const u8 secret_key[32],
                          const u8 *message, size_t message_size)
 {
-       u8 h_ram  [32];
-       hash_reduce(h_ram, signature, 32, public_key, 32, message, message_size);
+       ed25519_dom_sign(signature, secret_key, 0, 0, message, message_size);
+}
+
+int crypto_ed25519_check(const u8 signature[64], const u8 public_key[32],
+                         const u8 *msg, size_t msg_size)
+{
+       u8 h_ram[32];
+       hash_reduce(h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
        return crypto_eddsa_check_equation(signature, public_key, h_ram);
 }
 
+static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1\0";
+
+void crypto_ed25519_ph_sign(uint8_t signature[64], const uint8_t secret_key[32],
+                            const uint8_t message_hash[64])
+{
+       ed25519_dom_sign(signature, secret_key, domain, sizeof(domain),
+                        message_hash, 64);
+}
+
+int crypto_ed25519_ph_check(const uint8_t sig[64], const uint8_t pk[32],
+                            const uint8_t msg_hash[64])
+{
+       u8 h_ram[32];
+       hash_reduce(h_ram, domain, sizeof(domain), sig, 32, pk, 32, msg_hash, 64);
+       return crypto_eddsa_check_equation(sig, pk, h_ram);
+}
+
+
 #ifdef MONOCYPHER_CPP_NAMESPACE
 }
 #endif
index 2f7b414a2cf69a1436d8bff730b1979176bdaef7..77bb6b9bfa1992e8f94a2f94a8f8246d1c1bd3bc 100644 (file)
@@ -117,6 +117,14 @@ int crypto_ed25519_check(const uint8_t  signature [64],
                          const uint8_t  public_key[32],
                          const uint8_t *message, size_t message_size);
 
+// Pre-hash variants
+void crypto_ed25519_ph_sign(uint8_t       signature   [64],
+                            const uint8_t secret_key  [32],
+                            const uint8_t message_hash[64]);
+int crypto_ed25519_ph_check(const uint8_t signature   [64],
+                            const uint8_t public_key  [32],
+                            const uint8_t message_hash[64]);
+
 #ifdef __cplusplus
 }
 #endif
index 5ab2852014d6eecfd9299db711cdabedc341a1e8..be92c3d80d732c495bde534199a9c25f8e85df2e 100644 (file)
@@ -58,6 +58,7 @@ VEC     = chacha20  hchacha20  xchacha20     ietf_chacha20                \
           aead_ietf aead_8439                                             \
           poly1305  blake2b    sha512        hmac_sha512   argon2         \
           edDSA     edDSA_pk   ed_25519      ed_25519_pk   ed_25519_check \
+          ed_25519ph                                                      \
           x25519    x25519_pk  elligator_inv elligator_dir
 VEC2    = $(patsubst %, %.all.vec, $(VEC))
 HEADERS = $(patsubst %, %.h.vec  , $(VEC))
@@ -124,6 +125,7 @@ edDSA_pk.all.vec      : edDSA_pk.vec
 ed_25519.all.vec      : ed_25519.vec
 ed_25519_pk.all.vec   : ed_25519_pk.vec
 ed_25519_check.all.vec:                   vectors/ed_25519_check
+ed_25519ph.all.vec    :                   vectors/ed_25519ph
 elligator_dir.all.vec : elligator_dir.vec vectors/elligator_dir
 elligator_inv.all.vec : elligator_inv.vec vectors/elligator_inv
 $(VEC2):
diff --git a/tests/gen/vectors/ed_25519ph b/tests/gen/vectors/ed_25519ph
new file mode 100644 (file)
index 0000000..29ab550
--- /dev/null
@@ -0,0 +1,9 @@
+833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42:
+ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf:
+616263:
+98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406:
+
+17A4AB24CACC54F1ED6AADBDBE0B22328C4F4F9747F75DCEC653796963367476:
+b73f21f54921d332fcb8a32292c65bdafc91358d5383a3145e9aea57c9381440:
+0000000000000000000000000000000000000000000000000000000000000000:
+a8dd09bd36d6588a4535a3e258cd5bb75cef484f8f66bd7631b45bee89fddf03933ea8ea1c2b5636d133b7c5bb63f1ca55251b963cf3c9c13fe43bd773cc8600:
index abe15e8789c46a130a5a79f4f7062383efde6f88..60e67ba4989e6ec7a46ccd60527b520152313a07 100644 (file)
@@ -928,11 +928,43 @@ static void ed_25519_check(vector_reader *reader)
                                              msg.buf, msg.size);
 }
 
+static void ed_25519ph(vector_reader *reader)
+{
+    vector sk  = next_input(reader);
+    vector pk  = next_input(reader);
+    vector msg = next_input(reader);
+    vector out = next_output(reader);
+
+    // Test that we generate the correct public key
+    uint8_t secret_key[64];
+    uint8_t public_key[32];
+    crypto_ed25519_key_pair(secret_key, public_key, sk.buf);
+    ASSERT_EQUAL(public_key, pk.buf, 32);
+    ASSERT_EQUAL(public_key, secret_key + 32, 32);
+
+    // Generate output signature for comparison
+    uint8_t digest[64];
+    crypto_sha512(digest, msg.buf, msg.size);
+    crypto_ed25519_ph_sign(out.buf, secret_key, digest);
+
+    // Test that the correct signature is accepted
+    ASSERT_OK(crypto_ed25519_ph_check(out.buf, pk.buf, digest));
+
+    // Test that corrupted signatures are rejected
+    for (size_t i = 0; i < 64; i++) {
+        uint8_t corrupt_signature[64];
+        memcpy(corrupt_signature, out.buf, 64);
+        corrupt_signature[i] ^= 1; // corrupt one bit
+        ASSERT_KO(crypto_ed25519_ph_check(corrupt_signature, pk.buf, digest));
+    }
+}
+
 static void test_ed25519()
 {
        VECTORS(ed_25519);
        VECTORS(ed_25519_pk);
        VECTORS(ed_25519_check);
+       VECTORS(ed_25519ph);
 }
 
 /////////////////