Integrate ed25519-donna (Not yet used).

Integrate ed25519-donna into the build process, and provide an
interface that matches the `ref10` code.  Apart from the blinding and
Curve25519 key conversion, this functions as a drop-in replacement for
ref10 (verified by modifying crypto_ed25519.c).

Tests pass, and the benchmarks claim it is quite a bit faster, however
actually using the code requires additional integration work.
This commit is contained in:
Yawning Angel 2015-07-06 09:40:28 +00:00
parent 7b10741be4
commit 0f3eeca9b8
9 changed files with 388 additions and 10 deletions

2
.gitignore vendored
View File

@ -144,6 +144,8 @@ cscope.*
# /src/ext/
/src/ext/ed25519/ref10/libed25519_ref10.a
/src/ext/ed25519/ref10/libed25519_ref10.lib
/src/ext/ed25519/donna/libed25519_donna.a
/src/ext/ed25519/donna/libed25519_donna.lib
# /src/or/
/src/or/Makefile

View File

@ -43,6 +43,7 @@ endif
endif
LIBDONNA += $(LIBED25519_REF10)
LIBDONNA += $(LIBED25519_DONNA)
if THREADS_PTHREADS
threads_impl_source=src/common/compat_pthreads.c

View File

@ -0,0 +1,32 @@
We've made the following changes to the stock ed25519-donna from
as of 8757bd4cd209cb032853ece0ce413f122eef212c.
* Tor uses copies of `ed25519-donna.h` and `ed25519.c`, named
`ed25519_donna_tor.h` and `ed25591_tor.c`.
The main functional differences between the standard ed25519-donna
and the Tor specific version are:
* 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.
* `ED25519_FN(ed25519_randombytes_unsafe)` is now static.
* `ed25519-randombytes-custom.h` has the appropriate code to call
Tor's `crypto_rand()` routine, instead of directly using OpenSSL's
CSPRNG.
* OSX pollutes the global namespace with an `ALIGN` macro, which is
undef-ed right before the donna `ALIGN` macro is defined.
* If building with Clang's AddressSanitizer, disable inline assembly
since the compilation will fail in `ge25519_scalarmult_base_choose_niels`
on x86_64 targets due to running out of registers.

View File

@ -20,6 +20,8 @@
#include <sys/param.h>
#define DONNA_INLINE inline __attribute__((always_inline))
#define DONNA_NOINLINE __attribute__((noinline))
/* Tor: OSX pollutes the global namespace with an ALIGN macro. */
#undef ALIGN
#define ALIGN(x) __attribute__((aligned(x)))
#define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b)))
#define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b)))
@ -129,6 +131,19 @@ static inline void U64TO8_LE(unsigned char *p, const uint64_t v) {
}
#endif
/* Tor: Detect and disable inline assembly when clang's AddressSanitizer
* is present, due to compilation failing because it runs out of registers.
*
* The alternative is to annotate `ge25519_scalarmult_base_choose_niels`
* and selectively disable AddressSanitizer insturmentation, however doing
* things this way results in a "more sanitized" binary.
*/
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define ED25519_NO_INLINE_ASM
#endif
#endif
#include <stdlib.h>
#include <string.h>

View File

@ -6,3 +6,12 @@
ed25519_randombytes_unsafe is used by the batch verification function
to create random scalars
*/
/* Tor: Instead of calling OpenSSL's CSPRNG directly, call the wrapper. */
#include "crypto.h"
static void
ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len)
{
crypto_rand(p, len);
}

View File

@ -0,0 +1,24 @@
/* Added for Tor. */
#ifndef SRC_EXT_ED25519_DONNA_H_INCLUDED_
#define SRC_EXT_ED25519_DONNA_H_INCLUDED_
#include <torint.h>
typedef unsigned char curved25519_key[32];
int ed25519_sign_open_batch_donna(const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid);
void curved25519_scalarmult_basepoint_donna(curved25519_key pk, const curved25519_key e);
/* Tor specific interface to match the `ref10` glue code. */
int ed25519_donna_selftest(void);
int ed25519_donna_seckey(unsigned char *sk);
int ed25519_donna_seckey_expand(unsigned char *sk, const unsigned char *sk_seed);
int ed25519_donna_pubkey(unsigned char *pk, const unsigned char *sk);
int ed25519_donna_keygen(unsigned char *pk, unsigned char *sk);
int ed25519_donna_open(const unsigned char *signature, const unsigned char *m,
size_t mlen, const unsigned char *pk);
int ed25519_donna_sign(unsigned char *sig, const unsigned char *m, size_t mlen,
const unsigned char *sk, const unsigned char *pk);
#endif

View File

@ -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.
*/
/* 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"

View File

@ -1,19 +1,22 @@
#include <stdio.h>
#include "ed25519-donna.h"
/* Tor: Removed, file is inclued in ed25519.c instead. */
/* #include <stdio.h> */
/* #include "ed25519-donna.h" */
static int
test_adds() {
test_adds(void) {
#if defined(HAVE_UINT128) && !defined(ED25519_SSE2)
/* largest result for each limb from a mult or square: all elements except r1 reduced, r1 overflowed as far as possible */
static const bignum25519 max_bignum = {
0x7ffffffffffff,0x8000000001230,0x7ffffffffffff,0x7ffffffffffff,0x7ffffffffffff
};
#if 0
/* what max_bignum should fully reduce to */
static const unsigned char max_bignum_raw[32] = {
0x12,0x00,0x00,0x00,0x00,0x00,0x88,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
#endif
/* (max_bignum + max_bignum)^2 */
static const unsigned char max_bignum2_squared_raw[32] = {
@ -46,9 +49,9 @@ test_adds() {
};
#endif
unsigned char result[32];
static const bignum25519 ALIGN(16) zero = {0};
bignum25519 ALIGN(16) a, b, c;
size_t i;
/* static const bignum25519 ALIGN(16) zero = {0}; */
bignum25519 ALIGN(16) a, b /* , c */;
/* size_t i; */
/* a = (max_bignum + max_bignum) */
curve25519_add(a, max_bignum, max_bignum);
@ -80,7 +83,7 @@ test_adds() {
}
static int
test_subs() {
test_subs(void) {
#if defined(HAVE_UINT128) && !defined(ED25519_SSE2)
/* largest result for each limb from a mult or square: all elements except r1 reduced, r1 overflowed as far as possible */
static const bignum25519 max_bignum = {
@ -119,8 +122,8 @@ test_subs() {
#endif
unsigned char result[32];
static const bignum25519 ALIGN(16) zero = {0};
bignum25519 ALIGN(16) a, b, c;
size_t i;
bignum25519 ALIGN(16) a, b /* , c */;
/* size_t i; */
/* a = max_bignum - 0, which expands to 2p + max_bignum - 0 */
curve25519_sub(a, max_bignum, zero);
@ -158,7 +161,8 @@ test_subs() {
return 0;
}
/* Tor: Removed, tests are invoked as a function instead. */
#if 0
int
main() {
int ret = 0;
@ -172,5 +176,15 @@ main() {
if (!ret) printf("success\n");
return ret;
}
#endif
/* Tor: Added for initialization self-testing. */
int
ed25519_donna_selftest(void)
{
int ret = 0;
ret |= test_adds();
ret |= test_subs();
return (ret == 0) ? 0 : -1;
}

View File

@ -93,3 +93,44 @@ noinst_HEADERS += $(ED25519_REF10_HDRS)
LIBED25519_REF10=src/ext/ed25519/ref10/libed25519_ref10.a
noinst_LIBRARIES += $(LIBED25519_REF10)
src_ext_ed25519_donna_libed25519_donna_a_CFLAGS= \
-DED25519_CUSTOMRANDOM \
-DED25519_SUFFIX=_donna
src_ext_ed25519_donna_libed25519_donna_a_SOURCES= \
src/ext/ed25519/donna/ed25519_tor.c
ED25519_DONNA_HDRS = \
src/ext/ed25519/donna/curve25519-donna-32bit.h \
src/ext/ed25519/donna/curve25519-donna-64bit.h \
src/ext/ed25519/donna/curve25519-donna-helpers.h \
src/ext/ed25519/donna/curve25519-donna-sse2.h \
src/ext/ed25519/donna/ed25519-donna-32bit-sse2.h \
src/ext/ed25519/donna/ed25519-donna-32bit-tables.h \
src/ext/ed25519/donna/ed25519-donna-64bit-sse2.h \
src/ext/ed25519/donna/ed25519-donna-64bit-tables.h \
src/ext/ed25519/donna/ed25519-donna-64bit-x86-32bit.h \
src/ext/ed25519/donna/ed25519-donna-64bit-x86.h \
src/ext/ed25519/donna/ed25519-donna-basepoint-table.h \
src/ext/ed25519/donna/ed25519-donna-batchverify.h \
src/ext/ed25519/donna/ed25519-donna.h \
src/ext/ed25519/donna/ed25519-donna-impl-base.h \
src/ext/ed25519/donna/ed25519-donna-impl-sse2.h \
src/ext/ed25519/donna/ed25519-donna-portable.h \
src/ext/ed25519/donna/ed25519-donna-portable-identify.h \
src/ext/ed25519/donna/ed25519_donna_tor.h \
src/ext/ed25519/donna/ed25519.h \
src/ext/ed25519/donna/ed25519-hash-custom.h \
src/ext/ed25519/donna/ed25519-hash.h \
src/ext/ed25519/donna/ed25519-randombytes-custom.h \
src/ext/ed25519/donna/ed25519-randombytes.h \
src/ext/ed25519/donna/modm-donna-32bit.h \
src/ext/ed25519/donna/modm-donna-64bit.h \
src/ext/ed25519/donna/regression.h \
src/ext/ed25519/donna/test-ticks.h
noinst_HEADERS += $(ED25519_DONNA_HDRS)
LIBED25519_DONNA=src/ext/ed25519/donna/libed25519_donna.a
noinst_LIBRARIES += $(LIBED25519_DONNA)