From 1795e9e14f62b0f88e6218b9b86d78341886e889 Mon Sep 17 00:00:00 2001 From: Loup Vaillant Date: Sat, 30 Dec 2017 20:24:25 +0100 Subject: [PATCH] Speed benchmark for libsodium --- README.md | 3 + makefile | 7 ++ tests/speed-sodium.c | 217 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 tests/speed-sodium.c diff --git a/README.md b/README.md index 8c59870..24c5609 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,9 @@ not sure, you can always switch later. Note: the speed benchmark currently requires the POSIX `clock_gettime()` function. +There's a similar benchmark for libsodium: + + $ make speed-sodium Customisation ------------- diff --git a/makefile b/makefile index 0c01f00..c498a11 100644 --- a/makefile +++ b/makefile @@ -63,6 +63,9 @@ test: test.out speed: speed.out ./speed.out +speed-sodium: speed-sodium.out + ./speed-sodium.out + # Monocypher libraries lib/libmonocypher.a: lib/monocypher.o ar cr $@ $^ @@ -89,6 +92,10 @@ test.out : lib/test.o lib/monocypher.o lib/sha512.o lib/utils.o speed.out: lib/speed.o lib/monocypher.o lib/sha512.o lib/utils.o test.out speed.out: $(CC) $(CFLAGS) -I src -I src/optional -o $@ $^ +speed-sodium.out: tests/speed-sodium.c + $(CC) $(CFLAGS) -I src -I src/optional -o $@ $^ \ + $$(pkg-config --cflags libsodium) \ + $$(pkg-config --libs libsodium) tests/vectors.h: @echo "" diff --git a/tests/speed-sodium.c b/tests/speed-sodium.c new file mode 100644 index 0000000..4fa234e --- /dev/null +++ b/tests/speed-sodium.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include "sodium.h" + +// Copied from utils.h +#include +#include +typedef int8_t i8; +typedef uint8_t u8; +typedef uint32_t u32; +typedef int32_t i32; +typedef int64_t i64; +typedef uint64_t u64; +#define FOR(i, start, end) for (size_t (i) = (start); (i) < (end); (i)++) +#define RANDOM_INPUT(name, size) u8 name[size]; p_random(name, size) +// end of copy from utils.h + +typedef struct timespec timespec; + +// TODO: provide a user defined buffer size +#define KILOBYTE 1024 +#define MEGABYTE (1024 * KILOBYTE) +#define SIZE (50 * MEGABYTE) +#define MULT (SIZE / MEGABYTE) + +timespec diff(timespec start, timespec end) +{ + timespec duration; + duration.tv_sec = end.tv_sec - start.tv_sec; + duration.tv_nsec = end.tv_nsec - start.tv_nsec; + if (duration.tv_nsec < 0) { + duration.tv_nsec += 1000000000; + duration.tv_sec -= 1; + } + return duration; +} + +timespec min(timespec a, timespec b) +{ + if (a.tv_sec < b.tv_sec || + (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec)) { + return a; + } + return b; +} + +u64 speed(timespec duration) +{ +#define DIV 1000 // avoid round errors + static const u64 giga = 1000000000; + return DIV * giga / (duration.tv_nsec + duration.tv_sec * giga); +} + +static void print(const char *name, u64 speed, const char *unit) +{ + printf("%s: %5" PRIu64 " %s\n", name, speed, unit); +} + +// TODO: adjust this crap +#define TIMESTAMP(t) \ + timespec t; \ + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t) + +#define TIMING_START \ + timespec duration; \ + duration.tv_sec = -1; \ + duration.tv_nsec = -1; \ + duration.tv_sec = 3600 * 24; \ + duration.tv_nsec = 0; \ + FOR (i, 0, 10) { \ + TIMESTAMP(start); + +#define TIMING_END \ + TIMESTAMP(end); \ + duration = min(duration, diff(start, end)); \ + } /* end FOR*/ \ + return speed(duration) + + +// not random at all, it's just to measure the speed +void p_random(u8 *buf, size_t size) +{ + static u8 v = 57; // barely random variable + FOR (i, 0, size) { + buf[i] = v; + v *= 57; + } +} + +static u64 chacha20(void) +{ + static u8 in [SIZE]; p_random(in , SIZE); + static u8 key [ 32]; p_random(key , 32); + static u8 nonce[ 8]; p_random(nonce, 8); + static u8 out [SIZE]; + + TIMING_START { + crypto_stream_chacha20_xor(out, in, SIZE, nonce, key); + } + TIMING_END; +} + +static u64 poly1305(void) +{ + static u8 in [SIZE]; p_random(in , SIZE); + static u8 key[ 32]; p_random(key , 32); + static u8 out[ 16]; + + TIMING_START { + crypto_onetimeauth(out, in, SIZE, key); + } + TIMING_END; +} + +static u64 authenticated(void) +{ + static u8 in [SIZE]; p_random(in , SIZE); + static u8 key [ 32]; p_random(key , 32); + static u8 nonce[ 8]; p_random(nonce, 8); + static u8 out [SIZE]; + static u8 mac [crypto_aead_xchacha20poly1305_ietf_ABYTES]; + TIMING_START { + crypto_aead_xchacha20poly1305_ietf_encrypt_detached( + out, mac, 0, in, SIZE, 0, 0, 0, nonce, key); + } + TIMING_END; +} + +static u64 blake2b(void) +{ + static u8 in [SIZE]; p_random(in , SIZE); + static u8 key [ 32]; p_random(key, 32); + static u8 hash[ 64]; + + TIMING_START { + crypto_generichash(hash, 64, in, SIZE, key, 32); + } + TIMING_END; +} + +static u64 argon2i(void) +{ + static u8 password [ 16]; p_random(password, 16); + static u8 salt [ 16]; p_random(salt , 16); + static u8 hash [ 32]; + + TIMING_START { + if (crypto_pwhash(hash, 32, (char*)password, 16, salt, + 3, SIZE, crypto_pwhash_ALG_ARGON2I13)) { + fprintf(stderr, "Argon2i failed.\n"); + } + } + TIMING_END; +} + +static u64 x25519(void) +{ + u8 in [32] = {9}; + u8 out[32] = {9}; + + TIMING_START { + if (crypto_scalarmult(out, out, in)) { + fprintf(stderr, "Libsodium rejected the public key\n"); + } + } + TIMING_END; +} + +static u64 edDSA_sign(void) +{ + u8 sk [64]; p_random(sk, 32); + u8 pk [32]; crypto_sign_keypair(pk, sk); + u8 message [64]; p_random(message, 64); + u8 signature[64]; + + TIMING_START { + crypto_sign_detached(signature, 0, message, 64, sk); + } + TIMING_END; +} + +static u64 edDSA_check(void) +{ + u8 sk [64]; p_random(sk, 32); + u8 pk [32]; crypto_sign_keypair(pk, sk); + u8 message [64]; p_random(message, 64); + u8 signature[64]; + + crypto_sign_detached(signature, 0, message, 64, sk); + + TIMING_START { + if (crypto_sign_verify_detached(signature, message, 64, pk)) { + printf("Monocypher verification failed\n"); + } + } + TIMING_END; +} + +int main() +{ + if (sodium_init() == -1) { + printf("Libsodium init failed. Abort.\n"); + return 1; + } + print("Chacha20 ", chacha20() * MULT/DIV, "Mb/s" ); + print("Poly1305 ", poly1305() * MULT/DIV, "Mb/s" ); + print("Auth'd encryption", authenticated() * MULT/DIV, "Mb/s" ); + print("Blake2b ", blake2b() * MULT/DIV, "Mb/s" ); + print("Argon2i ", argon2i() * MULT/DIV, "Mb/s (3 passes)" ); + print("x25519 ", x25519() / DIV, "exchanges per second"); + print("EdDSA(sign) ", edDSA_sign() / DIV, "signatures per second"); + print("EdDSA(check) ", edDSA_check() / DIV, "checks per second"); + printf("\n"); + return 0; +} -- 2.47.3