SPECK Counter-based RNG

class randomgen.speck128.SPECK128(seed=None, *, counter=None, key=None, rounds=34, mode=None)

Container for the SPECK (128 x 256) pseudo-random number generator.

Parameters
seed{None, int, SeedSequence}, optional

Entropy initializing the pseudo-random number generator. Can be an integer in [0, 2**256), a SeedSequence instance or None (the default). If seed is None, then data is read from /dev/urandom (or the Windows analog) if available. If unavailable, a hash of the time and process ID is used.

counter{None, int, array_like[uint64]}, optional

Counter to use in the SPECK128 state. Can be either a Python int in [0, 2**128) or a 2-element uint64 array. If not provided, the counter is initialized at 0.

key{None, int, array_like[uint64]}, optional

Key to use in the SPECK128 state. Unlike seed, which is run through another RNG before use, the value in key is directly set. Can be either a Python int in [0, 2**256) or a 4-element uint64 array. key and seed cannot both be used.

rounds{int}, optional

Number of rounds of the SPECK algorithm to run. The default value 34 is the official value used in encryption. Reduced-round variant might (untested) perform well statistically with improved performance.

mode{None, “sequence”, “legacy”}, optional

The seeding mode to use. “legacy” uses the legacy SplitMix64-based initialization. “sequence” uses a SeedSequence to transforms the seed into an initial state. None defaults to “sequence”.

Notes

SPECK128 is a 64-bit PRNG that uses a counter-based design based on the SPECK-128 cryptographic function [1]. Instances using different values of the key produce distinct sequences. SPECK128 has a large period \(2^{129}\) and supports arbitrary advancing and jumping the sequence in increments of \(2^{64}\). These features allow multiple non-overlapping sequences to be generated.

SPECK128 provides a capsule containing function pointers that produce doubles, and unsigned 32 and 64- bit integers. These are not directly consumable in Python and must be consumed by a Generator or similar object that supports low-level access.

See AESCounter, Philox and ThreeFry for a related counter-based PRNG.

State and Seeding

The SPECK128 state vector consists of a 12-element array of uint64 values that capture buffered draws from the distribution, a 34-element array of uint64s holding the round key, and an 12-element array of uint64 that holds the 128-bit counters (6 by 128 bits). The offset varies between 0 and 96 and shows the location in the buffer of the next 64 bits.

SPECK128 is seeded using either a single 256-bit unsigned integer or a vector of 4 64-bit unsigned integers. In either case, the seed is used as an input for a second random number generator, SplitMix64, and the output of this PRNG function is used as the initial state. Using a single 64-bit value for the seed can only initialize a small range of the possible initial state values.

Parallel Features

SPECK128 can be used in parallel applications by calling the jump method to advances the state as-if \(2^{64}\) random numbers have been generated. Alternatively, advance can be used to advance the counter for any positive step in [0, 2**128). When using jump, all generators should be initialized with the same seed to ensure that the segments come from the same sequence.

>>> from randomgen import Generator, SPECK128
>>> rg = [Generator(SPECK128(1234)) for _ in range(10)]
# Advance each SPECK128 instances by i jumps
>>> for i in range(10):
...     rg[i].bit_generator.jump(i)

Alternatively, SPECK128 can be used in parallel applications by using a sequence of distinct keys where each instance uses different key.

>>> key = 2**93 + 2**65 + 2**33 + 2**17 + 2**9
>>> rg = [Generator(SPECK128(key=key+i)) for i in range(10)]

Compatibility Guarantee

SPECK128 makes a guarantee that a fixed seed and will always produce the same random integer stream.

References

1

Ray Beaulieu, Douglas Shors, Jason Smith, Stefan Treatman-Clark, Bryan Weeks, and Louis Wingers. SIMON and SPECK Implementation Guide. National Security Agency. January 15, 2019. from https://nsacyber.github.io/simon-speck/implementations/ImplementationGuide1.1.pdf

Examples

>>> from randomgen import Generator, SPECK128
>>> rg = Generator(SPECK128(1234))
>>> rg.standard_normal()
0.123  # random
Attributes
lockthreading.Lock

Lock instance that is shared so that the same bit git generator can be used in multiple Generators without corrupting the state. Code that generates values from a bit generator should hold the bit generator’s lock.

seed_seq{None, SeedSequence}

The SeedSequence instance used to initialize the generator if mode is “sequence” or is seed is a SeedSequence. None if mode is “legacy”.

Seeding and State

seed([seed, counter, key])

Seed the generator

state

Get or set the PRNG state

Parallel generation

advance(delta)

Advance the underlying RNG as-if delta draws have occurred.

jump([iter])

Jumps the state as-if iter * 2**64 random numbers are generated

jumped([iter])

Returns a new bit generator with the state jumped

Extending

cffi

CFFI interface

ctypes

ctypes interface

Testing

random_raw([size, output])

Return randoms as generated by the underlying BitGenerator