ed25519 is an Elliptic Curve Digital Signature Algortithm, developed by Dan Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, and Bo-Yin Yang.
This project provides performant, portable 32-bit & 64-bit implementations. All implementations are of course constant time in regard to secret data.
Batch verfication time (in parentheses) is the average time per 1 verification in a batch of 64 signatures. Counts are in thousands of cycles
Implementation | Sign | gcc | icc | clang | Verify | gcc | icc | clang |
---|---|---|---|---|---|---|---|---|
ed25519-donna 32bit | 603k | 373k | 451k | 1755k (755k) | 1118k (488k) | 1352k (566k) | ||
ed25519-donna 64bit | 132k | 129k | 140k | 374k (160k) | 386k (170k) | 408k (167k) | ||
ed25519-donna-sse2 32bit | 179k | 155k | 184k | 395k (204k) | 378k (197k) | 490k (234k) | ||
ed25519-donna-sse2 64bit | 122k | 114k | 128k | 372k (172k) | 352k (173k) | 412k (195k) |
SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops!
No configuration is needed if you are compiling against OpenSSL.
If you are not compiling aginst OpenSSL, you will need a hash function.
To use a simple/slow implementation of SHA-512, use -DED25519_REFHASH
when compiling ed25519.c. This should never be used except to verify the code works when OpenSSL is not available.
To use a custom hash function, use -DED25519_CUSTOMHASH
when compiling ed25519.c and put your custom hash implementation in ed25519-hash-custom.h. The hash must have a 512bit digest and implement
struct ed25519_hash_context;
void ed25519_hash_init(ed25519_hash_context *ctx);
void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen);
void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash);
void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
gcc ed25519.c -m32 -O3 -c
gcc ed25519.c -m64 -O3 -c
gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2
gcc ed25519.c -m64 -O3 -c -DED25519_SSE2
clang and icc are also supported
To use the code, link against ed25519.o -mbits
and:
#include "ed25519.h"
Add -lssl -lcrypto
when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error).
To generate a private key, simply generate 32 bytes from a secure cryptographic source:
ed25519_secret_key sk;
randombytes(sk, sizeof(ed25519_secret_key));
To generate a public key:
ed25519_public_key pk;
ed25519_publickey(sk, pk);
To sign a message:
ed25519_signature sig;
ed25519_sign(message, message_len, sk, pk, signature);
To verify a signature:
int valid = ed25519_sign_open(message, message_len, pk, signature) == 0;
To batch verify signatures:
const unsigned char *mp[num] = {message1, message2..}
size_t ml[num] = {message_len1, message_len2..}
const unsigned char *pkp[num] = {pk1, pk2..}
const unsigned char *sigp[num] = {signature1, signature2..}
int valid[num]
/* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */
int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0;
Note: Batch verification uses ed25519_randombytes_unsafe
, implemented in
ed25519-randombytes.h
, to generate random scalars for the verification code.
Currently this is implemented with a static RNG state that is initialized to the
same value on each run to test that the implementation is working. I don't have a
clean/portable method of implementing a thread-safe PRNG so if you use batch
verification seriously you will need to make sure the RNG is initialized with random data
or use a separate source of randomness such as /dev/urandom.
Unlike the SUPERCOP version, signatures are not appended to messages, and there is no need for padding in front of messages. Additionally, the secret key does not contain a copy of the public key, so it is 32 bytes instead of 64 bytes, and the public key must be provided to the signing function.
Curve25519 public keys can be generated thanks to Adam Langley leveraging Ed25519's precomputed basepoint scalar multiplication.
curved25519_key sk, pk;
randombytes(sk, sizeof(curved25519_key));
curved25519_scalarmult_basepoint(pk, sk);
Note the name is curved25519, a combination of curve and ed25519, to prevent name clashes. Performance is slightly faster than short message ed25519 signing due to both using the same code for the scalar multiply.
Testing/fuzzing against reference implemenations is now available. See fuzz/README.