From d8946df8eb342c0a7c56c59444c12f5682aa0f5d Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Tue, 17 Jul 2018 08:28:33 -0400 Subject: [PATCH] Add crypto_sign_sk2pk (PR #668) This should allow users to convert a ed25519 seret key to a public key without rolling their own code --- naclite.h | 15 +++++++++++++++ tweetnacl.cpp | 22 +++++++++++++++++++--- validat4.cpp | 7 +++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/naclite.h b/naclite.h index c2183ae5..c8d4a9d1 100644 --- a/naclite.h +++ b/naclite.h @@ -3,6 +3,10 @@ // Daniel J. Bernstein, Bernard van Gastel, Wesley Janssen, // Tanja Lange, Peter Schwabe and Sjaak Smetsers. +// The Tweet API was added to the Crypto++ library to cross-validate results. +// We debated over putting it in the Test namespace, but settled for the NaCl +// namespace to segreate it from other parts of the library. + /// \file naclite.h /// \brief Crypto++ interface to TweetNaCl library (20140917) /// \details TweetNaCl is a compact reimplementation of the NaCl library by @@ -373,6 +377,17 @@ int crypto_sign_open(byte *m,word64 *mlen,const byte *sm,word64 n,const byte *pk /// \since Crypto++ 6.0 int crypto_sign_keypair(byte *pk, byte *sk); +/// \brief Generate a public key from a secret key +/// \param pk public key byte buffer +/// \param sk private key byte buffer +/// \details crypto_sign_sk2pk() creates an ed25519 public key from an existing +/// secret key without the tail public key bytes. The function is not part of +/// libsodium or Tweet API. It was added for interop with the I2P Java library. +/// \returns 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 7.1 +int crypto_sign_sk2pk(byte *pk, const byte *sk); + /// \brief Produce a keystream using XSalsa20 /// \details crypto_stream() uses crypto_stream_xsalsa20 /// \returns 0 on success, non-0 otherwise diff --git a/tweetnacl.cpp b/tweetnacl.cpp index b36f1e08..05e66179 100644 --- a/tweetnacl.cpp +++ b/tweetnacl.cpp @@ -755,6 +755,25 @@ int crypto_sign_keypair(byte *pk, byte *sk) return 0; } +int crypto_sign_sk2pk(byte *pk, const byte *sk) +{ + byte d[64]; + gf p[4]; + int i; + + // randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p,d); + pack(pk,p); + + // for(i=0; i<32; ++i) sk[32 + i] = pk[i]; + return 0; +} + static const word64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; static void modL(byte *r,sword64 x[64]) @@ -895,6 +914,3 @@ NAMESPACE_END // CryptoPP NAMESPACE_END // NaCl #endif // NO_OS_DEPENDENCE - - - diff --git a/validat4.cpp b/validat4.cpp index cf7ef70b..71b791e0 100644 --- a/validat4.cpp +++ b/validat4.cpp @@ -455,6 +455,13 @@ bool TestCryptoSignKeys() { fail = (crypto_sign_keypair(pk, sk) != 0); pass = !fail && pass; + + byte xk[crypto_sign_PUBLICKEYBYTES]; + fail = (crypto_sign_sk2pk(xk, sk) != 0); + pass = !fail && pass; + + fail = std::memcmp(xk, pk, sizeof(xk)) != 0; + pass = !fail && pass; const word32 len = (i == 0 ? 0 : GlobalRNG().GenerateWord32(1, MAX_MESSAGE)); SecByteBlock m(len), sm(len+crypto_sign_BYTES), rm(len+crypto_sign_BYTES);