enacl/src/enacl_timing.erl
Jesper Louis Andersen 50b0058335 Improve the documentation of the project.
Go over the README file, and improve its contents. Add a Usage/hints section
with some helpful hints on how to use the library in turn. Also while here, make
sure that `rebar doc` works as expected and fix every documentation bug in
the EDoc sections, so it compiles and works. Verify the documentation output
is nice-looking while at it.
2014-12-18 09:28:00 +01:00

238 lines
7.4 KiB
Erlang

%%% @doc module enacl_timing provides helpers for timing enacl toward your installation.
%%% <p>To use this module, make sure you disable CPU frequency scaling to obtain better numbers for your system.</p>
%%% @end
-module(enacl_timing).
-export([all/0]).
%% @doc all/0 runs all timing code and reports the timings of different enacl primitives
%% <p>Returns a nested list structure containing maps which explains the runtimes of different primitives</p>
%% <p>The structure is subject to change without notice, so don't rely on it in code.</p>
%% @end
all() ->
[time_hashing(),
time_box(),
time_sign(),
time_secretbox(),
time_stream(),
time_auth(),
time_onetimeauth(),
time_precomputed()].
-define(ROUNDS, 300).
%% ONETIMEAUTH
%% ------------
time_onetimeauth() ->
Sz = 1024 * 128,
M = binary:copy(<<0>>, Sz),
K = <<"secretsecretsecretsecretsecret32">>,
T = timed(fun() -> onetime_auth(M, K, ?ROUNDS) end) / ?ROUNDS,
A = enacl:onetime_auth(M, K),
T2 = timed(fun() -> onetime_auth_verify(A, M, K, ?ROUNDS) end) / ?ROUNDS,
true = enacl:onetime_auth_verify(A, M, K),
[
#{ size => Sz, time => T, operation => onetime_auth },
#{ size => Sz, time => T2, operation => onetime_auth_verify }
].
onetime_auth(_M, _K, 0) -> ok;
onetime_auth(M, K, N) ->
enacl_nif:crypto_onetimeauth_b(M, K),
onetime_auth(M, K, N-1).
onetime_auth_verify(_A, _M, _K, 0) -> ok;
onetime_auth_verify(A, M, K, N) ->
enacl_nif:crypto_onetimeauth_verify_b(A, M, K),
onetime_auth_verify(A, M, K, N-1).
%% AUTH
%% -----------
time_auth() ->
Sz = 1024 * 32,
M = binary:copy(<<0>>, Sz),
K = <<"secretsecretsecretsecretsecret32">>,
T = timed(fun() -> auth(M, K, ?ROUNDS) end) / ?ROUNDS,
A = enacl:auth(M, K),
T2 = timed(fun() -> auth_verify(A, M, K, ?ROUNDS) end) / ?ROUNDS,
true = enacl:auth_verify(A, M, K),
[
#{ size => Sz, time => T, operation => auth },
#{ size => Sz, time => T2, operation => auth_verify }
].
auth(_M, _K, 0) -> ok;
auth(M, K, N) ->
enacl_nif:crypto_auth_b(M, K),
auth(M, K, N-1).
auth_verify(_A, _M, _K, 0) -> ok;
auth_verify(A, M, K, N) ->
enacl_nif:crypto_auth_verify_b(A, M, K),
auth_verify(A, M, K, N-1).
%% STREAM
%% -----------
time_stream() ->
Sz = 1024 * 128,
K = <<"secretsecretsecretsecretsecret32">>,
Nonce = <<0:192>>,
T = timed(fun () -> stream(Sz, Nonce, K, ?ROUNDS) end) / ?ROUNDS,
M = binary:copy(<<0>>, Sz),
T2 = timed(fun () -> stream_xor(M, Nonce, K, ?ROUNDS) end) / ?ROUNDS,
[
#{ size => Sz, time => T, operation => stream },
#{ size => Sz, time => T2, operation => stream_xor }
].
stream(_Sz, _Nonce, _K, 0) -> ok;
stream(Sz, Nonce, K, N) ->
enacl_nif:crypto_stream_b(Sz, Nonce, K),
stream(Sz, Nonce, K, N-1).
stream_xor(_M, _Nonce, _K, 0) -> ok;
stream_xor(M, Nonce, K, N) ->
enacl_nif:crypto_stream_xor_b(M, Nonce, K),
stream_xor(M, Nonce, K, N-1).
%% SECRETBOX
%% ----------
time_secretbox() ->
Sz = 1024 * 64,
M = binary:copy(<<0>>, Sz),
K = <<"secretsecretsecretsecretsecret32">>,
Nonce = binary:copy(<<0:192>>),
T = timed(fun() -> secretbox(M, Nonce, K, ?ROUNDS) end) / ?ROUNDS,
CT = enacl:secretbox(M, Nonce, K),
T2 = timed(fun() -> secretbox_open(CT, Nonce, K, ?ROUNDS) end) / ?ROUNDS,
{ok, M} = enacl:secretbox_open(CT, Nonce, K),
[
#{ size => Sz, time => T, operation => secretbox },
#{ size => Sz, time => T2, operation => secretbox_open }
].
secretbox(_M, _Nonce, _K, 0) -> ok;
secretbox(M, Nonce, K, N) ->
enacl_nif:crypto_secretbox_b(M, Nonce, K),
secretbox(M, Nonce, K, N-1).
secretbox_open(_M, _Nonce, _K, 0) -> ok;
secretbox_open(M, Nonce, K, N) ->
enacl_nif:crypto_secretbox_open_b(M, Nonce, K),
secretbox_open(M, Nonce, K, N-1).
%% SIGN
%% ---------
time_sign() ->
Sz = 1024 * 16,
M = binary:copy(<<0>>, Sz),
#{ public := PK, secret := SK } = enacl:sign_keypair(),
T = timed(fun() -> sign(M, SK, ?ROUNDS) end) / ?ROUNDS,
SM = enacl:sign(M, SK),
T2 = timed(fun() -> sign_open(SM, PK, ?ROUNDS) end) / ?ROUNDS,
[
#{ size => Sz, time => T, operation => sign },
#{ size => Sz, time => T2, operation => sign_open }
].
sign(_M, _SK, 0) -> ok;
sign(M, SK, N) ->
enacl_nif:crypto_sign_b(M, SK),
sign(M, SK, N-1).
sign_open(_SM, _PK, 0) -> ok;
sign_open(SM, PK, N) ->
enacl_nif:crypto_sign_open_b(SM, PK),
sign_open(SM, PK, N-1).
%% BOX
%% --------
time_box() ->
Sz = 1024 * 32,
ZB = binary:copy(<<0>>, enacl_nif:crypto_box_ZEROBYTES()),
BZB = binary:copy(<<0>>, enacl_nif:crypto_box_BOXZEROBYTES()),
Bin = binary:copy(<<0>>, Sz),
Nonce = binary:copy(<<0>>, enacl_nif:crypto_box_NONCEBYTES()),
#{ public := PK1, secret := SK1 } = enacl:box_keypair(),
#{ public := PK2, secret := SK2 } = enacl:box_keypair(),
T = timed(fun() -> box([ZB, Bin], Nonce, PK1, SK2, ?ROUNDS) end) / ?ROUNDS,
Boxed = enacl:box([ZB, Bin], Nonce, PK1, SK2),
T2 = timed(fun() -> box_open([BZB, Boxed], Nonce, PK2, SK1, ?ROUNDS) end) / ?ROUNDS,
[
#{ size => Sz, time => T, operation => box},
#{ size => Sz, time => T2, operation => box_open}
].
box_open(_Bin, _Nonce, _PK, _SK, 0) -> ok;
box_open(Bin, Nonce, PK, SK, N) ->
enacl_nif:crypto_box_open_b(Bin, Nonce, PK, SK),
box_open(Bin, Nonce, PK, SK, N-1).
box(_Bin, _Nonce, _PK, _SK, 0) -> ok;
box(Bin, Nonce, PK, SK, N) ->
enacl_nif:crypto_box_b(Bin, Nonce, PK, SK),
box(Bin, Nonce, PK, SK, N-1).
%% PRECOMPUTED
%% -------------------
time_precomputed() ->
Sz = 1024 * 64,
Bin = binary:copy(<<0>>, Sz),
ZB = binary:copy(<<0>>, enacl_nif:crypto_box_ZEROBYTES()),
BZB = binary:copy(<<0>>, enacl_nif:crypto_box_BOXZEROBYTES()),
Nonce = binary:copy(<<0>>, enacl_nif:crypto_box_NONCEBYTES()),
#{ public := PK1, secret := SK1 } = enacl:box_keypair(),
#{ public := PK2, secret := SK2 } = enacl:box_keypair(),
T = timed(fun() -> beforenm(PK1, SK2, ?ROUNDS) end) / ?ROUNDS,
K = enacl_nif:crypto_box_beforenm(PK1, SK2),
K = enacl_nif:crypto_box_beforenm(PK2, SK1),
T2 = timed(fun() -> afternm([ZB, Bin], Nonce, K, ?ROUNDS) end) / ?ROUNDS,
Ciphered = enacl_nif:crypto_box_afternm_b([ZB, Bin], Nonce, K),
Bin = enacl_nif:crypto_box_open_afternm_b([BZB, Ciphered], Nonce, K),
T3 = timed(fun() -> afternm_open([BZB, Ciphered], Nonce, K, ?ROUNDS) end) / ?ROUNDS,
[
#{ size => 'n/a', time => T, operation => box_beforenm },
#{ size => Sz, time => T2, operation => box_afternm },
#{ size => Sz, time => T3, operation => box_open_afternm }
].
afternm(_M, _Nonce, _K, 0) -> ok;
afternm(M, Nonce, K, N) ->
enacl_nif:crypto_box_afternm_b(M, Nonce, K),
afternm(M, Nonce, K, N-1).
afternm_open(_C, _Nonce, _K, 0) -> ok;
afternm_open(C, Nonce, K, N) ->
enacl_nif:crypto_box_open_afternm_b(C, Nonce, K),
afternm_open(C, Nonce, K, N-1).
beforenm(_PK, _SK, 0) -> ok;
beforenm(PK, SK, N) ->
enacl_nif:crypto_box_beforenm(PK, SK),
beforenm(PK, SK, N-1).
%% HASHING
%% ----------------
time_hashing() ->
Sz = 1024 * 32,
Bin = binary:copy(<<0>>, Sz),
T = timed(fun() -> hash(Bin, ?ROUNDS) end) / ?ROUNDS,
#{ size => Sz, time => T, operation => hash}.
hash(_Bin, 0) -> ok;
hash(Bin, N) ->
enacl_nif:crypto_hash_b(Bin),
hash(Bin, N-1).
%% Helpers
timed(Fun) ->
Fun(), % warmup
{T, _} = timer:tc(Fun),
T.