{ ^_^ } sinustrom Solving life, one problem at a time!

Improving RNG entropy under Linux

2019-10-22
Author: Zoltan Puskas
Categories: linux
Tags:

On my headless compile and compute box I’ve bumped into the low entropy problem, where the machine takes almost 10 minutes to become available during startup, as the kernel cannot gather enough seed entropy, blocking systemd and OpenSSH from finishing initialization. Though enabling RDRAND instructions in the kernel mitigated the issue of slow booting there was still not enough entropy post boot. This prompted me to dive a deeper into random number generators (RNG) under Linux to understand how it all works and what options are available to improve my entropy pool size, and if possible, the quality of it too.

Random number basics

One of the most important usage for random numbers in computing is for security (e.g. crypto keys, memory address randomization), although statistical analysis uses it for sampling and different simulators also make good use of them. Without good random numbers encryption keys become predicable thus weakening or even nullifying security.

Mathematically speaking a sequence of random numbers R1, R2, R3, …, RN has the following properties:

  • uniform distribution; i.e. values are equally probable everywhere within the range of possible R values,
  • independence; i.e. the current value of RN has no relation with the previous R1, …, RN-1 values.

Computers obtain random numbers by two main methods:

  • Collecting physical events from user interactions, hardware event timing as well as using specific hardware, so called true random number generators (TRNG). Latter are designed around some statistically random phenomena like radioactive decay, thermal noise, avalanche noise, etc.
  • Generating them via functions, a.k.a. pseudorandom number generators (PRNG).

Since computers are mostly predictable machines, we have very few sources of good entropy, making it hard to obtain a constant, relatively high bit rate sequence of random numbers. PRNG-s also become predictable without a good random number source for seeding their function.

Linux’s source code, namely drivers/char/random.c, provides great insight into random number generation in the kernel, it is well worth a read. In short: truly random numbers in reality are not generated, but rather “collected”. When enough real random events are fed into the system (a.k.a. we have enough entropy stored, which is done by maintaining state of a CRC-like function) we obtain random numbers by SHA hashing the contents of the entropy pool. If there are multiple sources of randomness, their values are mixed via XOR operation.

We use these real random numbers to seed the PRNG, which in turn is used to generate more pseudorandom numbers at a higher speed (think /dev/urandom, a.k.a. unlimited random number device). However due to the nature of the PRNG being a function it has to be reseeded periodically to provide good results, which are indistinguishable from real random, especially for cryptographic use cases. This is why we need a constant flow of real random numbers in the system.

In search for more entropy

Linux’s init system will save the entropy pool on shutdown and then use it to seed the RNG when booting up again. This is in fact supported by both openrc (urandom) and systemd (systemd-random-seed.service) and is enabled by default. However this is insufficient on a system where the available entropy in the pool during operation is really low, usually less than 100 bits, as was in my case. Since my box runs headless, has no peripherals attached, uses an SSD, not to mention the lack of hardware security module (e.g. a TPM), it’s not surprising entropy was so hard to come by.

To make the boot process reasonably fast we can enable CONFIG_RANDOM_TRUST_CPU=y in the kernel configuration, which tells Linux to trust the CPU manufacturer to initialize it’s congruential random number generator (CRNG), in other words use the RDRAND or equivalent instruction as a source of entropy.

    Device Drivers  --->
      [*] Trust the CPU manufacturer to initialize Linux's CRNG

Whether this instruction is “backdoored” or not is mostly irrelevant, since the Linux kernel uses multiple sources to collect entropy from, thus making /dev/random provide good random numbers regardless.

However this is still not enough to resolve the entropy pool being low post boot, causing performance problems for example when generating SSL/TLS or block ciphers (think certificate rotation, signing, etc). We need to additionally set up a way to feed the entropy pool with more random events. This can be achieved by setting up rngd from rng-tools. This daemon will monitor available entropy in the pool and feed it from multiple sources (e.g. RDRAND instruction, TPM chip, TRNG) to make sure the machine has a healthy amount of random bits ready to be used, usually >3000 bits.

Getting a TRNG

Technically rngd can function on only using the CPU’s random instruction to feed the entropy pool, however with the recent plague of processor issues, like the most recent AMD RDRAND bug, I think it’s reasonable to have at least one more reliable source of randomness, and since my compile box has no TPM chip, like most laptops do, I’ve decided to install a hardware random number generator.

Device options

Fortunately there are quite a few options to choose from. The list is non-exhaustive, as I primarily looked at Linux compatible, being open source as much as possible, and not too expensive solutions. Here are some devices to consider as additional hardware random number generators:

Device Hardware Firmware Kernel driver Needs utility Reflashable
ChaosKey Open Open Mainlined1 No Yes
Infinite Noise Open No FW2 Mainlined3 Yes4 n/a
OneRNG Open Open Mainlined3 Yes5 Yes
Bitbabbler Open No FW2 Mainlined3 Yes4 n/a
TrueRNG Closed Closed Mainlined3 Yes5 No

1 Driver provides /dev/hwrng device just like a TPM. If TPM is also present on the system, switching to ChaosKey is required.
2 USB interface chip is hardwired.
3 Uses kernel’s USB to serial driver.
4 Has it’s own daemon implementation, that needs compiling/installing, although it might be possible to read directly from the serial port by configuring rngd accordingly.
5 Has additional scripts and udev rules that need installing.

Reflashability along with open firmware source code is important for validation as well as for self flashing the device as an additional guarantee of tamper proofing.

In the end I’ve chosen the ChaosKey, as it’s completely open in addition to the driver being mainlined in the kernel, not needing further device specific binaries, and last but not least being compact.

Installing the ChaosKey

First a new kernel module is required for the ChaosKey to work, which can be achieved by enabling the following option:

    Device Drivers  --->
      [*] USB support  --->
        <M>   ChaosKey random number generator driver support

Once the module is loaded, the kernel will use the ChaosKey as an additional entropy source. If everything works the Chaoskey will show up as /dev/hwrng on the system and can be used as an additional source for random numbers.

The hardware itself fits nicely into the hidden USB compartment originally intended for the wireless receiver of the Steam Controller.

ChaosKey in the Steam Machine's bottom compartment ChaosKey in the Steam Machine's bottom compartment

Before installing the ChaosKey, I’ve usually had sub 100 bit entropy available on my box. An example of available entropy 20 minutes after boot:

$ cat /proc/sys/kernel/random/entropy_avail
34

After plugging in the TRNG the situation looks much healthier,

$ cat /proc/sys/kernel/random/entropy_avail
1168

though still far from the ideal ~3k+ bits.

The final piece to the puzzle is to run the aforementioned rngd daemon. For that we have to install rng-tools and enable the service:

# emerge rng-tools
# systemctl enable rngd.service
# systemctl start rngd.service

or if using openrc:

# rc-update add rngd
# /etc/init.d/rngd start

The default configuration for the daemon will do the right thing. Checking available entropy now shows plenty of random bits available even if heavily used:

$ cat /proc/sys/kernel/random/entropy_avail
3397

Note that the maxmium size for the kernel entropy pool is 4096 bits, and this is sufficient for everything. What really matters is how fast this pool is replenished when read from (a.k.a. what is the bitrate we can read from /dev/random).

What is the quality of the RNG?

While the definition for what a random number sequence is fairly straightforward, testing whether a finite number sequence produced by and RNG is truly random is a more complicated topic. I will not pretend to understand all the math behind it, however the author of the ThinAir PRNG library has a pretty good writeup on the characteristics of random number sequences, and their testing.

Checking the quality of the RNG is usually done by collecting a significant amount of random bits and then running a variety of tests against the number sequence. To evaluate the quality of my random numbers I followed in the footsteps of Die Raven Wiki.

Test setup

The machine used in question is an Alienware Steam Machine from 2016. The specs are:

Component Type
CPU Intel(R) Core(TM) i7-4785T CPU @ 2.20GHz
Graphics Nvidia GeForce GTX 860M 2GB GDDR5 RAM
RAM 16GB (2x8GB Corsair Vengeance DDR3L@-1600) RAM
Storage Intel 520 Series, 120GB SSD

It’s running Gentoo Linux with the following kernel at the time of the test:

$ uname -srp
Linux 5.3.7-gentoo Intel(R) Core(TM) i7-4785T CPU @ 2.20GHz

Additionally I’ve also run tests against numbers produced by the TPM 2.0 chip found in my Thinkpad T480 laptop, running the same kernel.

Testing tools

I’ve used the following tools to evaluate my random number sequences:

To install them on Gentoo run these commands:

# emerge rng-tools ent dieharder

The dieharder script used to generate the outputs:

#!/bin/bash

if [[ $# -lt 1 ]]; then
  echo "No input file provided"
  exit 1
fi

tests1=(1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 100 101 102)
tests2=(202 203 204 205 206 207 208 209)

dieharder -d 0 -g 201 -f $1 -D 1 -D 2 -D 4 -D 8 -D 16 -D 32 -D 64 -D 128 -D 256 > "${1}-output.txt"

for i in "${tests1[@]}";
  do dieharder -d $i -g 201 -f $1 | tail -n 1 >> "${1}-output.txt" ;
done

dieharder -d 200 -n 12 -g 201 -f $1 | tail -n 1 >> "${1}-output.txt"

for i in {1..4};
  do dieharder -d 201 -p 2500 -g 201 -n$i -f $1 | tail -n 1 >> "${1}-output.txt"
done

for i in "${tests2[@]}";
  do dieharder -d $i -g 201 -f $1 | tail -n 1 >> "${1}-output.txt" ;
done

It’s important to understand that any finite random number sequence has a slight chance to be “weak” on such tests due to the statistical nature of random numbers and having a finite sequence. Testing random number generators is best done on longer sequences, and in critical environments periodically, to get higher confidence in the correctness of the RNG.

And finally a simple script to run the infnoise plotting:

#!/bin/sh
#
# Source for plotting scripts: https://github.com/13-37-org/infnoise/tree/master/tests/plots
# Place the plotting scripts into the same directory as this script,
# dev-python/numpy and dev-python/matplotlib are required for them to run.
#

function makePlots {
  python colormap.py $1
  python scatterplot.py $1
}

if [[ $# -lt 1 ]]; then
  echo "No input file provided"
  exit 1
fi

makePlots $1

Gathering data and running the tests

I’ve gathered 512MiB data for each test using different configuration and sources. These sequences shall be long enough to test if any of the generators have obvious biases.

Without the ChaosKey plugged in, I collected a random sequence from /dev/random only with rngd enabled (effectively RDRAND produced numbers), since the entropy is otherwise so low that gathering random numbers from /dev/random (at 2.1 bits/s) would take way too long.

$ dd if=/dev/random of=random-rdrand.bin bs=256 count=2097152 iflag=fullblock
2097152+0 records in
2097152+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 257.451 s, 2.1 MB/s
$ dd if=/dev/urandom of=urandom.bin bs=256 count=2097152 iflag=fullblock
2097152+0 records in
2097152+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 7.61576 s, 70.5 MB/s

Then I plugged in the ChaosKey and gathered from:

  • /dev/hwrng: random number sequence produced by the ChaosKey (rngd has no effect on this),
  • /dev/random: random number sequence produced by all entropy sources,
  • /dev/urandom: pseudorandom number sequence produced by the Linux kernel with the help of the entropy pool.
# dd if=/dev/hwrng of=hwrng-chaos.bin bs=256 count=2097152 iflag=fullblock
2097152+0 records in
2097152+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 61680.9 s, 8.5 kB/s
$ dd if=/dev/random of=random-chaos.bin bs=256 count=2097152 iflag=fullblock
2097152+0 records in
2097152+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 1037.93 s, 517 kB/s
$ dd if=/dev/urandom of=urandom-chaos.bin bs=256 count=2097152 iflag=fullblock
2097152+0 records in
2097152+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 7.58345 s, 70.8 MB/s

Finally I’ve collected a sequence from the TPM 2.0 chip on my laptop.

# dd if=/dev/hwrng of=hwrng-tpm.bin bs=256 count=2097152 iflag=fullblock
2097152+0 records in
2097152+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 67206.2 s, 8.0 kB/s

Running the tests is fairly straightforward after this. For each binary mentioned above the following commands need to be executed (assuming scripts are located in the same directory as the test data):

$ cat <test_data>.bin | rngtest
$ ent <test_data>.bin
$ ./dieharder_test.sh <test_data>.bin
$ ./plot.sh <test_data>.bin

Understanding test ouput…

… for ‘rngtest’

This tool is roughly based on NIST’s statistical test suite for the validation of RNGs and PRNGs and tests for basic FIPS 140-2 compliance. Since the man page for rngtest lacks documentation on the tests, here is a TL;DR based on the aforementioned documentation, the source code, and some pointers by Warmcat:

This test suit will divide the input into 20k bit blocks and applies a set of tests. Since the sources are supposedly truly random, just because one block fails some test it does not mean it’s a “bad” block, as any bit pattern is equally likely as any other. As we cannot evaluate packets in isolation what we want to see is that the random sequence has no bias towards one type of error. The following tests are run:

  • Monobit: will look for 50% distribution of 0 and 1 bits in each block.
  • Poker: will look at the distribution of nibbles (consecutive 4bits, a.k.a. half-bytes). For each of the 5k nibbles in the test packet it maintains a count of occurrences of each nibble [0x0, …, 0xF], finally these counts are squared. The resulting number for each nibble must fall within the range of 1563176 - 1576928.
  • Run: A run is a series of consecutive 0 or 1 bits. It will count the number of runs of lengths 1 through 6, where runs longer than 6 bits are considered as 6. Counts are compared against a hard coded table to determine success or failure.
  • Long run: Similar to the run test, but here identical bit sequences of length 26 or more are searched for. For any 26 bits the chance for all of them being the same is 2 : 2^26 (once every 32Mbits). Given that the bit before the sequence has to be of the opposite value this gives us the final value of 2 : 2^27. For 20k bit sequences this brings us to the ideal value of 1/2^26 * 20000 = 0.00029802322387695 occurrence probability.
  • Continious run: Counts the occurrence of 32 bit patters being seen twice in a row. For every 4 bytes generated there is a 1 : 2^32 chance of having the same 4 bytes again. So the theoretical ideal value for this test is <number of input bits> / 32 / 2^32, so in this case where the input was 4294967296 bits long it comes to 0.03125.

… for ‘ent’

This tool’s website actually explains each test quite well, so I’m not going to repeat the details here, only provide some TL;DR notes for better understanding the already nice output of the program:

  • Entropy: we expect it to be 8bits per byte, meaning all the bits are random.
  • Compression: will try to compress the random number sequence. Truly random sequences cannot be compressed.
  • Chi-square test: intended for testing PRNGs mainly. Here a result is good if the percentages are in the range of 10%-90%, weak suspect if value is in the range of 90%-95% or 5%-10%, suspect if value is in range the of 95%-99% or 1%-5%, and almost certainly not random if the value is >99% or <1%.
  • Artihmetic mean: this is pretty much self explanatory, we want 127.5 bits for our sequence.
  • Monte Carlo value for π: this approximation converges slowly towards Pi, so a large sequence is required for high confidence results. We want an error as small as possible for the calculated value.
  • Serial Correlation Coefficient: This tests the independence of bytes on the previous value. We want no correlation, thus a value of 0 in an ideal case.

… for ‘dieharder’

This tool has a large set of other randomness tests, too long to describe here. For details I recommend visiting either Wikipedia’s Dieharder tests page or A study of entropy site.

Fortunately the output of Dieharder is easily human readable, with tests being marked as PASSED, WEAK, or FAILED. We want to see PASSED tests, though occasionally WEAK can occur, especially if the test sequence is not long enough. There should be not FAILED tests at all!

… for the plots

The colormap displays the square distribution and should show a “noisy” picture, where there are no visible clusters of pixels with the same colour.

The scatter plot will show correlation between values, if there are any. It should show no visible clustering of dots and they should be spread out randomly.

Evaluating the results

For the full output of the tests, please see the appendix at the bottom of the page.

The rngtest results do not show significant bias toward any type of the error, and thus all sources are passing the FIPS 140-2 tests with high probability.

On the ent tests the outputs pretty much speak for themselves. Essentially all sources pass with a good confidence yet again.

For dieharder tests we can see all random sources pass practically all tests. It’s worth noting that a few tests indicating WEAK are most likely caused by a statistical anomaly.

Finally the colormaps and scatter graphs don’t show obvious signs of correlation between the samples.

Overall we can say that all sources, with a high likelihood, produce quality random number sequences and shall be usable for all purposes, including secure cryptography.

Lessons

ChaosKey lived up to the expectations, and passed all tests with flying colours. Open source hardware can indeed be high quality and affordable!

Intel’s RDRAND instruction seems to be operating as intended as well, or more precisely: based on this small test it’s highly likely that it produces good random numbers. Others have gotten similar results when benchmarking Intel’s RDRAND. However there are no guarantees for the lack of subtle, hidden backdoors (i.e. via signal whitening), or simply bugs in the CPU’s random number generator. Since it’s practically impossible to find such issues, in high security environments, and for purists, it’s recommended to resolve this by installing additional good sources of randomness, that are also more easily verifiable.

Adding a TRNG will additionally make /dev/random provide a reasonable bit rate when reading the device, though still magnitudes slower than /dev/urandom. However these improved bit rates are sufficient to provide enough entropy to reseed the PRNG frequently, thus improving it’s quality.

TRNG or not, /dev/urandom generates high quality random number sequences, which means that one should always use /dev/urandom or equivalent kernel system call to get random numbers. The only exception is when initializing a PRNG, in which case the few hundred random bits shall be taken as a seed from /dev/random. TL;DR: The urandom generated sequences are good for practically all purposes!

Finally generating and testing randomness is not easy, and we can never really get 100% confidence on the correctness of such generators, just a very high one (unless we run the generator and the tests for all of eternity).

Appendix

Test output

rngtest

$ cat random-rdrand.bin | rngtest
rngtest 6.7
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 4294967296
rngtest: FIPS 140-2 successes: 214610
rngtest: FIPS 140-2 failures: 138
rngtest: FIPS 140-2(2001-10-10) Monobit: 20
rngtest: FIPS 140-2(2001-10-10) Poker: 21
rngtest: FIPS 140-2(2001-10-10) Runs: 40
rngtest: FIPS 140-2(2001-10-10) Long run: 57
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=1.552; avg=15.717; max=18.626)Gibits/s
rngtest: FIPS tests speed: (min=41.374; avg=165.707; max=179.939)Mibits/s
rngtest: Program run time: 24993088 microseconds

$ cat urandom.bin | rngtest
rngtest 6.7
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 4294967296
rngtest: FIPS 140-2 successes: 214575
rngtest: FIPS 140-2 failures: 173
rngtest: FIPS 140-2(2001-10-10) Monobit: 24
rngtest: FIPS 140-2(2001-10-10) Poker: 20
rngtest: FIPS 140-2(2001-10-10) Runs: 70
rngtest: FIPS 140-2(2001-10-10) Long run: 63
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=1.330; avg=14.752; max=18.626)Gibits/s
rngtest: FIPS tests speed: (min=47.446; avg=157.727; max=178.257)Mibits/s
rngtest: Program run time: 26261987 microseconds

$ cat hwrng-chaos.bin | rngtest
rngtest 6.7
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 4294967296
rngtest: FIPS 140-2 successes: 214585
rngtest: FIPS 140-2 failures: 163
rngtest: FIPS 140-2(2001-10-10) Monobit: 24
rngtest: FIPS 140-2(2001-10-10) Poker: 21
rngtest: FIPS 140-2(2001-10-10) Runs: 63
rngtest: FIPS 140-2(2001-10-10) Long run: 58
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=1.035; avg=14.315; max=18.626)Gibits/s
rngtest: FIPS tests speed: (min=91.699; avg=153.718; max=163.021)Mibits/s
rngtest: Program run time: 26948568 microseconds

$ cat random-chaos.bin | rngtest
rngtest 6.7
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 4294967296
rngtest: FIPS 140-2 successes: 214570
rngtest: FIPS 140-2 failures: 178
rngtest: FIPS 140-2(2001-10-10) Monobit: 24
rngtest: FIPS 140-2(2001-10-10) Poker: 21
rngtest: FIPS 140-2(2001-10-10) Runs: 72
rngtest: FIPS 140-2(2001-10-10) Long run: 63
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=1428571428.571; avg=15224685843.923; max=0.000)bits/s
rngtest: FIPS tests speed: (min=85.531; avg=153.760; max=173.395)Mibits/s
rngtest: Program run time: 26943057 microseconds

$ cat urandom-chaos.bin | rngtest
rngtest 6.7
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 4294967296
rngtest: FIPS 140-2 successes: 214577
rngtest: FIPS 140-2 failures: 171
rngtest: FIPS 140-2(2001-10-10) Monobit: 21
rngtest: FIPS 140-2(2001-10-10) Poker: 26
rngtest: FIPS 140-2(2001-10-10) Runs: 62
rngtest: FIPS 140-2(2001-10-10) Long run: 62
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=1538461538.462; avg=17342442743.160; max=0.000)bits/s
rngtest: FIPS tests speed: (min=36.469; avg=168.899; max=178.257)Mibits/s
rngtest: Program run time: 24519444 microseconds

$ cat hwrng-tpm.bin | rngtest
rngtest 6.7
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 4294967296
rngtest: FIPS 140-2 successes: 214595
rngtest: FIPS 140-2 failures: 153
rngtest: FIPS 140-2(2001-10-10) Monobit: 20
rngtest: FIPS 140-2(2001-10-10) Poker: 18
rngtest: FIPS 140-2(2001-10-10) Runs: 67
rngtest: FIPS 140-2(2001-10-10) Long run: 49
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=1.552; avg=15.897; max=18.626)Gibits/s
rngtest: FIPS tests speed: (min=36.680; avg=166.714; max=178.257)Mibits/s
rngtest: Program run time: 24840710 microseconds

ent

$ ent random-rdrand.bin
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 536870912 byte file by 0 percent.

Chi square distribution for 536870912 samples is 250.81, and randomly
would exceed this value 56.24 percent of the times.

Arithmetic mean value of data bytes is 127.4994 (127.5 = random).
Monte Carlo value for Pi is 3.141644162 (error 0.00 percent).
Serial correlation coefficient is -0.000023 (totally uncorrelated = 0.0).

$ ent urandom.bin
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 536870912 byte file by 0 percent.

Chi square distribution for 536870912 samples is 235.98, and randomly
would exceed this value 79.79 percent of the times.

Arithmetic mean value of data bytes is 127.5009 (127.5 = random).
Monte Carlo value for Pi is 3.141426366 (error 0.01 percent).
Serial correlation coefficient is 0.000041 (totally uncorrelated = 0.0).

$ ent hwrng-chaos.bin
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 536870912 byte file by 0 percent.

Chi square distribution for 536870912 samples is 266.64, and randomly
would exceed this value 29.56 percent of the times.

Arithmetic mean value of data bytes is 127.5047 (127.5 = random).
Monte Carlo value for Pi is 3.141215053 (error 0.01 percent).
Serial correlation coefficient is 0.000040 (totally uncorrelated = 0.0).

$ ent random-chaos.bin
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 536870912 byte file by 0 percent.

Chi square distribution for 536870912 samples is 234.67, and randomly
would exceed this value 81.47 percent of the times.

Arithmetic mean value of data bytes is 127.4989 (127.5 = random).
Monte Carlo value for Pi is 3.141590249 (error 0.00 percent).
Serial correlation coefficient is -0.000072 (totally uncorrelated = 0.0).

$ ent urandom-chaos.bin
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 536870912 byte file by 0 percent.

Chi square distribution for 536870912 samples is 257.98, and randomly
would exceed this value 43.60 percent of the times.

Arithmetic mean value of data bytes is 127.4984 (127.5 = random).
Monte Carlo value for Pi is 3.141471606 (error 0.00 percent).
Serial correlation coefficient is -0.000056 (totally uncorrelated = 0.0).

$ ent hwrng-tpm.bin
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 536870912 byte file by 0 percent.

Chi square distribution for 536870912 samples is 278.66, and randomly
would exceed this value 14.77 percent of the times.

Arithmetic mean value of data bytes is 127.5030 (127.5 = random).
Monte Carlo value for Pi is 3.141418901 (error 0.01 percent).
Serial correlation coefficient is -0.000055 (totally uncorrelated = 0.0).

dieharder

$ ./dieharder_test.sh random-rdrand.bin
$ cat random-rdrand.bin-output.txt
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |           filename             |
 file_input_raw|               random-rdrand.bin|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.89832521|  PASSED
      diehard_operm5|   0|   1000000|     100|0.08208992|  PASSED
  diehard_rank_32x32|   0|     40000|     100|0.65934458|  PASSED
    diehard_rank_6x8|   0|    100000|     100|0.16125477|  PASSED
   diehard_bitstream|   0|   2097152|     100|0.79996422|  PASSED
        diehard_opso|   0|   2097152|     100|0.28528645|  PASSED
        diehard_oqso|   0|   2097152|     100|0.18271989|  PASSED
         diehard_dna|   0|   2097152|     100|0.36204925|  PASSED
diehard_count_1s_str|   0|    256000|     100|0.66759183|  PASSED
diehard_count_1s_byt|   0|    256000|     100|0.25068107|  PASSED
 diehard_parking_lot|   0|     12000|     100|0.30484250|  PASSED
    diehard_2dsphere|   2|      8000|     100|0.36514382|  PASSED
    diehard_3dsphere|   3|      4000|     100|0.55996690|  PASSED
     diehard_squeeze|   0|    100000|     100|0.00446759|   WEAK
        diehard_runs|   0|    100000|     100|0.43310269|  PASSED
       diehard_craps|   0|    200000|     100|0.53532635|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     100|0.00051971|   WEAK
         sts_monobit|   1|    100000|     100|0.48127513|  PASSED
            sts_runs|   2|    100000|     100|0.28197997|  PASSED
          sts_serial|  16|    100000|     100|0.15333370|  PASSED
         rgb_bitdist|  12|    100000|     100|0.72886683|  PASSED
rgb_minimum_distance|   1|     10000|    2500|0.02451671|  PASSED
rgb_minimum_distance|   2|     10000|    2500|0.84265872|  PASSED
rgb_minimum_distance|   3|     10000|    2500|0.42912783|  PASSED
rgb_minimum_distance|   4|     10000|    2500|0.69080250|  PASSED
    rgb_permutations|   5|    100000|     100|0.57869062|  PASSED
      rgb_lagged_sum|   0|   1000000|     100|0.25283443|  PASSED
     rgb_kstest_test|   0|     10000|    1000|0.01951603|  PASSED
     dab_bytedistrib|   0|  51200000|       1|0.02157911|  PASSED
             dab_dct| 256|     50000|       1|0.66858518|  PASSED
        dab_filltree|  32|  15000000|       1|0.37117371|  PASSED
       dab_filltree2|   1|   5000000|       1|0.07838114|  PASSED
        dab_monobit2|  12|  65000000|       1|0.17627272|  PASSED

$ ./dieharder_test.sh urandom.bin
$ cat urandom.bin-output.txt
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |           filename             |
 file_input_raw|                     urandom.bin|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.02951714|  PASSED
      diehard_operm5|   0|   1000000|     100|0.95600867|  PASSED
  diehard_rank_32x32|   0|     40000|     100|0.80132252|  PASSED
    diehard_rank_6x8|   0|    100000|     100|0.15599997|  PASSED
   diehard_bitstream|   0|   2097152|     100|0.84493027|  PASSED
        diehard_opso|   0|   2097152|     100|0.89811025|  PASSED
        diehard_oqso|   0|   2097152|     100|0.55885937|  PASSED
         diehard_dna|   0|   2097152|     100|0.46413870|  PASSED
diehard_count_1s_str|   0|    256000|     100|0.77471662|  PASSED
diehard_count_1s_byt|   0|    256000|     100|0.74800777|  PASSED
 diehard_parking_lot|   0|     12000|     100|0.20530715|  PASSED
    diehard_2dsphere|   2|      8000|     100|0.88640604|  PASSED
    diehard_3dsphere|   3|      4000|     100|0.30179786|  PASSED
     diehard_squeeze|   0|    100000|     100|0.37912966|  PASSED
        diehard_runs|   0|    100000|     100|0.14673629|  PASSED
       diehard_craps|   0|    200000|     100|0.07100177|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     100|0.01867227|  PASSED
         sts_monobit|   1|    100000|     100|0.40139699|  PASSED
            sts_runs|   2|    100000|     100|0.56069871|  PASSED
          sts_serial|  16|    100000|     100|0.75983869|  PASSED
         rgb_bitdist|  12|    100000|     100|0.68560977|  PASSED
rgb_minimum_distance|   1|     10000|    2500|0.32675636|  PASSED
rgb_minimum_distance|   2|     10000|    2500|0.18164402|  PASSED
rgb_minimum_distance|   3|     10000|    2500|0.41663203|  PASSED
rgb_minimum_distance|   4|     10000|    2500|0.19212307|  PASSED
    rgb_permutations|   5|    100000|     100|0.56857885|  PASSED
      rgb_lagged_sum|   0|   1000000|     100|0.17068622|  PASSED
     rgb_kstest_test|   0|     10000|    1000|0.47860303|  PASSED
     dab_bytedistrib|   0|  51200000|       1|0.18248960|  PASSED
             dab_dct| 256|     50000|       1|0.47898501|  PASSED
        dab_filltree|  32|  15000000|       1|0.49195880|  PASSED
       dab_filltree2|   1|   5000000|       1|0.66055138|  PASSED
        dab_monobit2|  12|  65000000|       1|0.12722207|  PASSED

$ ./dieharder_test.sh hwrng-chaos.bin
$ cat hwrng-chaos.bin-output.txt
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |           filename             |
 file_input_raw|                 hwrng-chaos.bin|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.94347762|  PASSED
      diehard_operm5|   0|   1000000|     100|0.08449002|  PASSED
  diehard_rank_32x32|   0|     40000|     100|0.31134778|  PASSED
    diehard_rank_6x8|   0|    100000|     100|0.24045295|  PASSED
   diehard_bitstream|   0|   2097152|     100|0.94528267|  PASSED
        diehard_opso|   0|   2097152|     100|0.12091403|  PASSED
        diehard_oqso|   0|   2097152|     100|0.88661958|  PASSED
         diehard_dna|   0|   2097152|     100|0.14785487|  PASSED
diehard_count_1s_str|   0|    256000|     100|0.75613811|  PASSED
diehard_count_1s_byt|   0|    256000|     100|0.96139517|  PASSED
 diehard_parking_lot|   0|     12000|     100|0.28167383|  PASSED
    diehard_2dsphere|   2|      8000|     100|0.56018511|  PASSED
    diehard_3dsphere|   3|      4000|     100|0.82539881|  PASSED
     diehard_squeeze|   0|    100000|     100|0.30944204|  PASSED
        diehard_runs|   0|    100000|     100|0.28614328|  PASSED
       diehard_craps|   0|    200000|     100|0.70998556|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     100|0.23055436|  PASSED
         sts_monobit|   1|    100000|     100|0.28318593|  PASSED
            sts_runs|   2|    100000|     100|0.75002707|  PASSED
          sts_serial|  16|    100000|     100|0.37454492|  PASSED
         rgb_bitdist|  12|    100000|     100|0.40839478|  PASSED
rgb_minimum_distance|   1|     10000|    2500|0.50247052|  PASSED
rgb_minimum_distance|   2|     10000|    2500|0.27501306|  PASSED
rgb_minimum_distance|   3|     10000|    2500|0.12317861|  PASSED
rgb_minimum_distance|   4|     10000|    2500|0.44578151|  PASSED
    rgb_permutations|   5|    100000|     100|0.24312771|  PASSED
      rgb_lagged_sum|   0|   1000000|     100|0.81744092|  PASSED
     rgb_kstest_test|   0|     10000|    1000|0.09982715|  PASSED
     dab_bytedistrib|   0|  51200000|       1|0.71758532|  PASSED
             dab_dct| 256|     50000|       1|0.45795524|  PASSED
        dab_filltree|  32|  15000000|       1|0.46420462|  PASSED
       dab_filltree2|   1|   5000000|       1|0.10955427|  PASSED
        dab_monobit2|  12|  65000000|       1|0.66620684|  PASSED

$ ./dieharder_test.sh random-chaos.bin
$ cat random-chaos.bin-output.txt
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |           filename             |
 file_input_raw|                random-chaos.bin|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.63439981|  PASSED
      diehard_operm5|   0|   1000000|     100|0.64707022|  PASSED
  diehard_rank_32x32|   0|     40000|     100|0.51902140|  PASSED
    diehard_rank_6x8|   0|    100000|     100|0.14166896|  PASSED
   diehard_bitstream|   0|   2097152|     100|0.88490457|  PASSED
        diehard_opso|   0|   2097152|     100|0.01734895|  PASSED
        diehard_oqso|   0|   2097152|     100|0.15304141|  PASSED
         diehard_dna|   0|   2097152|     100|0.68317129|  PASSED
diehard_count_1s_str|   0|    256000|     100|0.04709180|  PASSED
diehard_count_1s_byt|   0|    256000|     100|0.49978440|  PASSED
 diehard_parking_lot|   0|     12000|     100|0.21450471|  PASSED
    diehard_2dsphere|   2|      8000|     100|0.15857683|  PASSED
    diehard_3dsphere|   3|      4000|     100|0.85439232|  PASSED
     diehard_squeeze|   0|    100000|     100|0.79126828|  PASSED
        diehard_runs|   0|    100000|     100|0.18190665|  PASSED
       diehard_craps|   0|    200000|     100|0.86038570|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     100|0.35219912|  PASSED
         sts_monobit|   1|    100000|     100|0.88554862|  PASSED
            sts_runs|   2|    100000|     100|0.36675893|  PASSED
          sts_serial|  16|    100000|     100|0.63928514|  PASSED
         rgb_bitdist|  12|    100000|     100|0.81378099|  PASSED
rgb_minimum_distance|   1|     10000|    2500|0.41597592|  PASSED
rgb_minimum_distance|   2|     10000|    2500|0.06594598|  PASSED
rgb_minimum_distance|   3|     10000|    2500|0.96240914|  PASSED
rgb_minimum_distance|   4|     10000|    2500|0.34780042|  PASSED
    rgb_permutations|   5|    100000|     100|0.99906765|   WEAK
      rgb_lagged_sum|   0|   1000000|     100|0.58025653|  PASSED
     rgb_kstest_test|   0|     10000|    1000|0.11530853|  PASSED
     dab_bytedistrib|   0|  51200000|       1|0.37250649|  PASSED
             dab_dct| 256|     50000|       1|0.68583749|  PASSED
        dab_filltree|  32|  15000000|       1|0.49725081|  PASSED
       dab_filltree2|   1|   5000000|       1|0.79252396|  PASSED
        dab_monobit2|  12|  65000000|       1|0.99646598|   WEAK

$ ./dieharder_test.sh urandom-chaos.bin
$ cat urandom-chaos.bin-output.txt
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |           filename             |
 file_input_raw|               urandom-chaos.bin|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.64578141|  PASSED
      diehard_operm5|   0|   1000000|     100|0.85386733|  PASSED
  diehard_rank_32x32|   0|     40000|     100|0.97850835|  PASSED
    diehard_rank_6x8|   0|    100000|     100|0.70628574|  PASSED
   diehard_bitstream|   0|   2097152|     100|0.82293393|  PASSED
        diehard_opso|   0|   2097152|     100|0.00209466|   WEAK
        diehard_oqso|   0|   2097152|     100|0.87850750|  PASSED
         diehard_dna|   0|   2097152|     100|0.34213071|  PASSED
diehard_count_1s_str|   0|    256000|     100|0.90522624|  PASSED
diehard_count_1s_byt|   0|    256000|     100|0.55758920|  PASSED
 diehard_parking_lot|   0|     12000|     100|0.76094232|  PASSED
    diehard_2dsphere|   2|      8000|     100|0.27144693|  PASSED
    diehard_3dsphere|   3|      4000|     100|0.88986005|  PASSED
     diehard_squeeze|   0|    100000|     100|0.40147383|  PASSED
        diehard_runs|   0|    100000|     100|0.10093985|  PASSED
       diehard_craps|   0|    200000|     100|0.54544412|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     100|0.00002515|   WEAK
         sts_monobit|   1|    100000|     100|0.78179912|  PASSED
            sts_runs|   2|    100000|     100|0.34365207|  PASSED
          sts_serial|  16|    100000|     100|0.73412434|  PASSED
         rgb_bitdist|  12|    100000|     100|0.70834165|  PASSED
rgb_minimum_distance|   1|     10000|    2500|0.53634411|  PASSED
rgb_minimum_distance|   2|     10000|    2500|0.08815324|  PASSED
rgb_minimum_distance|   3|     10000|    2500|0.55438524|  PASSED
rgb_minimum_distance|   4|     10000|    2500|0.56285509|  PASSED
    rgb_permutations|   5|    100000|     100|0.15686487|  PASSED
      rgb_lagged_sum|   0|   1000000|     100|0.88690513|  PASSED
     rgb_kstest_test|   0|     10000|    1000|0.77382830|  PASSED
     dab_bytedistrib|   0|  51200000|       1|0.78481508|  PASSED
             dab_dct| 256|     50000|       1|0.02579977|  PASSED
        dab_filltree|  32|  15000000|       1|0.15054423|  PASSED
       dab_filltree2|   1|   5000000|       1|0.08594208|  PASSED
        dab_monobit2|  12|  65000000|       1|0.12453405|  PASSED

$ ./dieharder_test.sh hwrng-tpm.bin
$ cat hwrng-tpm.bin-output.txt
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |           filename             |
 file_input_raw|                   hwrng-tpm.bin|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.59066550|  PASSED
      diehard_operm5|   0|   1000000|     100|0.63700972|  PASSED
  diehard_rank_32x32|   0|     40000|     100|0.97949363|  PASSED
    diehard_rank_6x8|   0|    100000|     100|0.85081321|  PASSED
   diehard_bitstream|   0|   2097152|     100|0.52582002|  PASSED
        diehard_opso|   0|   2097152|     100|0.51263283|  PASSED
        diehard_oqso|   0|   2097152|     100|0.96757860|  PASSED
         diehard_dna|   0|   2097152|     100|0.91158018|  PASSED
diehard_count_1s_str|   0|    256000|     100|0.11438815|  PASSED
diehard_count_1s_byt|   0|    256000|     100|0.98165405|  PASSED
 diehard_parking_lot|   0|     12000|     100|0.96749733|  PASSED
    diehard_2dsphere|   2|      8000|     100|0.00042059|   WEAK
    diehard_3dsphere|   3|      4000|     100|0.96064379|  PASSED
     diehard_squeeze|   0|    100000|     100|0.13259882|  PASSED
        diehard_runs|   0|    100000|     100|0.77902266|  PASSED
       diehard_craps|   0|    200000|     100|0.25547264|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     100|0.01407933|  PASSED
         sts_monobit|   1|    100000|     100|0.47681497|  PASSED
            sts_runs|   2|    100000|     100|0.69036528|  PASSED
          sts_serial|  16|    100000|     100|0.97237627|  PASSED
         rgb_bitdist|  12|    100000|     100|0.98545170|  PASSED
rgb_minimum_distance|   1|     10000|    2500|0.24054728|  PASSED
rgb_minimum_distance|   2|     10000|    2500|0.98618992|  PASSED
rgb_minimum_distance|   3|     10000|    2500|0.95612009|  PASSED
rgb_minimum_distance|   4|     10000|    2500|0.82816640|  PASSED
    rgb_permutations|   5|    100000|     100|0.50478812|  PASSED
      rgb_lagged_sum|   0|   1000000|     100|0.21081058|  PASSED
     rgb_kstest_test|   0|     10000|    1000|0.56474035|  PASSED
     dab_bytedistrib|   0|  51200000|       1|0.11140313|  PASSED
             dab_dct| 256|     50000|       1|0.08429594|  PASSED
        dab_filltree|  32|  15000000|       1|0.02116471|  PASSED
       dab_filltree2|   1|   5000000|       1|0.35667382|  PASSED
        dab_monobit2|  12|  65000000|       1|0.69449323|  PASSED

plots

$ for f in *.bin; do ./plot.sh $f; done

Other Intel RDRAND bechmarks


Content