Rand-ada: a random number generation toolkit for Ada

Hi all!

I published the release 0.1.0 of the rand crate (and its companion crates, rand_core, rand_chacha, rand_distributions, rand_sys and rand_xoshiro) to the Alire index.

It is a random number generation toolkit, with a design inspired by the rand rust crate. My goal is to iterate on that first design until an eventual stable 1.0 version.

What it provides:

  • A random number generator (RNG) abstraction in rand_core, as well as (for now) three RNG implementations: rand_chacha for a cryptographically secure RNG, rand_xoshiro for a fast, non secure RNG, and finally rand_sys to get system entropy (useful for seeding the other two).

  • rand_distributions provides a distribution abstraction, and (for now) two kinds of built-in distributions: uniform distributions sampling over a user provided range, and a bernoulli distribution for weighted boolean sampling.

The library aims to be extensible and easy to use. There are some examples of usage in the README.md (and on the crate page), I’ll copy some here:

with Rand;
--  get a thread local instance of a secure Rng
R : Rand.Rng := Rand.Thread_Rng;

--  generate basic types with convenience methods
V1 : Float := R.Gen;        --  a float in the range [0, 1)
V2 : Long_Integer := R.Gen; --  a long integer over the whole range

--  get the raw output of the Rng:
Buf : Rand.Core.Bytes (1 .. 256);
R.Next_Bytes (Buf);
X : Rand.Core.U64 := R.Next;

--  use predefined distributions
use Rand.Distributions;
D1 : Uniform_Nat.Distribution := Uniform_Nat.Create (8, 27);
S : Natural := D1.Sample (R);
   --  sample in the inclusive range [8, 27]
D2 : Bernoulli.Distribution := Bernoulli.Create (0.25);
S : Boolean := D2.Sample (R);
   --  a boolean that is True 25% of the time

You can explore the repo at GitHub - AldanTanneo/rand-ada: Random number generation toolkit in Ada :smiley:

11 Likes

The Randomness hierarchy of the PragmAda Reusable Components includes a number of PRN generators considered to be good quality: Marsaglia’s Universal and KISS RNGs, the Threefry encryption-based RNG, the ISAAC cryptographically secure RNG, and a generator that combines the KISS and Universal RNGs. Some of these may be of interest to you.

5 Likes

I have some issues with these RNGs, although they are interesting!

Notably, the U32_Ranges packages is a biased implementation for medium to big ranges (would be less of an issue with a similar U64_Ranges implementation), whereas my Uniform.Discrete distribution is unbiased for any size. The Real_Ranges implementation is less biased, but still cannot ensure equal sampling of all integers in the desired range, as it relies on a float conversion. There also doesn’t seem to be a way to get random values for any discrete type bigger than 32 bits.

The ISAAC secure generator looks like another xorshift-based generator to me. I’m not going to do an in depth analysis but it’s weird (it even has a warning that starting with a 0 seed gives a very low entropy starting sequence…). It’s probably fine when properly initialized but the library doesn’t provide good primitives for that, cf next paragraph.

Bigger problem (to me): the library doesn’t offer any way of getting system entropy, instead relying on system time, which is a big vulnerability in any sensitive context.

But good news: even if those aren’t my implementations of choice, it’s easy to implement the Rng interface from my rand_core crate on these PRNGs (or a wrapper type for them), and use them as needed :stuck_out_tongue:

This might be of interest to you.

It’s based on NIST criteria and there is also a good video on it from the maker.

2 Likes

Nice resource, although I chose to only implement widely recognized random number generators in part because that way I wouldn’t have to do randomness testing myself :slight_smile:

1 Like

My analysis of this was that it was unbiased for all ranges, excluding single-value and whole-type ranges (I should update the precondition to exclude the latter). If I have made an error in my analysis I would like to know what it is.

But the *_Ranges packages are for manipulating values obtained from the generators. They are not generators themselves.

Of course, since doing so is not portable. The time-based seed is a common portable approximation of this (see the description of the time-dependent Reset procedures in ARM A.5.2, for example), but not suitable for critical cases. For those one must seed any generator with true random values obtained non-portably.

I might have looked at it too quickly, never believe anything someone says on the internet :laughing:

[getting system entropy] is not portable.

That’s why I used another crate to do it portably on several OSes, and separated the rand_sys crate from the core interfaces to make the core crates usable even without an OS :slight_smile:

Never mind the part on randomness; go to the beginning and start from there. The video is pure gold.

3 Likes