diff --git a/Makefile b/Makefile index 1388c04..858d122 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ HEADERS= Makefile $(shell find src test -name "*.h") $(BUILD_OBJ)/timestamp HEADERSXX = $(HEADERS) $(shell find . -name "*.hxx") # components needed by the lib -LIBCOMPONENTS = $(BUILD_OBJ)/utils.o $(BUILD_OBJ)/shake.o $(BUILD_OBJ)/decaf_crypto.o # and per-field components +LIBCOMPONENTS = $(BUILD_OBJ)/utils.o $(BUILD_OBJ)/shake.o $(BUILD_OBJ)/decaf_crypto_255.o $(BUILD_OBJ)/decaf_crypto_448.o # and per-field components BENCHCOMPONENTS = $(BUILD_OBJ)/bench.o $(BUILD_OBJ)/shake.o diff --git a/src/decaf_crypto.c b/src/decaf_crypto_255.c similarity index 98% rename from src/decaf_crypto.c rename to src/decaf_crypto_255.c index dc4e523..2647541 100644 --- a/src/decaf_crypto.c +++ b/src/decaf_crypto_255.c @@ -1,14 +1,14 @@ /** * @cond internal - * @file decaf_crypto.c + * @file decaf_crypto_255.c * @copyright * Copyright (c) 2015 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * @author Mike Hamburg - * @brief Example Decaf cyrpto routines. + * @brief Example Decaf crypto routines, 255-bit version. */ -#include +#include #include static const unsigned int DECAF_255_SCALAR_OVERKILL_BYTES = DECAF_255_SCALAR_BYTES + 8; diff --git a/src/decaf_crypto_448.c b/src/decaf_crypto_448.c new file mode 100644 index 0000000..111f4a8 --- /dev/null +++ b/src/decaf_crypto_448.c @@ -0,0 +1,213 @@ +/** + * @cond internal + * @file decaf_crypto_448.c + * @copyright + * Copyright (c) 2015 Cryptography Research, Inc. \n + * Released under the MIT License. See LICENSE.txt for license information. + * @author Mike Hamburg + * @brief Example Decaf crypto routines, 448-bit version + * @todo TODO don't copy-paste. + */ + +#include +#include + +static const unsigned int DECAF_448_SCALAR_OVERKILL_BYTES = DECAF_448_SCALAR_BYTES + 8; + +void decaf_448_derive_private_key ( + decaf_448_private_key_t priv, + const decaf_448_symmetric_key_t proto +) { + const char *magic = "decaf::derive_448_private_key"; /* TODO: canonicalize and freeze */ + uint8_t encoded_scalar[DECAF_448_SCALAR_OVERKILL_BYTES]; + decaf_448_point_t pub; + + keccak_strobe_t strobe; + strobe_init(strobe, &STROBE_256, magic, 0); + strobe_key(strobe, proto, sizeof(decaf_448_symmetric_key_t)); + strobe_prng(strobe, encoded_scalar, sizeof(encoded_scalar)); + strobe_destroy(strobe); + + memcpy(priv->sym, proto, sizeof(decaf_448_symmetric_key_t)); + decaf_448_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar)); + + decaf_448_precomputed_scalarmul(pub, decaf_448_precomputed_base, priv->secret_scalar); + decaf_448_point_encode(priv->pub, pub); + + decaf_bzero(encoded_scalar, sizeof(encoded_scalar)); +} + +void +decaf_448_destroy_private_key ( + decaf_448_private_key_t priv +) { + decaf_bzero((void*)priv, sizeof(decaf_448_private_key_t)); +} + +void decaf_448_private_to_public ( + decaf_448_public_key_t pub, + const decaf_448_private_key_t priv +) { + memcpy(pub, priv->pub, sizeof(decaf_448_public_key_t)); +} + +static const uint16_t SHARED_SECRET_MAX_BLOCK_SIZE = 1<<12; /* TODO: standardize and freeze */ + +decaf_error_t +decaf_448_shared_secret ( + uint8_t *shared, + size_t shared_bytes, + const decaf_448_private_key_t my_privkey, + const decaf_448_public_key_t your_pubkey, + int me_first +) { + const char *magic = "decaf::decaf_448_shared_secret"; /* TODO: canonicalize and freeze */ + keccak_strobe_t strobe; + strobe_init(strobe, &STROBE_256, magic, 0); + + uint8_t ss_ser[DECAF_448_SER_BYTES]; + + if (me_first) { + strobe_ad(strobe,my_privkey->pub,sizeof(decaf_448_public_key_t)); + strobe_ad(strobe,your_pubkey,sizeof(decaf_448_public_key_t)); + } else { + strobe_ad(strobe,your_pubkey,sizeof(decaf_448_public_key_t)); + strobe_ad(strobe,my_privkey->pub,sizeof(decaf_448_public_key_t)); + } + decaf_error_t ret = decaf_448_direct_scalarmul( + ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE + ); + + strobe_transact(strobe,NULL,ss_ser,sizeof(ss_ser),STROBE_CW_DH_KEY); + + while (shared_bytes) { + uint16_t cando = (shared_bytes > SHARED_SECRET_MAX_BLOCK_SIZE) + ? SHARED_SECRET_MAX_BLOCK_SIZE : shared_bytes; + strobe_prng(strobe,shared,cando); + shared_bytes -= cando; + shared += cando; + } + + strobe_destroy(strobe); + decaf_bzero(ss_ser, sizeof(ss_ser)); + + return ret; +} + +void +decaf_448_sign_strobe ( + keccak_strobe_t strobe, + decaf_448_signature_t sig, + const decaf_448_private_key_t priv +) { + uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES]; + decaf_448_point_t point; + decaf_448_scalar_t nonce, challenge; + + /* Stir pubkey */ + strobe_transact(strobe,NULL,priv->pub,sizeof(decaf_448_public_key_t),STROBE_CW_SIG_PK); + + /* Derive nonce */ + keccak_strobe_t strobe2; + memcpy(strobe2,strobe,sizeof(strobe2)); + strobe_key(strobe2,priv->sym,sizeof(decaf_448_symmetric_key_t)); + strobe_prng(strobe2,overkill,sizeof(overkill)); + strobe_destroy(strobe2); + + decaf_448_scalar_decode_long(nonce, overkill, sizeof(overkill)); + decaf_448_precomputed_scalarmul(point, decaf_448_precomputed_base, nonce); + decaf_448_point_encode(sig, point); + + + /* Derive challenge */ + strobe_transact(strobe,NULL,sig,DECAF_448_SER_BYTES,STROBE_CW_SIG_EPH); + strobe_transact(strobe,overkill,NULL,sizeof(overkill),STROBE_CW_SIG_CHAL); + decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill)); + + /* Respond */ + decaf_448_scalar_mul(challenge, challenge, priv->secret_scalar); + decaf_448_scalar_sub(nonce, nonce, challenge); + + /* Save results */ + decaf_448_scalar_encode(overkill, nonce); + strobe_transact(strobe,&sig[DECAF_448_SER_BYTES],overkill,DECAF_448_SCALAR_BYTES,STROBE_CW_SIG_RESP); + + /* Clean up */ + decaf_448_scalar_destroy(nonce); + decaf_448_scalar_destroy(challenge); + decaf_bzero(overkill,sizeof(overkill)); +} + +decaf_error_t +decaf_448_verify_strobe ( + keccak_strobe_t strobe, + const decaf_448_signature_t sig, + const decaf_448_public_key_t pub +) { + decaf_bool_t ret; + + uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES]; + decaf_448_point_t point, pubpoint; + decaf_448_scalar_t challenge, response; + + /* Stir pubkey */ + strobe_transact(strobe,NULL,pub,sizeof(decaf_448_public_key_t),STROBE_CW_SIG_PK); + + /* Derive nonce */ + strobe_transact(strobe,NULL,sig,DECAF_448_SER_BYTES,STROBE_CW_SIG_EPH); + ret = decaf_successful( decaf_448_point_decode(point, sig, DECAF_TRUE) ); + + /* Derive challenge */ + strobe_transact(strobe,overkill,NULL,sizeof(overkill),STROBE_CW_SIG_CHAL); + decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill)); + + /* Decode response */ + strobe_transact(strobe,overkill,&sig[DECAF_448_SER_BYTES],DECAF_448_SCALAR_BYTES,STROBE_CW_SIG_RESP); + ret &= decaf_successful( decaf_448_scalar_decode(response, overkill) ); + ret &= decaf_successful( decaf_448_point_decode(pubpoint, pub, DECAF_FALSE) ); + + decaf_448_base_double_scalarmul_non_secret ( + pubpoint, response, pubpoint, challenge + ); + + ret &= decaf_448_point_eq(pubpoint, point); + + /* Nothing here is secret, so don't do these things: + decaf_bzero(overkill,sizeof(overkill)); + decaf_448_point_destroy(point); + decaf_448_point_destroy(pubpoint); + decaf_448_scalar_destroy(challenge); + decaf_448_scalar_destroy(response); + */ + + return decaf_succeed_if(ret); +} + +void +decaf_448_sign ( + decaf_448_signature_t sig, + const decaf_448_private_key_t priv, + const unsigned char *message, + size_t message_len +) { + keccak_strobe_t ctx; + strobe_init(ctx,&STROBE_256,"decaf::decaf_448_sign",0); /* TODO: canonicalize and freeze */ + strobe_transact(ctx, NULL, message, message_len, STROBE_CW_STREAMING_PLAINTEXT); + decaf_448_sign_strobe(ctx, sig, priv); + strobe_destroy(ctx); +} + +decaf_error_t +decaf_448_verify ( + const decaf_448_signature_t sig, + const decaf_448_public_key_t pub, + const unsigned char *message, + size_t message_len +) { + keccak_strobe_t ctx; + strobe_init(ctx,&STROBE_256,"decaf::decaf_448_sign",0); /* TODO: canonicalize and freeze */ + strobe_transact(ctx, NULL, message, message_len, STROBE_CW_STREAMING_PLAINTEXT); + decaf_error_t ret = decaf_448_verify_strobe(ctx, sig, pub); + strobe_destroy(ctx); + return ret; +} diff --git a/src/public_include/decaf/crypto.hxx b/src/public_include/decaf/crypto.hxx index c799a06..c9efb1d 100644 --- a/src/public_include/decaf/crypto.hxx +++ b/src/public_include/decaf/crypto.hxx @@ -6,7 +6,8 @@ * Copyright (c) 2015 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * - * @brief Example cryptography using Decaf + * @brief Example cryptography using Decaf. + * @warning FIXME: this is out of sync with crypto_*.h */ #ifndef __DECAF_CRYPTO_HXX__ #define __DECAF_CRYPTO_HXX__ 1 diff --git a/src/public_include/decaf/crypto.h b/src/public_include/decaf/crypto_255.h similarity index 97% rename from src/public_include/decaf/crypto.h rename to src/public_include/decaf/crypto_255.h index 8723cca..5f877af 100644 --- a/src/public_include/decaf/crypto.h +++ b/src/public_include/decaf/crypto_255.h @@ -1,5 +1,5 @@ /** - * @file decaf/crypto.h + * @file decaf/crypto_255.h * @copyright * Copyright (c) 2015 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. @@ -11,10 +11,10 @@ * @warning Experimental! The names, parameter orders etc are likely to change. */ -#ifndef __DECAF_CRYPTO_H__ -#define __DECAF_CRYPTO_H__ 1 +#ifndef __DECAF_CRYPTO_255_H__ +#define __DECAF_CRYPTO_255_H__ 1 -#include +#include #include /** Number of bytes for a symmetric key (expanded to full key) */ @@ -188,6 +188,6 @@ decaf_255_verify ( } /* extern "C" */ #endif -#endif /* __DECAF_CRYPTO_H__ */ +#endif /* __DECAF_CRYPTO_255_H__ */ diff --git a/src/public_include/decaf/crypto_448.h b/src/public_include/decaf/crypto_448.h new file mode 100644 index 0000000..6890df3 --- /dev/null +++ b/src/public_include/decaf/crypto_448.h @@ -0,0 +1,193 @@ +/** + * @file decaf/crypto_448.h + * @copyright + * Copyright (c) 2015 Cryptography Research, Inc. \n + * Released under the MIT License. See LICENSE.txt for license information. + * @author Mike Hamburg + * @brief Example Decaf cyrpto routines. + * @warning These are merely examples, though they ought to be secure. But real + * protocols will decide differently on magic numbers, formats, which items to + * hash, etc. + * @warning Experimental! The names, parameter orders etc are likely to change. + */ + +#ifndef __DECAF_CRYPTO_448_H__ +#define __DECAF_CRYPTO_448_H__ 1 + +#include +#include + +/** Number of bytes for a symmetric key (expanded to full key) */ +#define DECAF_448_SYMMETRIC_KEY_BYTES 32 + +/** @cond internal */ +#define API_VIS __attribute__((visibility("default"))) __attribute__((noinline)) // TODO: synergize with decaf.h +#define WARN_UNUSED __attribute__((warn_unused_result)) +#define NONNULL1 __attribute__((nonnull(1))) +#define NONNULL2 __attribute__((nonnull(1,2))) +#define NONNULL3 __attribute__((nonnull(1,2,3))) +#define NONNULL134 __attribute__((nonnull(1,3,4))) +#define NONNULL5 __attribute__((nonnull(1,2,3,4,5))) +/** @endcond */ + +/** A symmetric key, the compressed point of a private key. */ +typedef unsigned char decaf_448_symmetric_key_t[DECAF_448_SYMMETRIC_KEY_BYTES]; + +/** An encoded public key. */ +typedef unsigned char decaf_448_public_key_t[DECAF_448_SER_BYTES]; + +/** A signature. */ +typedef unsigned char decaf_448_signature_t[DECAF_448_SER_BYTES + DECAF_448_SCALAR_BYTES]; + +typedef struct { + /** @cond intetrnal */ + /** The symmetric key from which everything is expanded */ + decaf_448_symmetric_key_t sym; + + /** The scalar x */ + decaf_448_scalar_t secret_scalar; + + /** x*Base */ + decaf_448_public_key_t pub; + /** @endcond */ +} /** Private key structure for pointers. */ + decaf_448_private_key_s, + /** A private key (gmp array[1] style). */ + decaf_448_private_key_t[1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Derive a key from its compressed form. + * @param [out] priv The derived private key. + * @param [in] proto The compressed or proto-key, which must be 32 random bytes. + */ +void decaf_448_derive_private_key ( + decaf_448_private_key_t priv, + const decaf_448_symmetric_key_t proto +) NONNULL2 API_VIS; + +/** + * @brief Destroy a private key. + */ +void decaf_448_destroy_private_key ( + decaf_448_private_key_t priv +) NONNULL1 API_VIS; + +/** + * @brief Convert a private key to a public one. + * @param [out] pub The extracted private key. + * @param [in] priv The private key. + */ +void decaf_448_private_to_public ( + decaf_448_public_key_t pub, + const decaf_448_private_key_t priv +) NONNULL2 API_VIS; + +/** + * @brief Compute a Diffie-Hellman shared secret. + * + * This is an example routine; real protocols would use something + * protocol-specific. + * + * @param [out] shared A buffer to store the shared secret. + * @param [in] shared_bytes The size of the buffer. + * @param [in] my_privkey My private key. + * @param [in] your_pubkey Your public key. + * @param [in] me_first Direction flag to break symmetry. + * + * @retval DECAF_SUCCESS Key exchange was successful. + * @retval DECAF_FAILURE Key exchange failed. + */ +decaf_error_t +decaf_448_shared_secret ( + uint8_t *shared, + size_t shared_bytes, + const decaf_448_private_key_t my_privkey, + const decaf_448_public_key_t your_pubkey, + int me_first +) NONNULL134 WARN_UNUSED API_VIS; + +/** + * @brief Sign a message from a STROBE context. + * + * @param [out] sig The signature. + * @param [in] priv Your private key. + * @param [in] strobe A STROBE context with the message. + */ +void +decaf_448_sign_strobe ( + keccak_strobe_t strobe, + decaf_448_signature_t sig, + const decaf_448_private_key_t priv +) NONNULL3 API_VIS; + +/** + * @brief Sign a message. + * + * @param [out] sig The signature. + * @param [in] priv Your private key. + * @param [in] message The message. + * @param [in] message_len The message's length. + */ +void +decaf_448_sign ( + decaf_448_signature_t sig, + const decaf_448_private_key_t priv, + const unsigned char *message, + size_t message_len +) NONNULL3 API_VIS; + +/** + * @brief Verify a signed message from its STROBE context. + * + * @param [in] sig The signature. + * @param [in] pub The public key. + * @param [in] strobe A STROBE context with the message. + * + * @return DECAF_SUCCESS The signature verified successfully. + * @return DECAF_FAILURE The signature did not verify successfully. + */ +decaf_error_t +decaf_448_verify_strobe ( + keccak_strobe_t strobe, + const decaf_448_signature_t sig, + const decaf_448_public_key_t pub +) NONNULL3 API_VIS WARN_UNUSED; + +/** + * @brief Verify a signed message. + * + * @param [in] sig The signature. + * @param [in] pub The public key. + * @param [in] message The message. + * @param [in] message_len The message's length. + * + * @return DECAF_SUCCESS The signature verified successfully. + * @return DECAF_FAILURE The signature did not verify successfully. + */ +decaf_error_t +decaf_448_verify ( + const decaf_448_signature_t sig, + const decaf_448_public_key_t pub, + const unsigned char *message, + size_t message_len +) NONNULL3 API_VIS WARN_UNUSED; + +#undef API_VIS +#undef WARN_UNUSED +#undef NONNULL1 +#undef NONNULL2 +#undef NONNULL3 +#undef NONNULL134 +#undef NONNULL5 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __DECAF_CRYPTO_448_H__ */ + + diff --git a/src/shake.c b/src/shake.c index ac4a9a4..a5fa91c 100644 --- a/src/shake.c +++ b/src/shake.c @@ -583,7 +583,7 @@ void strobe_transact ( uint32_t len = sponge->params->rate - sponge->params->position; if (len < STROBE_FORGET_BYTES + len_cw) len += sponge->params->rate; - len -= len_cw; + len -= len_cw; /* HACK */ if (cw_flags & STROBE_FLAG_NO_LENGTH) len = 2*STROBE_FORGET_BYTES; diff --git a/test/bench_decaf.cxx b/test/bench_decaf.cxx index e27cee2..a64d9f3 100644 --- a/test/bench_decaf.cxx +++ b/test/bench_decaf.cxx @@ -11,7 +11,8 @@ #include #include -#include +#include +#include #include #include #include @@ -374,13 +375,8 @@ int main(int argc, char **argv) { bool micro = false; if (argc >= 2 && !strcmp(argv[1], "--micro")) micro = true; - - decaf_255_public_key_t p1,p2; - decaf_255_private_key_t s1,s2; + decaf_255_symmetric_key_t r1,r2; - decaf_255_signature_t sig1; - unsigned char ss[32]; - memset(r1,1,sizeof(r1)); memset(r2,2,sizeof(r2)); @@ -421,32 +417,72 @@ int main(int argc, char **argv) { Benches::micro(); } - /* TODO: 255->448 */ - printf("\nMacro-benchmarks:\n"); - for (Benchmark b("Keygen"); b.iter(); ) { - decaf_255_derive_private_key(s1,r1); - } + { + decaf_255_public_key_t p1,p2; + decaf_255_private_key_t s1,s2; + decaf_255_signature_t sig1; + unsigned char ss[32]; + + printf("\nMacro-benchmarks for IsoEd25519:\n"); + for (Benchmark b("Keygen"); b.iter(); ) { + decaf_255_derive_private_key(s1,r1); + } - decaf_255_private_to_public(p1,s1); - decaf_255_derive_private_key(s2,r2); - decaf_255_private_to_public(p2,s2); + decaf_255_private_to_public(p1,s1); + decaf_255_derive_private_key(s2,r2); + decaf_255_private_to_public(p2,s2); - for (Benchmark b("Shared secret"); b.iter(); ) { - decaf_bool_t ret = decaf_255_shared_secret(ss,sizeof(ss),s1,p2,1); - ignore_result(ret); - assert(ret); - } + for (Benchmark b("Shared secret"); b.iter(); ) { + decaf_bool_t ret = decaf_255_shared_secret(ss,sizeof(ss),s1,p2,1); + ignore_result(ret); + assert(ret); + } + + for (Benchmark b("Sign"); b.iter(); ) { + decaf_255_sign(sig1,s1,umessage,lmessage); + } - for (Benchmark b("Sign"); b.iter(); ) { - decaf_255_sign(sig1,s1,umessage,lmessage); + for (Benchmark b("Verify"); b.iter(); ) { + decaf_bool_t ret = decaf_255_verify(sig1,p1,umessage,lmessage); + rng.read(Buffer(umessage,lmessage)); + // umessage[0]++; + // umessage[1]^=umessage[0]; + ignore_result(ret); + } } + + { + decaf_448_public_key_t p1,p2; + decaf_448_private_key_t s1,s2; + decaf_448_signature_t sig1; + unsigned char ss[32]; + + printf("\nMacro-benchmarks for Ed448-Goldilocks:\n"); + for (Benchmark b("Keygen"); b.iter(); ) { + decaf_448_derive_private_key(s1,r1); + } - for (Benchmark b("Verify"); b.iter(); ) { - decaf_bool_t ret = decaf_255_verify(sig1,p1,umessage,lmessage); - rng.read(Buffer(umessage,lmessage)); - // umessage[0]++; - // umessage[1]^=umessage[0]; - ignore_result(ret); + decaf_448_private_to_public(p1,s1); + decaf_448_derive_private_key(s2,r2); + decaf_448_private_to_public(p2,s2); + + for (Benchmark b("Shared secret"); b.iter(); ) { + decaf_bool_t ret = decaf_448_shared_secret(ss,sizeof(ss),s1,p2,1); + ignore_result(ret); + assert(ret); + } + + for (Benchmark b("Sign"); b.iter(); ) { + decaf_448_sign(sig1,s1,umessage,lmessage); + } + + for (Benchmark b("Verify"); b.iter(); ) { + decaf_bool_t ret = decaf_448_verify(sig1,p1,umessage,lmessage); + rng.read(Buffer(umessage,lmessage)); + // umessage[0]++; + // umessage[1]^=umessage[0]; + ignore_result(ret); + } } Benches::macro(); diff --git a/test/test_decaf.cxx b/test/test_decaf.cxx index 1e7a1f5..b163235 100644 --- a/test/test_decaf.cxx +++ b/test/test_decaf.cxx @@ -11,7 +11,8 @@ #include #include -#include +#include +#include #include #include @@ -341,8 +342,7 @@ static void test_crypto() { }; // template -// TODO cross-field -static void test_decaf() { +static void test_decaf_255() { Test test("Sample crypto"); SpongeRng rng(Block("test_decaf")); @@ -376,6 +376,41 @@ static void test_decaf() { } } +/* TODO: don't copy-paste */ +static void test_decaf_448() { + Test test("Sample crypto"); + SpongeRng rng(Block("test_decaf")); + + decaf_448_symmetric_key_t proto1,proto2; + decaf_448_private_key_t s1,s2; + decaf_448_public_key_t p1,p2; + decaf_448_signature_t sig; + unsigned char shared1[1234],shared2[1234]; + const char *message = "Hello, world!"; + + for (int i=0; i::test_elligator(); Tests::test_ec(); Tests::test_crypto(); - test_decaf(); + test_decaf_255(); printf("\n"); printf("Testing %s:\n", Ed448Goldilocks::name()); @@ -392,6 +427,7 @@ int main(int argc, char **argv) { Tests::test_elligator(); Tests::test_ec(); Tests::test_crypto(); + test_decaf_448(); if (passing) printf("Passed all tests.\n");