Current section
Files
Jump to
Current section
Files
src/apiculture@random.erl
-module(apiculture@random).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/apiculture/random.gleam").
-export([random_bytes/1, random_chars/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Secure randomness abstraction.\n"
"\n"
" This module provides cryptographically secure random generation for Erlang\n"
" and JavaScript targets. It exposes both byte generation and unbiased direct\n"
" alphabet sampling.\n"
).
-file("src/apiculture/random.gleam", 22).
?DOC(
" Generates cryptographically secure random bytes.\n"
"\n"
" On Erlang: Uses `crypto:strong_rand_bytes/1`\n"
" On JavaScript: Uses `crypto.getRandomValues()` (Web Crypto API)\n"
" \n"
" Returns an error if secure randomness is unavailable.\n"
).
-spec random_bytes(integer()) -> {ok, bitstring()} |
{error, apiculture@error:error()}.
random_bytes(Count) ->
case Count =< 0 of
true ->
{error, invalid_byte_count};
false ->
{ok, crypto:strong_rand_bytes(Count)}
end.
-file("src/apiculture/random.gleam", 51).
-spec do_rejection_sample(integer(), integer(), list(integer())) -> {ok,
list(integer())} |
{error, apiculture@error:error()}.
do_rejection_sample(Alphabet_size, Count, Acc) ->
case Count of
0 ->
{ok, lists:reverse(Acc)};
_ ->
Bytes = crypto:strong_rand_bytes(1),
case Bytes of
<<Byte>> ->
Max_acceptable = (case Alphabet_size of
0 -> 0;
Gleam@denominator -> 256 div Gleam@denominator
end) * Alphabet_size,
case Byte < Max_acceptable of
true ->
Char_index = case Alphabet_size of
0 -> 0;
Gleam@denominator@1 -> Byte rem Gleam@denominator@1
end,
do_rejection_sample(
Alphabet_size,
Count - 1,
[Char_index | Acc]
);
false ->
do_rejection_sample(Alphabet_size, Count, Acc)
end;
_ ->
{error, secure_random_unavailable}
end
end.
-file("src/apiculture/random.gleam", 38).
?DOC(
" Generates cryptographically secure random characters by sampling directly\n"
" from an alphabet using rejection sampling to avoid modulo bias.\n"
"\n"
" This is mathematically distinct from generating random bytes and then\n"
" encoding them - this samples characters directly from the alphabet.\n"
).
-spec random_chars(apiculture@alphabet:alphabet(), integer()) -> {ok,
list(integer())} |
{error, apiculture@error:error()}.
random_chars(Alphabet, Count) ->
case Count =< 0 of
true ->
{error, invalid_byte_count};
false ->
Alphabet_size = apiculture@alphabet:size(Alphabet),
do_rejection_sample(Alphabet_size, Count, [])
end.