Implement missing random functions* enacl:randombytes_int32/0* enacl:randombytes_uniform/1

This commit is contained in:
Jesper Louis Andersen 2020-01-15 13:55:02 +01:00
parent bc1af327e5
commit f9d6034e84
4 changed files with 64 additions and 3 deletions

View File

@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
- Implement enacl:randombytes_int32/0. Returns a random 32bit unsigned
integer, by means of the underlying random source.
- Implement enacl:randombytes_uniform/1. Takes up to a 32bit unsigned
integer and produces a uniform integer in the range [0..N). Note
that the implementation avoids the typical non-uniformness which
would be present on a modulus operation on the nearest power-of-two
integer.
- Added a nix shell for easier development
## [0.17.2]

View File

@ -1029,6 +1029,31 @@ static ERL_NIF_TERM enif_randombytes(ErlNifEnv *env, int argc,
return enif_make_binary(env, &result);
}
static ERL_NIF_TERM enif_randombytes_int32(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifUInt64 result;
if (argc != 0) {
return enif_make_badarg(env);
}
result = randombytes_random();
return enif_make_uint64(env, result);
}
static ERL_NIF_TERM enif_randombytes_uniform(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
unsigned upper_bound;
ErlNifUInt64 result;
if ((argc != 1) || (!enif_get_uint(env, argv[0], &upper_bound))) {
return enif_make_badarg(env);
}
result = randombytes_uniform(upper_bound);
return enif_make_uint64(env, result);
}
/* Key exchange */
static ERL_NIF_TERM enif_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc,
@ -1741,7 +1766,14 @@ static ErlNifFunc nif_funcs[] = {
{"crypto_sign_ed25519_SECRETKEYBYTES", 0,
enif_crypto_sign_ed25519_SECRETKEYBYTES},
// Linux might block here if early in the boot sequence, so get it off the
// main scheduler. Otherwise, it it would probably be fine to run on the
// main scheduler. This plays it safe, albeit with a performance hit.
erl_nif_dirty_job_cpu_bound_macro("randombytes", 1, enif_randombytes),
erl_nif_dirty_job_cpu_bound_macro("randombytes_int32", 0,
enif_randombytes_int32),
erl_nif_dirty_job_cpu_bound_macro("randombytes_uniform", 1,
enif_randombytes_uniform),
erl_nif_dirty_job_cpu_bound_macro("crypto_kx_keypair", 0,
enif_crypto_kx_keypair),

View File

@ -122,7 +122,9 @@
%% Randomness
-export([
%% EQC
randombytes/1
randombytes/1,
randombytes_int32/0,
randombytes_uniform/1
]).
%%% Specific primitives
@ -204,6 +206,9 @@
-define(CRYPTO_GENERICHASH_KEYBYTES_MAX, 64).
-define(CRYPTO_GENERICHASH_KEYBYTES, 32).
%% Size limits
-define(MAX_32BIT_INT, 1 bsl 32).
%% @doc Verify makes sure the constants defined in libsodium matches ours
verify() ->
true = equals(binary:copy(<<0>>, enacl_nif:crypto_box_ZEROBYTES()), ?P_ZEROBYTES),
@ -1119,6 +1124,18 @@ aead_chacha20poly1305_MESSAGEBYTES_MAX() ->
randombytes(N) ->
enacl_nif:randombytes(N).
%% @doc randombytes_int32/0 produces an integer in the 32bit range
%% @end
-spec randombytes_int32() -> integer().
randombytes_int32() ->
enacl_nif:randombytes_int32().
%% @doc randombytes_uniform/1 produces a random integer in the space [0..N)
%% That is with the upper bound excluded. Fails for integers above 32bit size
%% @end
randombytes_uniform(N) when N < ?MAX_32BIT_INT ->
enacl_nif:randombytes_uniform(N).
%% Helpers
%% @doc bump/4 bumps a reduction budget linearly before returning the result

View File

@ -153,7 +153,9 @@
%% Access to the RNG
-export([
randombytes/1
randombytes/1,
randombytes_int32/0,
randombytes_uniform/1
]).
%% Undocumented features :>
@ -296,5 +298,7 @@ crypto_kx_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_kx_SECRETKEYBYTES() -> erlang:nif_error(nif_not_loaded).
randombytes(_RequestedSize) -> erlang:nif_error(nif_not_loaded).
randombytes_int32() -> erlang:nif_error(nif_not_loaded).
randombytes_uniform(_UpperBound) -> erlang:nif_error(nif_not_loaded).
scramble_block_16(_Block, _Key) -> erlang:nif_error(nif_not_loaded).