Raspberry Pi internal hardware random number generator






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:
  1. Install the random number generator tools (sudo apt-get install rng-tools)
  2. Add the hwrng module to the boot process (add line 'bcm2708-rng' to file /etc/modules)
  3. Reboot the machine
  4. /dev/hwrng is now available for reading (root access only)
  5. sudo chmod a+r /dev/hwrng  (gives user lever read access).  This only stays until machine rebooted!
  6. 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);
}


This will produce something like the following output on a Raspberry Pi:

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 $

ċ
trng.h
(13k)
Walter Anderson,
Apr 19, 2014, 1:52 PM
Comments