]> git.codecow.com Git - Monocypher.git/commitdiff
Added easy interface for Elligator
authorLoup Vaillant <loup@loup-vaillant.fr>
Wed, 18 Mar 2020 11:27:31 +0000 (12:27 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Wed, 18 Mar 2020 11:27:31 +0000 (12:27 +0100)
Note a small problem in the implementation: we are reusing one byte for
both the tweak and the next random seed.  This makes them *not*
independent, and a possible source of vulnerability.

In practice, this is only a problem for the 3 bits comprising the
cofactor, since the sign and the padding do not play a role in deciding
whether the mapping fails or succeeds.

TODO: take the cofactor from the clamped bits of the scalar, instead of
the tweak. This will ensure proper independence, while keeping the high
level code simple and maximally efficient.

src/monocypher.c
src/monocypher.h
tests/test.c

index a6ac92b6d1a9dd8977dc9834e77077b6b2b54579..f029d031da5c1bf6ab6be7de28fdcc0b6536959a 100644 (file)
@@ -2453,6 +2453,22 @@ int crypto_elligator2_inverse(u8 hash[32], const u8 secret_key[32], u8 tweak)
     return 0;
 }
 
+void crypto_elligator2_key_pair(u8 hash[32], u8 secret_key[32], u8 seed[32])
+{
+    u8 buf[64];
+    FOR (i, 0, 32) {
+        buf[i + 32] = seed[i];
+    }
+    do {
+        crypto_chacha20(buf, 0, 64, buf+32, zero);
+    } while(crypto_elligator2_inverse(buf+32, buf, buf[32]));
+
+    crypto_wipe(seed, 32);
+    FOR (i, 0, 32) { hash      [i] = buf[i+32]; }
+    FOR (i, 0, 32) { secret_key[i] = buf[i   ]; }
+    WIPE_BUFFER(buf);
+}
+
 ////////////////////
 /// Key exchange ///
 ////////////////////
index 0b76939a1f2805e7748bd09560fc293682583542..a9986bb5f792c994f547f79e96f8aae63257ff8e 100644 (file)
@@ -257,6 +257,8 @@ void crypto_check_init_custom_hash(crypto_check_ctx_abstract *ctx,
 void crypto_elligator2_direct(uint8_t curve[32], const uint8_t hash[32]);
 int crypto_elligator2_inverse(uint8_t hash[32], const uint8_t secret_key[32],
                               uint8_t tweak);
+void crypto_elligator2_key_pair(uint8_t hash[32], uint8_t secret_key[32],
+                                uint8_t seed[32]);
 
 ////////////////////////////
 /// Low level primitives ///
index 707609cce421ba9bc45016a068bb25232704fce9..fd6d92b0b017fbf6f525cb87e614f9b81d6e71de 100644 (file)
@@ -939,6 +939,44 @@ static int p_elligator_x25519()
     return status;
 }
 
+static int p_elligator_key_pair()
+{
+    int status = 0;
+    FOR(i, 0, 32) {
+        RANDOM_INPUT(seed, 32);
+        RANDOM_INPUT(sk2 , 32);
+        u8 r  [32];
+        u8 sk1[32];  crypto_elligator2_key_pair(r, sk1, seed);
+        u8 pkr[32];  crypto_elligator2_direct(pkr, r);
+        u8 pk1[32];  crypto_x25519_public_key(pk1, sk1);
+        u8 e1 [32];  crypto_x25519(e1, sk2, pk1);
+        u8 e2 [32];  crypto_x25519(e2, sk2, pkr);
+        status |= memcmp(e1, e2, 32);
+    }
+
+    printf("%s: elligator key pair\n", status != 0 ? "FAILED" : "OK");
+    return status;
+}
+
+static int p_elligator_key_pair_overlap()
+{
+    int status = 0;
+    FOR (i, 0, 94) {
+        u8 over[158];
+        u8 sep [ 64];
+        RANDOM_INPUT(s1, 32);
+        u8 *s2 = over + 63;
+        memcpy(s2, s1, 32);
+        crypto_elligator2_key_pair(sep     , sep      + 32, s1);
+        crypto_elligator2_key_pair(over + i, over + i + 32, s2);
+        status |= memcmp(sep, over + i, 64);
+    }
+
+    printf("%s: elligator key pair (overlapping i/o)\n",
+           status != 0 ? "FAILED" : "OK");
+    return status;
+}
+
 #define TEST(name, nb_inputs) vector_test(name, #name, nb_inputs, \
                                           nb_##name##_vectors,    \
                                           name##_vectors,         \
@@ -1006,6 +1044,8 @@ int main(int argc, char *argv[])
     status |= p_elligator_direct_overlap();
     status |= p_elligator_inverse_overlap();
     status |= p_elligator_x25519();
+    status |= p_elligator_key_pair();
+    status |= p_elligator_key_pair_overlap();
     printf("\n%s\n\n", status != 0 ? "SOME TESTS FAILED" : "All tests OK!");
     return status;
 }