pw_random#

Pigweed’s pw_random module provides a generic interface for random number generators, as well as some practical embedded-friendly implementations. While this module does not provide drivers for hardware random number generators, it acts as a user-friendly layer that can be used to abstract away such hardware.

Embedded systems have the propensity to be more deterministic than your typical PC. Sometimes this is a good thing. Other times, it’s valuable to have some random numbers that aren’t predictable. In security contexts or areas where things must be marked with a unique ID, this is especially important. Depending on the project, true hardware random number generation peripherals may or may not be available. Even if RNG hardware is present, it might not always be active or accessible. pw_random provides libraries that make these situations easier to manage.

Using RandomGenerator#

There’s two sides to a RandomGenerator; the input, and the output. The outputs are relatively straightforward; GetInt(T&) randomizes the passed integer reference, GetInt(T&, T exclusive_upper_bound) produces a random integer less than exclusive_upper_bound, and Get() dumps random values into the passed span. The inputs are in the form of the InjectEntropy*() functions. These functions are used to “seed” the random generator. In some implementations, this can simply be resetting the seed of a PRNG, while in others it might directly populate a limited buffer of random data. In all cases, entropy injection is used to improve the randomness of calls to Get*().

It might not be easy to find sources of entropy in a system, but in general a few bits of noise from ADCs or other highly variable inputs can be accumulated in a RandomGenerator over time to improve randomness. Such an approach might not be sufficient for security, but it could help for less strict uses.

API reference#

namespace random#
class RandomGenerator#

A random generator uses injected entropy to generate random values. Many of the guarantees for this interface are provided at the level of the implementations. In general:

  • DO assume a generator will always succeed.

  • DO NOT assume a generator is cryptographically secure.

  • DO NOT assume uniformity of generated data.

Subclassed by pw::random::XorShiftStarRng64

Public Functions

template<class T>
inline void GetInt(T &dest, const T &exclusive_upper_bound)#

Calculates a uniformly distributed random number in the range [0, exclusive_upper_bound).

This avoids modulo biasing. Uniformity is only guaranteed if the underlying generator generates uniform data. Uniformity is achieved by generating new random numbers until one is generated in the desired range (with optimizations).

Parameters:
  • dest[out] The destination to populate the random number into.

  • exclusive_upper_bound[in] The largest number that can be populated into dest, exclusive.

virtual void Get(ByteSpan dest) = 0#

Populates the destination buffer with a randomly generated value.

Parameters:

dest[out] The destination buffer.

virtual void InjectEntropyBits(uint32_t data, uint_fast8_t num_bits) = 0#

Injects entropy into the pool.

Parameters:
  • data[in] Up to 32 bits of random entropy data.

  • num_bits[in] The number of bits of entropy. If less than 32, entropy is assumed to be stored in the least significant bits of data.

inline void InjectEntropy(ConstByteSpan data)#

Injects entropy into the pool byte-by-byte.

class XorShiftStarRng64 : public pw::random::RandomGenerator#

A random generator based off the xorshift* algorithm.

The state is represented as an integer that, with each generation, performs exclusive OR (XOR) operations on different left/right bit shifts of itself. The * in xorshift* refers to a final multiplication that is applied to the output value. The final multiplication is essentially a nonlinear transformation that makes the algorithm stronger than a plain XOR shift.

Pigweed’s implementation augments xorshift* with an ability to inject entropy to reseed the generator throughout its lifetime. When entropy is injected, the results of the generator are no longer completely deterministic based on the original seed.

See also Xorshift RNGs and An experimental exploration of Marsaglia’s xorshift generators, scrambled.

Warning

This random generator is NOT cryptographically secure. It incorporates pseudo-random generation to extrapolate any true injected entropy. The distribution is not guaranteed to be uniform.

Public Functions

inline virtual void Get(ByteSpan dest) final#

Populates the destination buffer with a randomly generated value.

This generator uses entropy-seeded PRNG to never exhaust its random number pool.

inline virtual void InjectEntropyBits(uint32_t data, uint_fast8_t num_bits) final#

Injects entropy by rotating the state by the number of entropy bits before XORing the entropy with the current state.

This technique ensures that seeding the random value with single bits will progressively fill the state with more entropy.

Future Work#

A simple “entropy pool” implementation could buffer incoming entropy later use instead of requiring an application to directly poll the hardware RNG peripheral when the random data is needed. This would let a device collect entropy when idling, improving the latency of potentially performance-sensitive areas where random numbers are needed.