From: Loup Vaillant Date: Wed, 18 Mar 2020 11:27:31 +0000 (+0100) Subject: Added easy interface for Elligator X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=bc1ba59d9521fd19bb5bfde12681399a20359549;p=Monocypher.git Added easy interface for Elligator 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. --- diff --git a/src/monocypher.c b/src/monocypher.c index a6ac92b..f029d03 100644 --- a/src/monocypher.c +++ b/src/monocypher.c @@ -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 /// //////////////////// diff --git a/src/monocypher.h b/src/monocypher.h index 0b76939..a9986bb 100644 --- a/src/monocypher.h +++ b/src/monocypher.h @@ -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 /// diff --git a/tests/test.c b/tests/test.c index 707609c..fd6d92b 100644 --- a/tests/test.c +++ b/tests/test.c @@ -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; }