From ec4ece08f0c589583e7f5bd19f0a5f2f0f7cd3fc Mon Sep 17 00:00:00 2001 From: Michael Hamburg Date: Tue, 2 May 2017 15:37:10 -0700 Subject: [PATCH] add decaf_edXXX_convert_public_key_to_xXXX; thanks Johan Pascal --- src/GENERATED/c/curve25519/decaf.c | 44 +++++++++++++++++++++++++ src/GENERATED/c/curve25519/eddsa.c | 15 +++++++++ src/GENERATED/c/ed448goldilocks/decaf.c | 44 +++++++++++++++++++++++++ src/GENERATED/c/ed448goldilocks/eddsa.c | 15 +++++++++ src/GENERATED/include/decaf/ed255.h | 26 +++++++++++++++ src/GENERATED/include/decaf/ed255.hxx | 14 ++++++++ src/GENERATED/include/decaf/ed448.h | 26 +++++++++++++++ src/GENERATED/include/decaf/ed448.hxx | 14 ++++++++ src/per_curve/decaf.tmpl.c | 44 +++++++++++++++++++++++++ src/per_curve/eddsa.tmpl.c | 15 +++++++++ src/per_curve/eddsa.tmpl.h | 26 +++++++++++++++ src/per_curve/eddsa.tmpl.hxx | 14 ++++++++ test/test_decaf.cxx | 42 +++++++++++++++++++++++ 13 files changed, 339 insertions(+) diff --git a/src/GENERATED/c/curve25519/decaf.c b/src/GENERATED/c/curve25519/decaf.c index afbb958..fa4f8fd 100644 --- a/src/GENERATED/c/curve25519/decaf.c +++ b/src/GENERATED/c/curve25519/decaf.c @@ -1318,6 +1318,50 @@ decaf_error_t decaf_x25519 ( return decaf_succeed_if(mask_to_bool(nz)); } +/* Thanks Johan Pascal */ +void decaf_ed25519_convert_public_key_to_x25519 ( + uint8_t x[DECAF_X25519_PUBLIC_BYTES], + const uint8_t ed[DECAF_EDDSA_25519_PUBLIC_BYTES] +) { + gf y; + { + uint8_t enc2[DECAF_EDDSA_25519_PUBLIC_BYTES]; + memcpy(enc2,ed,sizeof(enc2)); + + /* retrieve y from the ed compressed point */ + enc2[DECAF_EDDSA_25519_PUBLIC_BYTES-1] &= ~0x80; + ignore_result(gf_deserialize(y, enc2, 0)); + decaf_bzero(enc2,sizeof(enc2)); + } + + { + gf n,d; + +#if EDDSA_USE_SIGMA_ISOGENY + /* u = (1+y)/(1-y)*/ + gf_add(n, y, ONE); /* n = y+1 */ + gf_sub(d, ONE, y); /* d = 1-y */ + gf_invert(d, d); /* d = 1/(1-y) */ + gf_mul(y, n, d); /* u = (y+1)/(1-y) */ + gf_serialize(x,y,1); +#else /* EDDSA_USE_SIGMA_ISOGENY */ + /* u = y^2 * (1-dy^2) / (1-y^2) */ + gf_sqr(n,y); /* y^2*/ + gf_sub(d,ONE,n); /* 1-y^2*/ + gf_invert(d,d); /* 1/(1-y^2)*/ + gf_mul(y,n,d); /* y^2 / (1-y^2) */ + gf_mulw(d,n,EDWARDS_D); /* dy^2*/ + gf_sub(d, ONE, d); /* 1-dy^2*/ + gf_mul(n, y, d); /* y^2 * (1-dy^2) / (1-y^2) */ + gf_serialize(x,n,1); +#endif /* EDDSA_USE_SIGMA_ISOGENY */ + + decaf_bzero(y,sizeof(y)); + decaf_bzero(n,sizeof(n)); + decaf_bzero(d,sizeof(d)); + } +} + void decaf_x25519_generate_key ( uint8_t out[X_PUBLIC_BYTES], const uint8_t scalar[X_PRIVATE_BYTES] diff --git a/src/GENERATED/c/curve25519/eddsa.c b/src/GENERATED/c/curve25519/eddsa.c index 4e37b82..9e8aa15 100644 --- a/src/GENERATED/c/curve25519/eddsa.c +++ b/src/GENERATED/c/curve25519/eddsa.c @@ -89,6 +89,21 @@ void decaf_ed25519_prehash_init ( hash_init(hash); } +/* In this file because it uses the hash */ +void decaf_ed25519_convert_private_key_to_x25519 ( + uint8_t x[DECAF_X25519_PRIVATE_BYTES], + const uint8_t ed[DECAF_EDDSA_25519_PRIVATE_BYTES] +) { + /* pass the private key through hash_hash function */ + /* and keep the first DECAF_X25519_PRIVATE_BYTES bytes */ + hash_hash( + x, + DECAF_X25519_PRIVATE_BYTES, + ed, + DECAF_EDDSA_25519_PRIVATE_BYTES + ); +} + void decaf_ed25519_derive_public_key ( uint8_t pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES], const uint8_t privkey[DECAF_EDDSA_25519_PRIVATE_BYTES] diff --git a/src/GENERATED/c/ed448goldilocks/decaf.c b/src/GENERATED/c/ed448goldilocks/decaf.c index c159d1d..4b664fa 100644 --- a/src/GENERATED/c/ed448goldilocks/decaf.c +++ b/src/GENERATED/c/ed448goldilocks/decaf.c @@ -1318,6 +1318,50 @@ decaf_error_t decaf_x448 ( return decaf_succeed_if(mask_to_bool(nz)); } +/* Thanks Johan Pascal */ +void decaf_ed448_convert_public_key_to_x448 ( + uint8_t x[DECAF_X448_PUBLIC_BYTES], + const uint8_t ed[DECAF_EDDSA_448_PUBLIC_BYTES] +) { + gf y; + { + uint8_t enc2[DECAF_EDDSA_448_PUBLIC_BYTES]; + memcpy(enc2,ed,sizeof(enc2)); + + /* retrieve y from the ed compressed point */ + enc2[DECAF_EDDSA_448_PUBLIC_BYTES-1] &= ~0x80; + ignore_result(gf_deserialize(y, enc2, 0)); + decaf_bzero(enc2,sizeof(enc2)); + } + + { + gf n,d; + +#if EDDSA_USE_SIGMA_ISOGENY + /* u = (1+y)/(1-y)*/ + gf_add(n, y, ONE); /* n = y+1 */ + gf_sub(d, ONE, y); /* d = 1-y */ + gf_invert(d, d); /* d = 1/(1-y) */ + gf_mul(y, n, d); /* u = (y+1)/(1-y) */ + gf_serialize(x,y,1); +#else /* EDDSA_USE_SIGMA_ISOGENY */ + /* u = y^2 * (1-dy^2) / (1-y^2) */ + gf_sqr(n,y); /* y^2*/ + gf_sub(d,ONE,n); /* 1-y^2*/ + gf_invert(d,d); /* 1/(1-y^2)*/ + gf_mul(y,n,d); /* y^2 / (1-y^2) */ + gf_mulw(d,n,EDWARDS_D); /* dy^2*/ + gf_sub(d, ONE, d); /* 1-dy^2*/ + gf_mul(n, y, d); /* y^2 * (1-dy^2) / (1-y^2) */ + gf_serialize(x,n,1); +#endif /* EDDSA_USE_SIGMA_ISOGENY */ + + decaf_bzero(y,sizeof(y)); + decaf_bzero(n,sizeof(n)); + decaf_bzero(d,sizeof(d)); + } +} + void decaf_x448_generate_key ( uint8_t out[X_PUBLIC_BYTES], const uint8_t scalar[X_PRIVATE_BYTES] diff --git a/src/GENERATED/c/ed448goldilocks/eddsa.c b/src/GENERATED/c/ed448goldilocks/eddsa.c index 9d78fb3..81fa6fa 100644 --- a/src/GENERATED/c/ed448goldilocks/eddsa.c +++ b/src/GENERATED/c/ed448goldilocks/eddsa.c @@ -89,6 +89,21 @@ void decaf_ed448_prehash_init ( hash_init(hash); } +/* In this file because it uses the hash */ +void decaf_ed448_convert_private_key_to_x448 ( + uint8_t x[DECAF_X448_PRIVATE_BYTES], + const uint8_t ed[DECAF_EDDSA_448_PRIVATE_BYTES] +) { + /* pass the private key through hash_hash function */ + /* and keep the first DECAF_X448_PRIVATE_BYTES bytes */ + hash_hash( + x, + DECAF_X448_PRIVATE_BYTES, + ed, + DECAF_EDDSA_448_PRIVATE_BYTES + ); +} + void decaf_ed448_derive_public_key ( uint8_t pubkey[DECAF_EDDSA_448_PUBLIC_BYTES], const uint8_t privkey[DECAF_EDDSA_448_PRIVATE_BYTES] diff --git a/src/GENERATED/include/decaf/ed255.h b/src/GENERATED/include/decaf/ed255.h index 4b8c981..99e1ebc 100644 --- a/src/GENERATED/include/decaf/ed255.h +++ b/src/GENERATED/include/decaf/ed255.h @@ -192,6 +192,32 @@ decaf_error_t decaf_255_point_decode_like_eddsa_and_ignore_cofactor ( const uint8_t enc[DECAF_EDDSA_25519_PUBLIC_BYTES] ) API_VIS NONNULL NOINLINE; +/** + * @brief EdDSA to ECDH public key conversion + * Deserialize the point to get y on Edwards curve, + * Convert it to u coordinate on Montgomery curve. + * + * @param[out] x The ECDH public key as in RFC7748(point on Montgomery curve) + * @param[in] ed The EdDSA public key(point on Edwards curve) + */ +void decaf_ed25519_convert_public_key_to_x25519 ( + uint8_t x[DECAF_X25519_PUBLIC_BYTES], + const uint8_t ed[DECAF_EDDSA_25519_PUBLIC_BYTES] +) API_VIS NONNULL NOINLINE; + +/** + * @brief EdDSA to ECDH private key conversion + * Using the appropriate hash function, hash the EdDSA private key + * and keep only the lower bytes to get the ECDH private key + * + * @param[out] x The ECDH private key as in RFC7748 + * @param[in] ed The EdDSA private key + */ +void decaf_ed25519_convert_private_key_to_x25519 ( + uint8_t x[DECAF_X25519_PRIVATE_BYTES], + const uint8_t ed[DECAF_EDDSA_25519_PRIVATE_BYTES] +) API_VIS NONNULL NOINLINE; + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/GENERATED/include/decaf/ed255.hxx b/src/GENERATED/include/decaf/ed255.hxx index 84215e9..d80f83e 100644 --- a/src/GENERATED/include/decaf/ed255.hxx +++ b/src/GENERATED/include/decaf/ed255.hxx @@ -237,6 +237,13 @@ public: memcpy(x,priv_.data(), priv_.size()); } + /** Convert to X format (to be used for key exchange) */ + inline SecureBuffer convert_to_x() const { + SecureBuffer out(DECAF_X25519_PRIVATE_BYTES); + decaf_ed25519_convert_private_key_to_x25519(out.data(), priv_.data()); + return out; + } + /** Return the corresponding public key */ inline MyPublicKey pub() const NOEXCEPT { MyPublicKey pub(*this); @@ -403,6 +410,13 @@ public: inline void serialize_into(unsigned char *x) const NOEXCEPT { memcpy(x,pub_.data(), pub_.size()); } + + /** Convert to X format (to be used for key exchange) */ + inline SecureBuffer convert_to_x() const { + SecureBuffer out(DECAF_X25519_PRIVATE_BYTES); + decaf_ed25519_convert_public_key_to_x25519(out.data(), pub_.data()); + return out; + } }; /* class PublicKey */ }; /* template<> struct EdDSA */ diff --git a/src/GENERATED/include/decaf/ed448.h b/src/GENERATED/include/decaf/ed448.h index a0b5d98..7a56e92 100644 --- a/src/GENERATED/include/decaf/ed448.h +++ b/src/GENERATED/include/decaf/ed448.h @@ -191,6 +191,32 @@ decaf_error_t decaf_448_point_decode_like_eddsa_and_ignore_cofactor ( const uint8_t enc[DECAF_EDDSA_448_PUBLIC_BYTES] ) API_VIS NONNULL NOINLINE; +/** + * @brief EdDSA to ECDH public key conversion + * Deserialize the point to get y on Edwards curve, + * Convert it to u coordinate on Montgomery curve. + * + * @param[out] x The ECDH public key as in RFC7748(point on Montgomery curve) + * @param[in] ed The EdDSA public key(point on Edwards curve) + */ +void decaf_ed448_convert_public_key_to_x448 ( + uint8_t x[DECAF_X448_PUBLIC_BYTES], + const uint8_t ed[DECAF_EDDSA_448_PUBLIC_BYTES] +) API_VIS NONNULL NOINLINE; + +/** + * @brief EdDSA to ECDH private key conversion + * Using the appropriate hash function, hash the EdDSA private key + * and keep only the lower bytes to get the ECDH private key + * + * @param[out] x The ECDH private key as in RFC7748 + * @param[in] ed The EdDSA private key + */ +void decaf_ed448_convert_private_key_to_x448 ( + uint8_t x[DECAF_X448_PRIVATE_BYTES], + const uint8_t ed[DECAF_EDDSA_448_PRIVATE_BYTES] +) API_VIS NONNULL NOINLINE; + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/GENERATED/include/decaf/ed448.hxx b/src/GENERATED/include/decaf/ed448.hxx index 10c3d4b..d299939 100644 --- a/src/GENERATED/include/decaf/ed448.hxx +++ b/src/GENERATED/include/decaf/ed448.hxx @@ -237,6 +237,13 @@ public: memcpy(x,priv_.data(), priv_.size()); } + /** Convert to X format (to be used for key exchange) */ + inline SecureBuffer convert_to_x() const { + SecureBuffer out(DECAF_X448_PRIVATE_BYTES); + decaf_ed448_convert_private_key_to_x448(out.data(), priv_.data()); + return out; + } + /** Return the corresponding public key */ inline MyPublicKey pub() const NOEXCEPT { MyPublicKey pub(*this); @@ -403,6 +410,13 @@ public: inline void serialize_into(unsigned char *x) const NOEXCEPT { memcpy(x,pub_.data(), pub_.size()); } + + /** Convert to X format (to be used for key exchange) */ + inline SecureBuffer convert_to_x() const { + SecureBuffer out(DECAF_X448_PRIVATE_BYTES); + decaf_ed448_convert_public_key_to_x448(out.data(), pub_.data()); + return out; + } }; /* class PublicKey */ }; /* template<> struct EdDSA */ diff --git a/src/per_curve/decaf.tmpl.c b/src/per_curve/decaf.tmpl.c index f1cac90..842369e 100644 --- a/src/per_curve/decaf.tmpl.c +++ b/src/per_curve/decaf.tmpl.c @@ -1307,6 +1307,50 @@ decaf_error_t decaf_x$(gf_shortname) ( return decaf_succeed_if(mask_to_bool(nz)); } +/* Thanks Johan Pascal */ +void decaf_ed$(gf_shortname)_convert_public_key_to_x$(gf_shortname) ( + uint8_t x[DECAF_X$(gf_shortname)_PUBLIC_BYTES], + const uint8_t ed[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES] +) { + gf y; + { + uint8_t enc2[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES]; + memcpy(enc2,ed,sizeof(enc2)); + + /* retrieve y from the ed compressed point */ + enc2[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES-1] &= ~0x80; + ignore_result(gf_deserialize(y, enc2, 0)); + decaf_bzero(enc2,sizeof(enc2)); + } + + { + gf n,d; + +#if EDDSA_USE_SIGMA_ISOGENY + /* u = (1+y)/(1-y)*/ + gf_add(n, y, ONE); /* n = y+1 */ + gf_sub(d, ONE, y); /* d = 1-y */ + gf_invert(d, d); /* d = 1/(1-y) */ + gf_mul(y, n, d); /* u = (y+1)/(1-y) */ + gf_serialize(x,y,1); +#else /* EDDSA_USE_SIGMA_ISOGENY */ + /* u = y^2 * (1-dy^2) / (1-y^2) */ + gf_sqr(n,y); /* y^2*/ + gf_sub(d,ONE,n); /* 1-y^2*/ + gf_invert(d,d); /* 1/(1-y^2)*/ + gf_mul(y,n,d); /* y^2 / (1-y^2) */ + gf_mulw(d,n,EDWARDS_D); /* dy^2*/ + gf_sub(d, ONE, d); /* 1-dy^2*/ + gf_mul(n, y, d); /* y^2 * (1-dy^2) / (1-y^2) */ + gf_serialize(x,n,1); +#endif /* EDDSA_USE_SIGMA_ISOGENY */ + + decaf_bzero(y,sizeof(y)); + decaf_bzero(n,sizeof(n)); + decaf_bzero(d,sizeof(d)); + } +} + void decaf_x$(gf_shortname)_generate_key ( uint8_t out[X_PUBLIC_BYTES], const uint8_t scalar[X_PRIVATE_BYTES] diff --git a/src/per_curve/eddsa.tmpl.c b/src/per_curve/eddsa.tmpl.c index 7c48408..fb0210e 100644 --- a/src/per_curve/eddsa.tmpl.c +++ b/src/per_curve/eddsa.tmpl.c @@ -80,6 +80,21 @@ void decaf_ed$(gf_shortname)_prehash_init ( hash_init(hash); } +/* In this file because it uses the hash */ +void decaf_ed$(gf_shortname)_convert_private_key_to_x$(gf_shortname) ( + uint8_t x[DECAF_X$(gf_shortname)_PRIVATE_BYTES], + const uint8_t ed[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES] +) { + /* pass the private key through hash_hash function */ + /* and keep the first DECAF_X$(gf_shortname)_PRIVATE_BYTES bytes */ + hash_hash( + x, + DECAF_X$(gf_shortname)_PRIVATE_BYTES, + ed, + DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES + ); +} + void decaf_ed$(gf_shortname)_derive_public_key ( uint8_t pubkey[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES], const uint8_t privkey[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES] diff --git a/src/per_curve/eddsa.tmpl.h b/src/per_curve/eddsa.tmpl.h index 5ca2181..26e5a2f 100644 --- a/src/per_curve/eddsa.tmpl.h +++ b/src/per_curve/eddsa.tmpl.h @@ -176,6 +176,32 @@ decaf_error_t $(c_ns)_point_decode_like_eddsa_and_ignore_cofactor ( const uint8_t enc[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES] ) API_VIS NONNULL NOINLINE; +/** + * @brief EdDSA to ECDH public key conversion + * Deserialize the point to get y on Edwards curve, + * Convert it to u coordinate on Montgomery curve. + * + * @param[out] x The ECDH public key as in RFC7748(point on Montgomery curve) + * @param[in] ed The EdDSA public key(point on Edwards curve) + */ +void decaf_ed$(gf_shortname)_convert_public_key_to_x$(gf_shortname) ( + uint8_t x[DECAF_X$(gf_shortname)_PUBLIC_BYTES], + const uint8_t ed[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES] +) API_VIS NONNULL NOINLINE; + +/** + * @brief EdDSA to ECDH private key conversion + * Using the appropriate hash function, hash the EdDSA private key + * and keep only the lower bytes to get the ECDH private key + * + * @param[out] x The ECDH private key as in RFC7748 + * @param[in] ed The EdDSA private key + */ +void decaf_ed$(gf_shortname)_convert_private_key_to_x$(gf_shortname) ( + uint8_t x[DECAF_X$(gf_shortname)_PRIVATE_BYTES], + const uint8_t ed[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES] +) API_VIS NONNULL NOINLINE; + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/per_curve/eddsa.tmpl.hxx b/src/per_curve/eddsa.tmpl.hxx index c88a24a..cc47ac1 100644 --- a/src/per_curve/eddsa.tmpl.hxx +++ b/src/per_curve/eddsa.tmpl.hxx @@ -221,6 +221,13 @@ public: memcpy(x,priv_.data(), priv_.size()); } + /** Convert to X format (to be used for key exchange) */ + inline SecureBuffer convert_to_x() const { + SecureBuffer out(DECAF_X$(gf_shortname)_PRIVATE_BYTES); + decaf_ed$(gf_shortname)_convert_private_key_to_x$(gf_shortname)(out.data(), priv_.data()); + return out; + } + /** Return the corresponding public key */ inline MyPublicKey pub() const NOEXCEPT { MyPublicKey pub(*this); @@ -387,6 +394,13 @@ public: inline void serialize_into(unsigned char *x) const NOEXCEPT { memcpy(x,pub_.data(), pub_.size()); } + + /** Convert to X format (to be used for key exchange) */ + inline SecureBuffer convert_to_x() const { + SecureBuffer out(DECAF_X$(gf_shortname)_PRIVATE_BYTES); + decaf_ed$(gf_shortname)_convert_public_key_to_x$(gf_shortname)(out.data(), pub_.data()); + return out; + } }; /* class PublicKey */ }; /* template<> struct EdDSA<$(cxx_ns)> */ diff --git a/test/test_decaf.cxx b/test/test_decaf.cxx index 085db58..2d5d10d 100644 --- a/test/test_decaf.cxx +++ b/test/test_decaf.cxx @@ -534,12 +534,54 @@ static void test_eddsa() { } +/* Thanks Johan Pascal */ +static void test_convert_eddsa_to_x() { + Test test("ECDH using EdDSA keys"); + SpongeRng rng(Block("test_x_on_eddsa_key"),SpongeRng::DETERMINISTIC); + + for (int i=0; i::PrivateKey alice_priv(rng); + typename EdDSA::PublicKey alice_pub(alice_priv); + typename EdDSA::PrivateKey bob_priv(rng); + typename EdDSA::PublicKey bob_pub(bob_priv); + + /* convert them to ECDH format + * check public key value by computing it from direct conversion and regeneration from converted private) + */ + SecureBuffer alice_priv_x = alice_priv.convert_to_x(); + SecureBuffer alice_pub_x_conversion = alice_pub.convert_to_x(); + SecureBuffer alice_pub_x_generated = DhLadder::derive_public_key(alice_priv_x); + if (!memeq(alice_pub_x_conversion, alice_pub_x_generated)) { + test.fail(); + printf(" Ed2X Public key convertion and regeneration from converted private key differs.\n"); + } + SecureBuffer bob_priv_x = bob_priv.convert_to_x(); + SecureBuffer bob_pub_x_conversion = bob_pub.convert_to_x(); + SecureBuffer bob_pub_x_generated = DhLadder::derive_public_key(bob_priv_x); + if (!memeq(bob_pub_x_conversion, bob_pub_x_generated)) { + test.fail(); + printf(" Ed2X Public key convertion and regeneration from converted private key differs.\n"); + } + + /* compute shared secrets and check they match */ + SecureBuffer alice_shared = DhLadder::shared_secret(bob_pub_x_conversion, alice_priv_x); + SecureBuffer bob_shared = DhLadder::shared_secret(alice_pub_x_conversion, bob_priv_x); + + if (!memeq(alice_shared, bob_shared)) { + test.fail(); + printf(" ECDH shared secret mismatch.\n"); + } + } +} + static void run() { printf("Testing %s:\n",Group::name()); test_arithmetic(); test_elligator(); test_ec(); test_eddsa(); + test_convert_eddsa_to_x(); test_cfrg_crypto(); test_cfrg_vectors(); printf("\n");