|
@@ -0,0 +1,240 @@
|
|
|
+
|
|
|
+ Public domain by Andrew M. <liquidsun@gmail.com>
|
|
|
+
|
|
|
+ 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.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#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;
|
|
|
+
|
|
|
+
|
|
|
+ ed25519_hram(hash, RS, pk, m, mlen);
|
|
|
+ expand256_modm(hram, hash, 64);
|
|
|
+
|
|
|
+
|
|
|
+ expand256_modm(S, RS + 32, 32);
|
|
|
+
|
|
|
+
|
|
|
+ ge25519_double_scalarmult_vartime(&R, &A, hram, S);
|
|
|
+ ge25519_pack(checkR, &R);
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+
|
|
|
+ for (i = 0; i < 32; i++) ec[i] = e[i];
|
|
|
+ ec[0] &= 248;
|
|
|
+ ec[31] &= 127;
|
|
|
+ ec[31] |= 64;
|
|
|
+
|
|
|
+ expand_raw256_modm(s, ec);
|
|
|
+
|
|
|
+
|
|
|
+ ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s);
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+
|
|
|
+ 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)
|
|
|
+{
|
|
|
+
|
|
|
+ * 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;
|
|
|
+
|
|
|
+
|
|
|
+ * except that the key expansion step is omitted as sk already is in expanded
|
|
|
+ * form.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+
|
|
|
+ ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r);
|
|
|
+ ge25519_pack(sig, &R);
|
|
|
+
|
|
|
+
|
|
|
+ ed25519_hram(hram, sig, pk, m, mlen);
|
|
|
+ expand256_modm(S, hram, 64);
|
|
|
+
|
|
|
+
|
|
|
+ expand256_modm(a, sk, 32);
|
|
|
+ mul256_modm(S, S, a);
|
|
|
+
|
|
|
+
|
|
|
+ add256_modm(S, S, r);
|
|
|
+
|
|
|
+
|
|
|
+ contract256_modm(sig + 32, S);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#include "test-internals.c"
|
|
|
+
|