Commit 310bb3cc authored by Jesper Louis Andersen's avatar Jesper Louis Andersen
Browse files

Remove the mention of the timing module.

We have a better way to handle this. So we are going to handle it in a better way, by
simply making the direct solution: Fix the crap by using DTrace.
parent a58ab2c1
......@@ -41,7 +41,7 @@ but also note that our interface has full Edoc documentation, generated by execu
In general, the primitives provided by NaCl are intermediate-level primitives. Rather than you having to select a cipher suite, it is selected for you, and primitives are provided at a higher level. However, their correct use is still needed in order to be secure:
* Always make sure you obey the scheme of *nonce* values. If you ever reuse a nonce, and an attacker figures this out, the system will leak the XOR difference of messages sent with the same nonce. Given enough guessing, this can in turn leak the encryption stream of bits and every message hereafter, sent on the same keypair combination and reusing that nonce, will be trivially breakable.
* Use the beforenm/afternm primitives if using the `box` public-key encryption scheme. Precomputing the Curve25519 operations yields much faster operation in practice for a stream. Consult the `enacl_timing:all/0` function in order to see how much faster it is for your system. The authors Core i7-4900MQ can process roughly 32 Kilobyte data on the stream in the time it takes to do the Curve25519 computations. While NaCl is *fast*, this can make it even faster in practice.
* Use the beforenm/afternm primitives if using the `box` public-key encryption scheme. Precomputing the Curve25519 operations yields much faster operation in practice for a stream. Consult the `bench` directory for benchmarks in order to see how much faster it is for your system. The authors Core i7-4900MQ can process roughly 32 Kilobyte data on the stream in the time it takes to do the Curve25519 computations. While NaCl is *fast*, this can make it even faster in practice.
* Encrypting very large blocks of data, several megabytes for instance, is problematic for two reasons. First, while the library attempts to avoid being a memory hog, you need at least a from-space and a to-space for the data, meaning you need at least double the memory for the operation. Furthermore, while such large blocks are executed on the dirty schedulers, they will never yield the DS for another piece of work. This means you end up blocking the dirty schedulers in turn. It is often better to build a framing scheme and encrypt data in smaller chunks, say 64 or 128 kilobytes at a time. In any case, it is important to measure. Especially for latency.
* The library should provide correct success type specifications. This means you can use the dialyzer on your code and get hints for incorrect usage of the library.
* Note that every "large" input to the library accepts `iodata()` rather than `binary()` data. The library itself will convert `iodata()` to binaries internally, so you don't have to do it at your end. It often yields simpler code since you can just build up an iolist of your data and shove it to the library. Key material, nonces and the like are generally *not* accepted as `iodata()` however but requires you to input binary data. This is a deliberate choice since most such material is not supposed to be broken up and constructed ever (except perhaps for the Nonce construction).
......
%%% @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.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment