| @@ -166,7 +166,7 @@ endef | |||||
| define define_curve | define define_curve | ||||
| LIBCOMPONENTS += $$(BUILD_OBJ)/$(1)/decaf.o $$(BUILD_OBJ)/$(1)/elligator.o $$(BUILD_OBJ)/$(1)/scalar.o \ | LIBCOMPONENTS += $$(BUILD_OBJ)/$(1)/decaf.o $$(BUILD_OBJ)/$(1)/elligator.o $$(BUILD_OBJ)/$(1)/scalar.o \ | ||||
| $$(BUILD_OBJ)/$(1)/crypto.o $$(BUILD_OBJ)/$(1)/decaf_tables.o | |||||
| $$(BUILD_OBJ)/$(1)/crypto.o $$(BUILD_OBJ)/$(1)/eddsa.o $$(BUILD_OBJ)/$(1)/decaf_tables.o | |||||
| PER_OBJ_DIRS += $$(BUILD_OBJ)/$(1) | PER_OBJ_DIRS += $$(BUILD_OBJ)/$(1) | ||||
| GLOBAL_HEADERS_OF_$(1) = $(BUILD_INC)/decaf/decaf_$(3).h $(BUILD_INC)/decaf/decaf_$(3).hxx \ | GLOBAL_HEADERS_OF_$(1) = $(BUILD_INC)/decaf/decaf_$(3).h $(BUILD_INC)/decaf/decaf_$(3).hxx \ | ||||
| $(BUILD_INC)/decaf/crypto_$(3).h $(BUILD_INC)/decaf/crypto_$(3).hxx | $(BUILD_INC)/decaf/crypto_$(3).h $(BUILD_INC)/decaf/crypto_$(3).hxx | ||||
| @@ -91,7 +91,6 @@ gf_invert(gf y, const gf x) { | |||||
| gf_copy(y, t2); | gf_copy(y, t2); | ||||
| } | } | ||||
| #if COFACTOR==8 | |||||
| /** Return high bit of x = low bit of 2x mod p */ | /** Return high bit of x = low bit of 2x mod p */ | ||||
| static mask_t gf_lobit(const gf x) { | static mask_t gf_lobit(const gf x) { | ||||
| gf y; | gf y; | ||||
| @@ -99,7 +98,6 @@ static mask_t gf_lobit(const gf x) { | |||||
| gf_strong_reduce(y); | gf_strong_reduce(y); | ||||
| return -(y->limb[0]&1); | return -(y->limb[0]&1); | ||||
| } | } | ||||
| #endif | |||||
| /** identity = (0,1) */ | /** identity = (0,1) */ | ||||
| const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | ||||
| @@ -1046,6 +1044,60 @@ decaf_error_t API_NS(direct_scalarmul) ( | |||||
| return succ; | return succ; | ||||
| } | } | ||||
| void API_NS(point_encode_like_eddsa) ( | |||||
| uint8_t enc[$(C_NS)_EDDSA_PUBLIC_BYTES], | |||||
| const point_t p | |||||
| ) { | |||||
| /* The point is now on the twisted curve. Move it to untwisted. */ | |||||
| gf x, y, z, t; | |||||
| #if IMAGINE_TWIST | |||||
| { | |||||
| /* TODO: make sure cofactor is clear */ | |||||
| point_t q; | |||||
| API_NS(point_double)(q,p); | |||||
| gf_div_qnr(x, q->x); | |||||
| gf_copy(y, q->y); | |||||
| gf_copy(z, q->z); | |||||
| API_NS(point_destroy(q)); | |||||
| } | |||||
| #else | |||||
| { | |||||
| /* 4-isogeny: 2xy/(y^+x^2), (y^2-x^2)/(2z^2-y^2+x^2) */ | |||||
| gf u; | |||||
| gf_sqr ( x, p->x ); | |||||
| gf_sqr ( t, p->y ); | |||||
| gf_add( u, x, t ); // x^2 + y^2 | |||||
| gf_add( z, p->y, p->x ); | |||||
| gf_sqr ( y, z); // (x+y)^2 | |||||
| gf_sub ( y, y, u ); // 2xy | |||||
| gf_sub ( z, t, x ); // y^2 - x^2 | |||||
| gf_sqr ( x, p->z ); // z^2 | |||||
| gf_add ( t, x, x); // 2z^2 | |||||
| gf_sub ( t, t, z); // 2z^2 - y^2 + x^2 | |||||
| gf_mul ( x, t, y ); // (2z^2 - y^2 + x^2)(2xy) | |||||
| gf_mul ( y, z, u ); // (y^2 - x^2)(x^2 + y^2) | |||||
| gf_mul ( z, u, t ); // (x^2 + y^2)(2z^2 - y^2 + x^2) | |||||
| decaf_bzero(t,sizeof(u)); | |||||
| } | |||||
| #endif | |||||
| /* Affinize */ | |||||
| gf_invert(z,z); | |||||
| gf_mul(t,x,z); | |||||
| gf_mul(x,y,z); | |||||
| /* Encode */ | |||||
| enc[$(C_NS)_EDDSA_PRIVATE_BYTES-1] = 0; | |||||
| gf_serialize(enc, x, 1); | |||||
| enc[$(C_NS)_EDDSA_PRIVATE_BYTES-1] |= 0x80 &~ gf_lobit(t); | |||||
| decaf_bzero(x,sizeof(x)); | |||||
| decaf_bzero(y,sizeof(y)); | |||||
| decaf_bzero(z,sizeof(z)); | |||||
| decaf_bzero(t,sizeof(t)); | |||||
| } | |||||
| decaf_error_t API_NS(x_direct_scalarmul) ( | decaf_error_t API_NS(x_direct_scalarmul) ( | ||||
| uint8_t out[X_PUBLIC_BYTES], | uint8_t out[X_PUBLIC_BYTES], | ||||
| const uint8_t base[X_PUBLIC_BYTES], | const uint8_t base[X_PUBLIC_BYTES], | ||||
| @@ -37,6 +37,16 @@ typedef struct gf_$(gf_shortname)_s { | |||||
| /** Number of bits in the "which" field of an elligator inverse */ | /** Number of bits in the "which" field of an elligator inverse */ | ||||
| #define $(C_NS)_INVERT_ELLIGATOR_WHICH_BITS $(ceil_log2(cofactor) + 7 + elligator_onto - ((gf_bits-2) % 8)) | #define $(C_NS)_INVERT_ELLIGATOR_WHICH_BITS $(ceil_log2(cofactor) + 7 + elligator_onto - ((gf_bits-2) % 8)) | ||||
| /* TODO: move to a different file? */ | |||||
| /** Number of bytes in an EdDSA public key. */ | |||||
| #define $(C_NS)_EDDSA_PUBLIC_BYTES $((gf_bits)/8 + 1) /* TODO: change name? */ | |||||
| /** Number of bytes in an EdDSA private key. */ | |||||
| #define $(C_NS)_EDDSA_PRIVATE_BYTES $(C_NS)_EDDSA_PUBLIC_BYTES /* TODO: change name? */ | |||||
| /** Number of bytes in an EdDSA private key. */ | |||||
| #define $(C_NS)_EDDSA_SIGNATURE_BYTES ($(C_NS)_PUBLIC_BYTES + $(C_NS)_PRIVATE_BYTES) /* TODO: change name? */ | |||||
| /** Number of bytes in an x$(gf_shortname) public key */ | /** Number of bytes in an x$(gf_shortname) public key */ | ||||
| #define X$(gf_shortname)_PUBLIC_BYTES $((gf_bits-1)/8 + 1) | #define X$(gf_shortname)_PUBLIC_BYTES $((gf_bits-1)/8 + 1) | ||||
| @@ -404,6 +414,29 @@ void $(c_ns)_x_base_scalarmul ( | |||||
| const uint8_t scalar[X$(gf_shortname)_PRIVATE_BYTES] | const uint8_t scalar[X$(gf_shortname)_PRIVATE_BYTES] | ||||
| ) API_VIS NONNULL NOINLINE; | ) API_VIS NONNULL NOINLINE; | ||||
| /** | |||||
| * @brief EdDSA key generation. This function uses a different (non-Decaf) | |||||
| * encoding. | |||||
| * | |||||
| * @param [out] pubkey The public key. | |||||
| * @param [in] privkey The private key. | |||||
| */ | |||||
| void $(c_ns)_eddsa_derive_public_key ( | |||||
| uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | |||||
| const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES] | |||||
| ) API_VIS NONNULL NOINLINE; | |||||
| /** | |||||
| * @brief EdDSA point encoding. | |||||
| * | |||||
| * @param [out] enc The encoded point. | |||||
| * @param [in] p The point. | |||||
| */ | |||||
| void $(c_ns)_point_encode_like_eddsa ( | |||||
| uint8_t enc[$(C_NS)_EDDSA_PUBLIC_BYTES], | |||||
| const $(c_ns)_point_t p | |||||
| ) API_VIS NONNULL NOINLINE; | |||||
| /** | /** | ||||
| * @brief Precompute a table for fast scalar multiplication. | * @brief Precompute a table for fast scalar multiplication. | ||||
| * Some implementations do not include precomputed points; for | * Some implementations do not include precomputed points; for | ||||
| @@ -649,6 +649,25 @@ public: | |||||
| } | } | ||||
| }; | }; | ||||
| struct EdDSA { | |||||
| public: | |||||
| /** The size of a public key */ | |||||
| static const size_t PUBLIC_BYTES = $(C_NS)_EDDSA_PUBLIC_BYTES; | |||||
| /** The size of a private key */ | |||||
| static const size_t PRIVATE_BYTES = $(C_NS)_EDDSA_PRIVATE_BYTES; | |||||
| /* TODO: make into a nice class. Change name. Possibly move to another include file. */ | |||||
| static inline SecureBuffer generate_key ( | |||||
| const FixedBlock<PRIVATE_BYTES> &secret | |||||
| ) { | |||||
| SecureBuffer out(PUBLIC_BYTES); | |||||
| $(c_ns)_eddsa_derive_public_key(out.data(), secret.data()); | |||||
| return out; | |||||
| } | |||||
| }; | |||||
| }; /* struct $(cxx_ns) */ | }; /* struct $(cxx_ns) */ | ||||
| /** @cond internal */ | /** @cond internal */ | ||||
| @@ -56,6 +56,7 @@ template<typename Group> struct Tests { | |||||
| typedef typename Group::Scalar Scalar; | typedef typename Group::Scalar Scalar; | ||||
| typedef typename Group::Point Point; | typedef typename Group::Point Point; | ||||
| typedef typename Group::DhLadder DhLadder; | typedef typename Group::DhLadder DhLadder; | ||||
| typedef typename Group::EdDSA EdDSA; | |||||
| typedef typename Group::Precomputed Precomputed; | typedef typename Group::Precomputed Precomputed; | ||||
| static void print(const char *name, const Scalar &x) { | static void print(const char *name, const Scalar &x) { | ||||
| @@ -455,6 +456,8 @@ static void test_cfrg_crypto() { | |||||
| } | } | ||||
| } | } | ||||
| static const Block eddsa_sk, eddsa_pk; | |||||
| static void test_cfrg_vectors() { | static void test_cfrg_vectors() { | ||||
| Test test("CFRG test vectors"); | Test test("CFRG test vectors"); | ||||
| SecureBuffer k = DhLadder::base_point(); | SecureBuffer k = DhLadder::base_point(); | ||||
| @@ -462,6 +465,24 @@ static void test_cfrg_vectors() { | |||||
| int the_ntests = (NTESTS < 1000000) ? 1000 : 1000000; | int the_ntests = (NTESTS < 1000000) ? 1000 : 1000000; | ||||
| /* EdDSA */ | |||||
| if (eddsa_sk.size()) { | |||||
| SecureBuffer eddsa_pk2 = EdDSA::generate_key(eddsa_sk); | |||||
| if (!memeq(SecureBuffer(eddsa_pk), eddsa_pk2)) { | |||||
| test.fail(); | |||||
| printf(" EdDSA vectors disagree."); | |||||
| printf("\n Correct: "); | |||||
| for (unsigned i=0; i<eddsa_pk.size(); i++) printf("%02x", eddsa_pk[i]); | |||||
| printf("\n Incorrect: "); | |||||
| for (unsigned i=0; i<eddsa_pk.size(); i++) printf("%02x", eddsa_pk2[i]); | |||||
| printf("\n"); | |||||
| } | |||||
| } | |||||
| /* X25519/X448 */ | |||||
| for (int i=0; i<the_ntests && test.passing_now; i++) { | for (int i=0; i<the_ntests && test.passing_now; i++) { | ||||
| SecureBuffer n = DhLadder::shared_secret(u,k); | SecureBuffer n = DhLadder::shared_secret(u,k); | ||||
| u = k; k = n; | u = k; k = n; | ||||
| @@ -500,6 +521,7 @@ static void run() { | |||||
| }; /* template<GroupId GROUP> struct Tests */ | }; /* template<GroupId GROUP> struct Tests */ | ||||
| /* X25519, X448 test vectors */ | |||||
| template<> const uint8_t Tests<IsoEd25519>::rfc7748_1[32] = { | template<> const uint8_t Tests<IsoEd25519>::rfc7748_1[32] = { | ||||
| 0x42,0x2c,0x8e,0x7a,0x62,0x27,0xd7,0xbc, | 0x42,0x2c,0x8e,0x7a,0x62,0x27,0xd7,0xbc, | ||||
| 0xa1,0x35,0x0b,0x3e,0x2b,0xb7,0x27,0x9f, | 0xa1,0x35,0x0b,0x3e,0x2b,0xb7,0x27,0x9f, | ||||
| @@ -576,8 +598,36 @@ const uint8_t elli_patho_448[56] = { | |||||
| template<> const Block Tests<Ed448Goldilocks>::elli_patho(elli_patho_448,56); | template<> const Block Tests<Ed448Goldilocks>::elli_patho(elli_patho_448,56); | ||||
| template<> const Block Tests<IsoEd25519>::elli_patho(NULL,0); | template<> const Block Tests<IsoEd25519>::elli_patho(NULL,0); | ||||
| /* EdDSA test vectors */ | |||||
| const uint8_t ed448_eddsa_sk[57] = { | |||||
| 0x6c,0x82,0xa5,0x62,0xcb,0x80,0x8d,0x10, | |||||
| 0xd6,0x32,0xbe,0x89,0xc8,0x51,0x3e,0xbf, | |||||
| 0x6c,0x92,0x9f,0x34,0xdd,0xfa,0x8c,0x9f, | |||||
| 0x63,0xc9,0x96,0x0e,0xf6,0xe3,0x48,0xa3, | |||||
| 0x52,0x8c,0x8a,0x3f,0xcc,0x2f,0x04,0x4e, | |||||
| 0x39,0xa3,0xfc,0x5b,0x94,0x49,0x2f,0x8f, | |||||
| 0x03,0x2e,0x75,0x49,0xa2,0x00,0x98,0xf9, | |||||
| 0x5b | |||||
| }; | |||||
| const uint8_t ed448_eddsa_pk[57] = { | |||||
| 0x5f,0xd7,0x44,0x9b,0x59,0xb4,0x61,0xfd, | |||||
| 0x2c,0xe7,0x87,0xec,0x61,0x6a,0xd4,0x6a, | |||||
| 0x1d,0xa1,0x34,0x24,0x85,0xa7,0x0e,0x1f, | |||||
| 0x8a,0x0e,0xa7,0x5d,0x80,0xe9,0x67,0x78, | |||||
| 0xed,0xf1,0x24,0x76,0x9b,0x46,0xc7,0x06, | |||||
| 0x1b,0xd6,0x78,0x3d,0xf1,0xe5,0x0f,0x6c, | |||||
| 0xd1,0xfa,0x1a,0xbe,0xaf,0xe8,0x25,0x61, | |||||
| 0x80 | |||||
| }; | |||||
| template<> const Block Tests<Ed448Goldilocks>::eddsa_sk(ed448_eddsa_sk,57); | |||||
| template<> const Block Tests<Ed448Goldilocks>::eddsa_pk(ed448_eddsa_pk,57); | |||||
| template<> const Block Tests<IsoEd25519>::eddsa_sk(NULL,0); /* TODO */ | |||||
| template<> const Block Tests<IsoEd25519>::eddsa_pk(NULL,0); /* TODO */ | |||||
| int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||
| (void) argc; (void) argv; | (void) argc; (void) argv; | ||||
| run_for_all_curves<Tests>(); | run_for_all_curves<Tests>(); | ||||
| if (passing) printf("Passed all tests.\n"); | if (passing) printf("Passed all tests.\n"); | ||||
| return passing ? 0 : 1; | return passing ? 0 : 1; | ||||