/* Public domain by Andrew M. Ed25519 reference implementation using Ed25519-donna */ /* Tor specific notes: This file is used by Tor instead of `ed25519.c` as the number of changes/additions is non-trivial. Tor modifications to `ed25519.c`: * 'Tab` -> ' '. * Include `ed25519_donna_tor.h` instead of `ed25519.h`. * The external interface has been reworked to match that provided by Tor's copy of the SUPERCOP `ref10` code. * The secret (aka private) key is now stored/used in expanded form. * The internal math tests from `test-internals.c` have been wrapped in a function and the entire file is included to allow for runtime validation. */ /* define ED25519_SUFFIX to have it appended to the end of each public function */ #if !defined(ED25519_SUFFIX) #define ED25519_SUFFIX #endif #define ED25519_FN3(fn,suffix) fn##suffix #define ED25519_FN2(fn,suffix) ED25519_FN3(fn,suffix) #define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX) #include "ed25519-donna.h" #include "ed25519_donna_tor.h" #include "ed25519-randombytes.h" #include "ed25519-hash.h" typedef unsigned char ed25519_signature[64]; typedef unsigned char ed25519_public_key[32]; typedef unsigned char ed25519_secret_key[32]; static int ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); /* Generates a (extsk[0..31]) and aExt (extsk[32..63]) */ DONNA_INLINE static void ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { ed25519_hash(extsk, sk, 32); extsk[0] &= 248; extsk[31] &= 127; extsk[31] |= 64; } static void ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public_key pk, const unsigned char *m, size_t mlen) { ed25519_hash_context ctx; ed25519_hash_init(&ctx); ed25519_hash_update(&ctx, RS, 32); ed25519_hash_update(&ctx, pk, 32); ed25519_hash_update(&ctx, m, mlen); ed25519_hash_final(&ctx, hram); } static int ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { ge25519 ALIGN(16) R, A; hash_512bits hash; bignum256modm hram, S; unsigned char checkR[32]; if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) return -1; /* hram = H(R,A,m) */ ed25519_hram(hash, RS, pk, m, mlen); expand256_modm(hram, hash, 64); /* S */ expand256_modm(S, RS + 32, 32); /* SB - H(R,A,m)A */ ge25519_double_scalarmult_vartime(&R, &A, hram, S); ge25519_pack(checkR, &R); /* check that R = SB - H(R,A,m)A */ return ed25519_verify(RS, checkR, 32) ? 0 : -1; } #include "ed25519-donna-batchverify.h" /* Fast Curve25519 basepoint scalar multiplication */ void ED25519_FN(curved25519_scalarmult_basepoint) (curved25519_key pk, const curved25519_key e) { curved25519_key ec; bignum256modm s; bignum25519 ALIGN(16) yplusz, zminusy; ge25519 ALIGN(16) p; size_t i; /* clamp */ for (i = 0; i < 32; i++) ec[i] = e[i]; ec[0] &= 248; ec[31] &= 127; ec[31] |= 64; expand_raw256_modm(s, ec); /* scalar * basepoint */ ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s); /* u = (y + z) / (z - y) */ curve25519_add(yplusz, p.y, p.z); curve25519_sub(zminusy, p.z, p.y); curve25519_recip(zminusy, zminusy); curve25519_mul(yplusz, yplusz, zminusy); curve25519_contract(pk, yplusz); } /* Tor has a specific idea of how an Ed25519 implementaion should behave. Implement such a beast using the ed25519-donna primitives/internals. * Private key generation using Tor's CSPRNG. * Routines that deal with the private key now use the expanded form. */ int ed25519_donna_seckey(unsigned char *sk) { ed25519_secret_key seed; if (crypto_strongest_rand(seed, 32)) return -1; ed25519_extsk(sk, seed); memwipe(seed, 0, sizeof(seed)); return 0; } int ed25519_donna_seckey_expand(unsigned char *sk, const unsigned char *skseed) { ed25519_extsk(sk, skseed); return 0; } int ed25519_donna_pubkey(unsigned char *pk, const unsigned char *sk) { bignum256modm a; ge25519 ALIGN(16) A; /* A = aB */ expand256_modm(a, sk, 32); ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); ge25519_pack(pk, &A); return 0; } int ed25519_donna_keygen(unsigned char *pk, unsigned char *sk) { int ok; ok = ed25519_donna_seckey(sk); ed25519_donna_pubkey(pk, sk); return ok; } int ed25519_donna_open(const unsigned char *signature, const unsigned char *m, size_t mlen, const unsigned char *pk) { /* Wrap the ed25519-donna routine, since it is also used by the batch * verification code. */ return ED25519_FN(ed25519_sign_open)(m, mlen, pk, signature); } int ed25519_donna_sign(unsigned char *sig, const unsigned char *m, size_t mlen, const unsigned char *sk, const unsigned char *pk) { ed25519_hash_context ctx; bignum256modm r, S, a; ge25519 ALIGN(16) R; hash_512bits hashr, hram; /* This is equivalent to the removed `ED25519_FN(ed25519_sign)` routine, * except that the key expansion step is omitted as sk already is in expanded * form. */ /* r = H(aExt[32..64], m) */ ed25519_hash_init(&ctx); ed25519_hash_update(&ctx, sk + 32, 32); ed25519_hash_update(&ctx, m, mlen); ed25519_hash_final(&ctx, hashr); expand256_modm(r, hashr, 64); /* R = rB */ ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); ge25519_pack(sig, &R); /* S = H(R,A,m).. */ ed25519_hram(hram, sig, pk, m, mlen); expand256_modm(S, hram, 64); /* S = H(R,A,m)a */ expand256_modm(a, sk, 32); mul256_modm(S, S, a); /* S = (r + H(R,A,m)a) */ add256_modm(S, S, r); /* S = (r + H(R,A,m)a) mod L */ contract256_modm(sig + 32, S); return 0; } #include "test-internals.c"