The Raspberry Pi (A/A+/B/B+/and 2) includes a hardware based random number generator that promises to provide the fastest, best source for the typical users to obtain cryptographic quality random numbers in an extremely small portable package.
The following steps should be performed to get the hardware random number generator up and running:
- Install the random number generator tools (sudo apt-get install rng-tools)
- Add the hwrng module to the boot process (add line ‘bcm2708-rng’ to file /etc/modules)
- Reboot the machine
- /dev/hwrng is now available for reading (root access only)
- sudo chmod a+r /dev/hwrng (gives user lever read access). This only stays until machine rebooted!
- To make the change permanent, make the following change in the /etc/rc.local file:
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
# ADD this line just above the exit 0 command
chmod a+r /dev/hwrng
exit 0
One way to generate a 1 megabyte file with random numbers (bytes) is to use the following command:
dd if=/dev/hwrng of=hwrng-test-data.bin bs=1024 count=1024
Testing
I used the following dd command on a pi to collect 4GB of data from its internal hardware random number generator.
dd bs=1024 count=4194304 if=/dev/hwrng of=hwrng.01.bin
I repeated this collection several times to have independent samples to perform analysis testing on. The detailed results of these tests are here:
As you can see from the above detailed analysis of the samples, the data behaves exactly as we would expect a true random number generator to perform, it occasionally fails some tests, but those failures are not duplicated on subsequent samples indicating the failures are just examples of random chance as one would expect. Overall the built in hardware random generator on the Raspberry Pi appears to perform quite well, and at 1 million bits per second is likely the most affordable true random number generator available to the general public.
Using the generator
The dd command works well for creating a binary file of random numbers; however, that is less than useful for most applications. Since I am in the process of setting up a Pi Cluster, I thought it would be nice to create a class to encapsulate obtaining random numbers in a variety of formats. Ultimately I am planning on producing software that will make use of the Raspberry Pi cluster to serve up random numbers to other machines that will make use of them for things like simulations. Until then here is the class that encapsulates the random number generator.
The class library to use the Raspberry Pi hardware random number generator is trng.h This class contains only four methods.
trng.random()
This method will return a full range (32 or 64 bit) random number depending upon the data type used. For integers, the number is self-explanatory. For real numbers (float and double) the value will be between 0 and 1.
trng.random(max)
This method will return a random number between 0 and the specified max.
trng.random(min,max)
This method will return a random number between min and max
trng.rnorm(mean, stdDev)
This method will return a random number with a gaussian (normal, bell-curve) distribution that has the specified mean and standard deviation, if and only if the data type is a float or a double. For all other types this method will always return a 0.
Example of how to use
// test-suite.cpp
//
// Copyright 2014 by Walter Anderson
//
// This program is a basic example and test-suite of how to use the
// trng class on a Raspberry Pi to obtain true random numbers in a
// variety of forms.
//
// This is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// It is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Entropy. If not, see <http://www.gnu.org/licenses/>.
#include <iostream>
#include <iomanip>
#include "trng.h"
using namespace std;
int main(int argc, char *argv[])
{
cout << "Basic tests of the Raspberry Pi trng class\n";
cout << setfill(' ') << setw(10) << dec;
trng<unsigned int> rng_int;
cout << "\n32-bit unsigned integers\n\ttrng<unsigned int> rng\n";
cout << "\trng.random()\t" << rng_int.random() << "\n";
cout << "\trng.random(10)\t" << rng_int.random(10) << "\n";
cout << "\trng.random(256)\t" << rng_int.random(256) << "\n";
cout << "\trng.random(64K)\t" << rng_int.random(65536) << "\n";
cout << "\trng.random(1,7)\t" << rng_int.random(1,7) << "\n";
cout << setfill(' ') << setw(20) << dec;
trng<unsigned long long> rng_ull;
cout << "\n64-bit unsigned integers\n\ttrng<unsigned long long> rng\n";
cout << "\trng.random()\t\t\t" << rng_ull.random() << "\n";
cout << "\trng.random(10000000000)\t\t" << rng_ull.random(10000000000) << "\n";
cout << "\trng.random(10000000000,70000000000)\t" << rng_ull.random(10000000000,70000000000) << "\n";
cout << setprecision(6) << setw(12);
trng<float> rng_float;
cout << "\nSingle precision real numbers\n\ttrng<float> rng\n";
cout << "\trng.random()\t\t" << rng_float.random() << "\n";
cout << "\trng.random(100.0)\t" << rng_float.random(100.0) << "\n";
cout << "\trng.random(10.0,20.0)\t" << rng_float.random(10.0,20.0) << "\n";
cout << "\trng.random(-1.0,1.0)\t" << rng_float.random(-1.0,1.0) << "\n";
cout << "\trng.rnorm(100.0,10.0)\t" << rng_float.rnorm(100.0,10.0) << "\n";
cout << setprecision(16) << setw(24);
trng<double> rng_double;
cout << "\nDouble precision real numbers\n\ttrng<double> rng\n";
cout << "\trng.random()\t\t" << rng_double.random() << "\n";
cout << "\trng.random(100.0)\t" << rng_double.random(100.0) << "\n";
cout << "\trng.random(10.0,20.0)\t" << rng_double.random(10.0,20.0) << "\n";
cout << "\trng.random(-1.0,1.0)\t" << rng_double.random(-1.0,1.0) << "\n";
cout << "\trng.rnorm(100.0,10.0)\t" << rng_double.rnorm(100.0,10.0) << "\n";
return(0);
}
wandrson@PiClstr01 ~/Development/trng $ ./test-suite
Basic tests of the Raspberry Pi trng class
32-bit unsigned integers
trng<unsigned int> rng
rng.random() 363060944
rng.random(10) 6
rng.random(256) 167
rng.random(64K) 9549
rng.random(1,7) 1
64-bit unsigned integers
trng<unsigned long long> rng
rng.random() 18158521333103429368
rng.random(10000000000) 6185328474
rng.random(10000000000,70000000000) 20057500399
Single precision real numbers
trng<float> rng
rng.random() 0.875868
rng.random(100.0) 4.90507
rng.random(10.0,20.0) 16.9112
rng.random(-1.0,1.0) -0.918352
rng.rnorm(100.0,10.0) 105.194
Double precision real numbers
trng<double> rng
rng.random() 0.101364384401903
rng.random(100.0) 17.68870818557542
rng.random(10.0,20.0) 17.40012921593946
rng.random(-1.0,1.0) -0.2272936767514655
rng.rnorm(100.0,10.0) 112.4538963802969
wandrson@PiClstr01 ~/Development/trng $