std.random suggestions
Denis Feklushkin
feklushkin.denis at gmail.com
Tue Sep 16 12:04:20 UTC 2025
I don't like the way the module std.random is designed
From a software side we have three types of ~random numbers
sources:
1. Hardware (or environmental) "true" noise.
The most reliable source, which may not be that fast, i.e. it may
be emptied in some cases, so it can be blocking and non-blocking
in block devices terms.
This is exacatly what provided by /dev/random in Linux. It should
also be noted that this random source type does not exist on all
platforms.
2. Based on hardware noise (described in 1) seeded pseudo-random
sequence.
Less (but still) reliable because it extrapolates a true random
number using a deterministic algorithm (like described in 3
below). Suitable for generating large volumes of numbers.
This is exacatly what provided by /dev/urandom in Linux. Again,
not all platforms providing it.
3. Pre-determined pseudorandom sequences based on some
predictable algorithm.
Also good for getting large amounts of numbers and fast, but it
strictly can't be used for cryptography etc. Its advantage is
that it is always available in all systems since (at worst) it is
just a mathematical function.
I think if we save users from deepening into details this will
only go to the benefit of security. So, my suggestion:
1. Do not provide any access about entropy sources (I am about
std.internal.entropy.EntropySource.tryAll and
forceEntropySource). At the application programming level we
usually have one source of true entropy. (If this is not so
please correct me.) No need to make ambitious interfaces
describing the theoretical diversity of RNGs. The "entropy" word
can be excluded from the API description completely.
2. Completely exclude "seeding" concept: this is a source of
potential issues
(https://github.com/dlang/phobos/pull/10865/commits/3c2f87ef745ca6de6e392007421af81e661aecbe). Seeding can be encapsulated inside of of urandom generator (see 2 above) if needed.
In fact, you know exactly what amount and quality of random bytes
you want to get at some point of your code. And, for example, if
system does not provides true RNG needed by you, then let the
corresponding function be totally unavailable for compilation and
leads to compile time error. Then you can't accidentally build
your neat designed software with weak predictable RNG.
It follows from this that it is necessary to provide only four
points for obtaining random numbers, all without the need for any
combining of them by users. (My suggestion is place each of it in
dedicated std.random.* module)
1. std.random.truerandom: implemented as OS/hardware call if
system provides hardware (or environmental) random number
generator. Suitable for encryption key generation, etc. Maybe
three functions will be provided, something like:
ubyte[Size] trueRandom(size_t Size)(); // blocks and waits if no
enough entropy
bool trueRandom(ref ubyte[] result); // returns false if no
enough entropy
void trueRandomEx(ref ubyte[] result); // throws if no enough
entropy
If there is no random number generator in the system, then these
functions will not be available and the compilation may end with
the error!
2. std.random.seededrandom: function(s) that is implemented
either by OS call (for Linux/Windows/Mac) or by some another TRNG
call + PseudoRandom (on baremetal platforms). Does not blocks and
not throws. Does not exist if there is no TRNG avalable because
internally uses seed value. So, again: if there is no random
number generator in the system, then these functions will not be
available and the compilation may fail.
These are pretty good random numbers for general purpose like
UUID generation.
3. std.random.pseudorandom.pseudoRandom: not for cryptography at
all. Name was specifically chosen so that the user would clearly
see the "pseudo" prefix.
Suitable for drawing a starry sky in a retro games or so one.
Internally calls std.random.seededrandom if exists or uses
std.random.predetermined (4) with seed value if seededrandom
doesn't exist. Guaranteed to exist on all platforms.
4. std.random.predetermined: functions implementing pseudorandom
number generators (PRNG). Mostly for internal use, but sometimes
users may want to get guaranteed repeatability of pseudorandom
sequences.
That's all, and nothing superfluous! I.e., if you do not use
something, it does not creates any global variables, etc. From
the point of view of the user, seems, everything is also simple
and clear. It will be difficult to make a issue with RNG in this
case.
Perhaps this is suitable for Phobos 3?
More information about the Digitalmars-d
mailing list