[Python-ideas] PEP 504: Using the system RNG by default

Tim Peters tim.peters at gmail.com
Wed Sep 16 21:13:27 CEST 2015

[Steven D'Aprano <steve at pearwood.info>, on "secrets"]

+1 on everything.  Glad _that's_ finally over ;-)

One tech point:

> ...
>   + secrets.random calls the CSPRNG; it just returns a random number
>     (integer?). There is no API for getting or setting the state,
>     setting the seed, or returning values from non-uniform
>     distributions;

The OpenBSD arc4random() has a very sparse API, but gets this part
exactly right:

    uint32_t arc4random_uniform(uint32_t upper_bound);

    arc4random_uniform() will return a single 32-bit value, uniformly
    distributed but less than upper_bound. This is recommended
    over constructions like “arc4random() % upper_bound” as it
    avoids "modulo bias" when the upper bound is not a power
    of two. In the worst case, this function may consume multiple
    iterations to ensure uniformity; see the source code to understand
    the problem and solution.

In Python, there's no point to the uint32_t restrictions, and the
function is already implemented for arbitrary bigints via the current
(but private)
Random._randbelow() method, whose implementation could be simplified
for this specific use.

That in turn relies on the .getrandbits(number_of_bits) method, which
SystemRandom overrides.

So getrandbits() is the fundamental primitive. and SystemRandom
already implements that based on .urandom() results.

An OpenBSD-ish random_uniform(upper_bound) would be a "nice to have",
but not essential.

> + secrets.choice similarly uses the CSPRNG.

Apart from error checking, that's just:

def choice(seq):
    return seq[self.random_uniform(len(seq))]

random.Random already does that (and SystemRandom inherits it),
although spelled with _randbelow().

More information about the Python-ideas mailing list