diff --git a/.gitignore b/.gitignore
index 101f340c..6898147f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,6 +74,7 @@ test/default/core3
test/default/core4
test/default/core5
test/default/core6
+test/default/ed25519_convert
test/default/generichash
test/default/generichash2
test/default/generichash3
diff --git a/builds/msvc/vs2010/test/test.vcxproj b/builds/msvc/vs2010/test/test.vcxproj
index 2cd94c3c..c84b2d65 100644
--- a/builds/msvc/vs2010/test/test.vcxproj
+++ b/builds/msvc/vs2010/test/test.vcxproj
@@ -112,6 +112,9 @@
true
+
+ true
+
true
@@ -211,4 +214,4 @@
-
\ No newline at end of file
+
diff --git a/builds/msvc/vs2010/test/test.vcxproj.filters b/builds/msvc/vs2010/test/test.vcxproj.filters
index c0819e8e..e09eef9b 100644
--- a/builds/msvc/vs2010/test/test.vcxproj.filters
+++ b/builds/msvc/vs2010/test/test.vcxproj.filters
@@ -49,6 +49,9 @@
src
+
+ src
+
src
@@ -159,4 +162,4 @@
{5b5af4b5-c6aa-4b30-bdef-074b1bdc43ea}
-
\ No newline at end of file
+
diff --git a/builds/msvc/vs2012/test/test.vcxproj b/builds/msvc/vs2012/test/test.vcxproj
index 65fd4d8f..40c2afaf 100644
--- a/builds/msvc/vs2012/test/test.vcxproj
+++ b/builds/msvc/vs2012/test/test.vcxproj
@@ -112,6 +112,9 @@
true
+
+ true
+
true
@@ -211,4 +214,4 @@
-
\ No newline at end of file
+
diff --git a/builds/msvc/vs2012/test/test.vcxproj.filters b/builds/msvc/vs2012/test/test.vcxproj.filters
index c0819e8e..e09eef9b 100644
--- a/builds/msvc/vs2012/test/test.vcxproj.filters
+++ b/builds/msvc/vs2012/test/test.vcxproj.filters
@@ -49,6 +49,9 @@
src
+
+ src
+
src
@@ -159,4 +162,4 @@
{5b5af4b5-c6aa-4b30-bdef-074b1bdc43ea}
-
\ No newline at end of file
+
diff --git a/builds/msvc/vs2013/test/test.vcxproj b/builds/msvc/vs2013/test/test.vcxproj
index 780396e9..eff09cc2 100644
--- a/builds/msvc/vs2013/test/test.vcxproj
+++ b/builds/msvc/vs2013/test/test.vcxproj
@@ -112,6 +112,9 @@
true
+
+ true
+
true
@@ -211,4 +214,4 @@
-
\ No newline at end of file
+
diff --git a/builds/msvc/vs2013/test/test.vcxproj.filters b/builds/msvc/vs2013/test/test.vcxproj.filters
index c0819e8e..e09eef9b 100644
--- a/builds/msvc/vs2013/test/test.vcxproj.filters
+++ b/builds/msvc/vs2013/test/test.vcxproj.filters
@@ -49,6 +49,9 @@
src
+
+ src
+
src
@@ -159,4 +162,4 @@
{5b5af4b5-c6aa-4b30-bdef-074b1bdc43ea}
-
\ No newline at end of file
+
diff --git a/src/libsodium/crypto_sign/ed25519/ref10/keypair.c b/src/libsodium/crypto_sign/ed25519/ref10/keypair.c
index 79556472..a83095b1 100644
--- a/src/libsodium/crypto_sign/ed25519/ref10/keypair.c
+++ b/src/libsodium/crypto_sign/ed25519/ref10/keypair.c
@@ -2,8 +2,11 @@
#include
#include "api.h"
-#include "randombytes.h"
#include "crypto_hash_sha512.h"
+#include "crypto_scalarmult_curve25519.h"
+#include "randombytes.h"
+#include "utils.h"
+#include "fe.h"
#include "ge.h"
int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk,
@@ -31,3 +34,39 @@ int crypto_sign_keypair(unsigned char *pk, unsigned char *sk)
randombytes(seed,32);
return crypto_sign_seed_keypair(pk,sk,seed);
}
+
+int crypto_sign_ed25519_pk_to_curve25519(unsigned char *curve25519_pk,
+ const unsigned char *ed25519_pk)
+{
+ ge_p3 A;
+ fe x;
+ fe one_minus_y;
+
+ ge_frombytes_negate_vartime(&A, ed25519_pk);
+ fe_1(one_minus_y);
+ fe_sub(one_minus_y, one_minus_y, A.Y);
+ fe_invert(one_minus_y, one_minus_y);
+ fe_1(x);
+ fe_add(x, x, A.Y);
+ fe_mul(x, x, one_minus_y);
+ fe_tobytes(curve25519_pk, x);
+
+ return 0;
+}
+
+int crypto_sign_ed25519_sk_to_curve25519(unsigned char *curve25519_sk,
+ const unsigned char *ed25519_sk)
+{
+ unsigned char h[crypto_hash_sha512_BYTES];
+
+ crypto_hash_sha512(h, ed25519_sk,
+ crypto_sign_ed25519_SECRETKEYBYTES -
+ crypto_sign_ed25519_PUBLICKEYBYTES);
+ h[0] &= 248;
+ h[31] &= 127;
+ h[31] |= 64;
+ memcpy(curve25519_sk, h, crypto_scalarmult_curve25519_BYTES);
+ sodium_memzero(h, sizeof h);
+
+ return 0;
+}
diff --git a/src/libsodium/include/sodium/crypto_sign_ed25519.h b/src/libsodium/include/sodium/crypto_sign_ed25519.h
index 101b6c95..e1f93aad 100644
--- a/src/libsodium/include/sodium/crypto_sign_ed25519.h
+++ b/src/libsodium/include/sodium/crypto_sign_ed25519.h
@@ -57,6 +57,13 @@ SODIUM_EXPORT
int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk,
const unsigned char *seed);
+SODIUM_EXPORT
+int crypto_sign_ed25519_pk_to_curve25519(unsigned char *curve25519_pk,
+ const unsigned char *ed25519_pk);
+
+SODIUM_EXPORT
+int crypto_sign_ed25519_sk_to_curve25519(unsigned char *curve25519_sk,
+ const unsigned char *ed25519_sk);
#ifdef __cplusplus
}
#endif
diff --git a/test/default/Makefile.am b/test/default/Makefile.am
index cafc782d..c25efe1b 100644
--- a/test/default/Makefile.am
+++ b/test/default/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST = \
core4.exp \
core5.exp \
core6.exp \
+ ed25519_convert.exp \
generichash.exp \
generichash2.exp \
generichash3.exp \
@@ -77,6 +78,7 @@ DISTCLEANFILES = \
core4.res \
core5.res \
core6.res \
+ ed25519_convert.res \
generichash.res \
generichash2.res \
generichash3.res \
@@ -139,6 +141,7 @@ TESTS_TARGETS = \
core4 \
core5 \
core6 \
+ ed25519_convert \
generichash \
generichash2 \
generichash3 \
@@ -241,6 +244,9 @@ core5_LDADD = $(TESTS_LDADD)
core6_SOURCE = cmptest.h core6.c
core6_LDADD = $(TESTS_LDADD)
+ed25519_convert_SOURCE = cmptest.h ed25519_convert.c
+ed25519_convert_LDADD = $(TESTS_LDADD)
+
generichash_SOURCE = cmptest.h generichash.c
generichash_LDADD = $(TESTS_LDADD)
diff --git a/test/default/ed25519_convert.c b/test/default/ed25519_convert.c
new file mode 100644
index 00000000..da0f2666
--- /dev/null
+++ b/test/default/ed25519_convert.c
@@ -0,0 +1,49 @@
+#include
+#include
+
+#define TEST_NAME "ed25519_convert"
+#include "cmptest.h"
+
+static const unsigned char keypair_seed[crypto_sign_ed25519_SEEDBYTES] = {
+ 0x42, 0x11, 0x51, 0xa4, 0x59, 0xfa, 0xea, 0xde,
+ 0x3d, 0x24, 0x71, 0x15, 0xf9, 0x4a, 0xed, 0xae,
+ 0x42, 0x31, 0x81, 0x24, 0x09, 0x5a, 0xfa, 0xbe,
+ 0x4d, 0x14, 0x51, 0xa5, 0x59, 0xfa, 0xed, 0xee
+};
+
+int main(void)
+{
+ unsigned char ed25519_pk[crypto_sign_ed25519_PUBLICKEYBYTES];
+ unsigned char ed25519_skpk[crypto_sign_ed25519_SECRETKEYBYTES +
+ crypto_sign_ed25519_PUBLICKEYBYTES];
+ unsigned char curve25519_pk[crypto_scalarmult_curve25519_BYTES];
+ unsigned char curve25519_pk2[crypto_scalarmult_curve25519_BYTES];
+ unsigned char curve25519_sk[crypto_scalarmult_curve25519_BYTES];
+ char curve25519_pk_hex[crypto_scalarmult_curve25519_BYTES * 2 + 1];
+ char curve25519_sk_hex[crypto_scalarmult_curve25519_BYTES * 2 + 1];
+ unsigned int i;
+
+ crypto_sign_ed25519_seed_keypair(ed25519_pk, ed25519_skpk, keypair_seed);
+ crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk);
+ crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk);
+ sodium_bin2hex(curve25519_pk_hex, sizeof curve25519_pk_hex,
+ curve25519_pk, sizeof curve25519_pk);
+ sodium_bin2hex(curve25519_sk_hex, sizeof curve25519_sk_hex,
+ curve25519_sk, sizeof curve25519_sk);
+
+ printf("curve25519 pk: [%s]\n", curve25519_pk_hex);
+ printf("curve25519 sk: [%s]\n", curve25519_sk_hex);
+
+ for (i = 0U; i < 500U; i++) {
+ crypto_sign_ed25519_keypair(ed25519_pk, ed25519_skpk);
+ crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk);
+ crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk);
+ crypto_scalarmult_curve25519_base(curve25519_pk2, curve25519_sk);
+ if (memcmp(curve25519_pk, curve25519_pk2, sizeof curve25519_pk) != 0) {
+ printf("conversion failed\n");
+ }
+ }
+ printf("ok\n");
+
+ return 0;
+}
diff --git a/test/default/ed25519_convert.exp b/test/default/ed25519_convert.exp
new file mode 100644
index 00000000..cba2b7b8
--- /dev/null
+++ b/test/default/ed25519_convert.exp
@@ -0,0 +1,3 @@
+curve25519 pk: [f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50]
+curve25519 sk: [8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166]
+ok