From 77039e648c8a62bfc4f0242531d5fd4874b29aad Mon Sep 17 00:00:00 2001 From: Guilherme Andrade Date: Sat, 18 Mar 2017 17:27:35 +0000 Subject: Support cryptographically strong rand plugin --- lib/stdlib/src/rand.erl | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'lib/stdlib/src/rand.erl') diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index 1f457b9e0e..3ff7aaf15f 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -45,20 +45,22 @@ %% ===================================================================== %% This depends on the algorithm handler function --type alg_seed() :: exs64_state() | exsplus_state() | exs1024_state(). +-type alg_seed() :: exs64_state() | exsplus_state() | exs1024_state() | term(). + %% This is the algorithm handler function within this module -type alg_handler() :: #{type := alg(), - max := integer(), - next := fun(), - uniform := fun(), - uniform_n := fun(), - jump := fun()}. - -%% Internal state --opaque state() :: {alg_handler(), alg_seed()}. --type alg() :: exs64 | exsplus | exs1024. --opaque export_state() :: {alg(), alg_seed()}. --export_type([alg/0, state/0, export_state/0]). + max := integer() | infinity, + next := fun((alg_seed()) -> {uint64(), alg_seed()}), + uniform := fun((state()) -> {float(), state()}), + uniform_n := fun((pos_integer(), state()) -> {pos_integer(), state()}), + jump := fun((state()) -> state())}. + +%% Algorithm state +-type state() :: {alg_handler(), alg_seed()}. +-type builtin_alg() :: exs64 | exsplus | exs1024. +-type alg() :: builtin_alg() | term(). +-type export_state() :: {alg(), alg_seed()}. +-export_type([builtin_alg/0, alg/0, alg_handler/0, alg_seed/0, state/0, export_state/0]). %% ===================================================================== %% API @@ -81,15 +83,17 @@ export_seed_s({#{type:=Alg}, Seed}) -> {Alg, Seed}. %% seed({Alg,Seed}) setup RNG with a previously exported seed %% and return the NEW state --spec seed(AlgOrExpState::alg() | export_state()) -> state(). +-spec seed(AlgOrStateOrExpState::builtin_alg() | state() | export_state()) -> state(). seed(Alg) -> seed_put(seed_s(Alg)). --spec seed_s(AlgOrExpState::alg() | export_state()) -> state(). +-spec seed_s(AlgOrStateOrExpState::builtin_alg() | state() | export_state()) -> state(). seed_s(Alg) when is_atom(Alg) -> seed_s(Alg, {erlang:phash2([{node(),self()}]), erlang:system_time(), erlang:unique_integer()}); +seed_s({AlgHandler, _Seed} = State) when is_map(AlgHandler) -> + State; seed_s({Alg0, Seed}) -> {Alg,_SeedFun} = mk_alg(Alg0), {Alg, Seed}. @@ -97,11 +101,11 @@ seed_s({Alg0, Seed}) -> %% seed/2: seeds RNG with the algorithm and given values %% and returns the NEW state. --spec seed(Alg :: alg(), {integer(), integer(), integer()}) -> state(). +-spec seed(Alg :: builtin_alg(), {integer(), integer(), integer()}) -> state(). seed(Alg0, S0) -> seed_put(seed_s(Alg0, S0)). --spec seed_s(Alg :: alg(), {integer(), integer(), integer()}) -> state(). +-spec seed_s(Alg :: builtin_alg(), {integer(), integer(), integer()}) -> state(). seed_s(Alg0, S0 = {_, _, _}) -> {Alg, Seed} = mk_alg(Alg0), AS = Seed(S0), -- cgit v1.2.3 From 54b89c8750bed431275f1f376fb10ec7899ca335 Mon Sep 17 00:00:00 2001 From: Guilherme Andrade Date: Wed, 22 Mar 2017 21:50:20 +0000 Subject: fixup! Support cryptographically strong rand plugin Fix plugin alg type --- lib/stdlib/src/rand.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/stdlib/src/rand.erl') diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index 3ff7aaf15f..ddd22914e2 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -58,7 +58,7 @@ %% Algorithm state -type state() :: {alg_handler(), alg_seed()}. -type builtin_alg() :: exs64 | exsplus | exs1024. --type alg() :: builtin_alg() | term(). +-type alg() :: builtin_alg() | atom(). -type export_state() :: {alg(), alg_seed()}. -export_type([builtin_alg/0, alg/0, alg_handler/0, alg_seed/0, state/0, export_state/0]). -- cgit v1.2.3 From 195edd9076c865f8af6a9aeeb02bc032b94c0fb3 Mon Sep 17 00:00:00 2001 From: Guilherme Andrade Date: Wed, 22 Mar 2017 21:51:17 +0000 Subject: fixup! Support cryptographically strong rand plugin Minimize use of guards. --- lib/stdlib/src/rand.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/stdlib/src/rand.erl') diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index ddd22914e2..60da53cd2b 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -88,15 +88,15 @@ seed(Alg) -> seed_put(seed_s(Alg)). -spec seed_s(AlgOrStateOrExpState::builtin_alg() | state() | export_state()) -> state(). -seed_s(Alg) when is_atom(Alg) -> - seed_s(Alg, {erlang:phash2([{node(),self()}]), - erlang:system_time(), - erlang:unique_integer()}); seed_s({AlgHandler, _Seed} = State) when is_map(AlgHandler) -> State; seed_s({Alg0, Seed}) -> {Alg,_SeedFun} = mk_alg(Alg0), - {Alg, Seed}. + {Alg, Seed}; +seed_s(Alg) -> + seed_s(Alg, {erlang:phash2([{node(),self()}]), + erlang:system_time(), + erlang:unique_integer()}). %% seed/2: seeds RNG with the algorithm and given values %% and returns the NEW state. -- cgit v1.2.3 From e1a74e3077ca870520a748f29dd7c4b9115ce090 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 3 Apr 2017 12:29:23 +0200 Subject: Clean up documentation and test cases --- lib/stdlib/src/rand.erl | 68 +++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 25 deletions(-) (limited to 'lib/stdlib/src/rand.erl') diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index 60da53cd2b..dfd102f9ef 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -45,22 +45,31 @@ %% ===================================================================== %% This depends on the algorithm handler function --type alg_seed() :: exs64_state() | exsplus_state() | exs1024_state() | term(). +-type alg_state() :: + exs64_state() | exsplus_state() | exs1024_state() | term(). %% This is the algorithm handler function within this module --type alg_handler() :: #{type := alg(), - max := integer() | infinity, - next := fun((alg_seed()) -> {uint64(), alg_seed()}), - uniform := fun((state()) -> {float(), state()}), - uniform_n := fun((pos_integer(), state()) -> {pos_integer(), state()}), - jump := fun((state()) -> state())}. +-type alg_handler() :: + #{type := alg(), + max := integer() | infinity, + next := + fun((alg_state()) -> {non_neg_integer(), alg_state()}), + uniform := + fun((state()) -> {float(), state()}), + uniform_n := + fun((pos_integer(), state()) -> {pos_integer(), state()}), + jump := + fun((state()) -> state())}. %% Algorithm state --type state() :: {alg_handler(), alg_seed()}. +-type state() :: {alg_handler(), alg_state()}. -type builtin_alg() :: exs64 | exsplus | exs1024. -type alg() :: builtin_alg() | atom(). --type export_state() :: {alg(), alg_seed()}. --export_type([builtin_alg/0, alg/0, alg_handler/0, alg_seed/0, state/0, export_state/0]). +-type export_state() :: {alg(), alg_state()}. +-export_type( + [builtin_alg/0, alg/0, alg_handler/0, alg_state/0, + state/0, export_state/0]). +-export_type([exs64_state/0, exsplus_state/0, exs1024_state/0]). %% ===================================================================== %% API @@ -74,7 +83,7 @@ export_seed() -> _ -> undefined end. --spec export_seed_s(state()) -> export_state(). +-spec export_seed_s(State :: state()) -> export_state(). export_seed_s({#{type:=Alg}, Seed}) -> {Alg, Seed}. %% seed(Alg) seeds RNG with runtime dependent values @@ -83,11 +92,15 @@ export_seed_s({#{type:=Alg}, Seed}) -> {Alg, Seed}. %% seed({Alg,Seed}) setup RNG with a previously exported seed %% and return the NEW state --spec seed(AlgOrStateOrExpState::builtin_alg() | state() | export_state()) -> state(). +-spec seed( + AlgOrStateOrExpState :: builtin_alg() | state() | export_state()) -> + state(). seed(Alg) -> seed_put(seed_s(Alg)). --spec seed_s(AlgOrStateOrExpState::builtin_alg() | state() | export_state()) -> state(). +-spec seed_s( + AlgOrStateOrExpState :: builtin_alg() | state() | export_state()) -> + state(). seed_s({AlgHandler, _Seed} = State) when is_map(AlgHandler) -> State; seed_s({Alg0, Seed}) -> @@ -101,11 +114,15 @@ seed_s(Alg) -> %% seed/2: seeds RNG with the algorithm and given values %% and returns the NEW state. --spec seed(Alg :: builtin_alg(), {integer(), integer(), integer()}) -> state(). +-spec seed( + Alg :: builtin_alg(), Seed :: {integer(), integer(), integer()}) -> + state(). seed(Alg0, S0) -> seed_put(seed_s(Alg0, S0)). --spec seed_s(Alg :: builtin_alg(), {integer(), integer(), integer()}) -> state(). +-spec seed_s( + Alg :: builtin_alg(), Seed :: {integer(), integer(), integer()}) -> + state(). seed_s(Alg0, S0 = {_, _, _}) -> {Alg, Seed} = mk_alg(Alg0), AS = Seed(S0), @@ -117,7 +134,7 @@ seed_s(Alg0, S0 = {_, _, _}) -> %% uniform/0: returns a random float X where 0.0 < X < 1.0, %% updating the state in the process dictionary. --spec uniform() -> X::float(). +-spec uniform() -> X :: float(). uniform() -> {X, Seed} = uniform_s(seed_get()), _ = seed_put(Seed), @@ -127,7 +144,7 @@ uniform() -> %% uniform/1 returns a random integer X where 1 =< X =< N, %% updating the state in the process dictionary. --spec uniform(N :: pos_integer()) -> X::pos_integer(). +-spec uniform(N :: pos_integer()) -> X :: pos_integer(). uniform(N) -> {X, Seed} = uniform_s(N, seed_get()), _ = seed_put(Seed), @@ -137,7 +154,7 @@ uniform(N) -> %% returns a random float X where 0.0 < X < 1.0, %% and a new state. --spec uniform_s(state()) -> {X::float(), NewS :: state()}. +-spec uniform_s(State :: state()) -> {X :: float(), NewState :: state()}. uniform_s(State = {#{uniform:=Uniform}, _}) -> Uniform(State). @@ -145,7 +162,8 @@ uniform_s(State = {#{uniform:=Uniform}, _}) -> %% uniform_s/2 returns a random integer X where 1 =< X =< N, %% and a new state. --spec uniform_s(N::pos_integer(), state()) -> {X::pos_integer(), NewS::state()}. +-spec uniform_s(N :: pos_integer(), State :: state()) -> + {X :: pos_integer(), NewState :: state()}. uniform_s(N, State = {#{uniform_n:=Uniform, max:=Max}, _}) when 0 < N, N =< Max -> Uniform(N, State); @@ -159,7 +177,7 @@ uniform_s(N, State0 = {#{uniform:=Uniform}, _}) %% after a large number of call defined for each algorithm. %% The large number is algorithm dependent. --spec jump(state()) -> NewS :: state(). +-spec jump(state()) -> NewState :: state(). jump(State = {#{jump:=Jump}, _}) -> Jump(State). @@ -168,7 +186,7 @@ jump(State = {#{jump:=Jump}, _}) -> %% and write back the new value to the internal state, %% then returns the new value. --spec jump() -> NewS :: state(). +-spec jump() -> NewState :: state(). jump() -> seed_put(jump(seed_get())). @@ -186,7 +204,7 @@ normal() -> %% The Ziggurat Method for generating random variables - Marsaglia and Tsang %% Paper and reference code: http://www.jstatsoft.org/v05/i08/ --spec normal_s(state()) -> {float(), NewS :: state()}. +-spec normal_s(State :: state()) -> {float(), NewState :: state()}. normal_s(State0) -> {Sign, R, State} = get_52(State0), Idx = R band 16#FF, @@ -249,7 +267,7 @@ mk_alg(exs1024) -> %% Reference URL: http://xorshift.di.unimi.it/ %% ===================================================================== --type exs64_state() :: uint64(). +-opaque exs64_state() :: uint64(). exs64_seed({A1, A2, A3}) -> {V1, _} = exs64_next(((A1 band ?UINT32MASK) * 4294967197 + 1)), @@ -284,7 +302,7 @@ exs64_jump(_) -> %% Modification of the original Xorshift128+ algorithm to 116 %% by Sebastiano Vigna, a lot of thanks for his help and work. %% ===================================================================== --type exsplus_state() :: nonempty_improper_list(uint58(), uint58()). +-opaque exsplus_state() :: nonempty_improper_list(uint58(), uint58()). -dialyzer({no_improper_lists, exsplus_seed/1}). @@ -353,7 +371,7 @@ exsplus_jump(S, [AS0|AS1], J, N) -> %% Reference URL: http://xorshift.di.unimi.it/ %% ===================================================================== --type exs1024_state() :: {list(uint64()), list(uint64())}. +-opaque exs1024_state() :: {list(uint64()), list(uint64())}. exs1024_seed({A1, A2, A3}) -> B1 = (((A1 band ?UINT21MASK) + 1) * 2097131) band ?UINT21MASK, -- cgit v1.2.3