Netduino Powered True Random Number Generator (TRNG)

In software development, most often when we want to generate a random number we have to generate a Pseudo-random Number. However, there are times when you need a true random number, weather for cryptographic purposes or for lotteries. To generate true random numbers you need a True Random Number Generator (TRNG), which must be a piece of hardware. There are several on the market which use a variety of methods to generate their randomness. I used the circuit developed by Rob Seward, which uses avalanche noise between the two transistors… I’ll let Rob Seward explain it in his own words.

The two transistors with their bases touching create “avalanche noise in a reverse-biased PN junction.” This noise is amplified by the third transistor and sent across a voltage divider to Arduino. On the oscilloscope, the signal looks very fuzzy. In software, that randomness is converted into a stream of 1s and 0s.

Since I love my Netduino, and I love building cool stuff, I decided to build one of these for my Netduino.

 

The code for it is fairly straight forward

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace TRNG
{
public class Program
{
#region configuration
//Configuration
//8 Bits gives you an int output of 0-255
//16 bits gives you an int output of 0-65535
//32 bit gives you a stackoverflow. :)
private static int bits = 8;
//End Configuration
#endregion

#region ports
private static OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
private static AnalogInput in_port = new AnalogInput(Pins.GPIO_PIN_A0);
private static OutputPort _0led = new OutputPort(Pins.GPIO_PIN_D0, false);
private static OutputPort _1led = new OutputPort(Pins.GPIO_PIN_D1, false);
#endregion

#region bias removal stuff
private static int previous;
private static int flip_flop = 0;
#endregion

private static int calibration_value = 0;
private static string byt = "";

private static void Loop()
{
int d = in_port.Read();

if (d > calibration_value)
{
ExclusiveOr(1);
//byt = byt + "1";
_0led.Write(true);
Thread.Sleep(30);
_0led.Write(false);
}
else
{
ExclusiveOr(0);
//byt = byt + "0";
_1led.Write(true);
Thread.Sleep(30);
_1led.Write(false);
}

if (byt.Length == bits)
{
Output();
}
}
private static void Calibrate()
{
DateTime start = DateTime.Now;
TimeSpan ts = DateTime.Now - start;
int count = 0;
int total = 0;
//Making this a bit lager may, or may not, provide better results.
while (count < 10000)
{
total += in_port.Read();
count++;
//ts = DateTime.Now - start;
}
calibration_value = total / count;
BlinkLed();
return;
}
private static void vonNeumann(int input)
{
if (input != previous)
{
byt = byt + input.ToString();
previous = (in_port.Read() > calibration_value) ? 0 : 1;
}
}
private static void ExclusiveOr(int input)
{
flip_flop = (flip_flop == 1) ? 0 : 1;
byt = byt + (flip_flop ^ input).ToString();
}
private static void BlinkLed()
{
led.Write(true);
Thread.Sleep(30);
led.Write(false);
}

public static void Main()
{
Calibrate();
//setup Von Neumann
previous = (in_port.Read() > calibration_value) ? 1 : 0;
Debug.Print("Loop");
while(true)
Loop();
}
private static void Output()
{
//Dont have an LCD to output to yet...
Debug.Print(byt + " = " + ParseBinary(byt).ToString());
byt = "";
}
public static long ParseBinary(string input)
{
//Thanks to Jon Skeet for this one http://stackoverflow.com/questions/4281649/convert-binary-to-int-without-convert-toint32/4282972#4282972

// Count up instead of down - it doesn't matter which way you do it
long output = 0;
for (int i = 0; i < input.Length; i++)
{
if (input[i] == '1')
{
output |= 1 << (input.Length - i - 1);
}
}
return output;
}
}
}

The first thing we do is to calibrate the device, because as the device ages the output can drift a bit. We read the values from the ADC 10,000 times and average the readings, which gives us our middle point, anytime we read a value higher than this, we will make it a 1, and when we read lower it is a 0.  We can use this to create either numbers or letters, since its simply a binary stream. It is a good idea to have some filtering of the output and I have implemented 2 methods to do that vonNeumann and ExclusiveOr. The vonNeumann provides the best results, however I find that in most cases I don’t need to use it. Your results will vary based on how noisy your environment is, I find that when I head out on the lake the numbers are far more stable then when I’m at home or even just in town. I could imagine that around large motors (such as those in factories) you will find more noise in your output.

The PCB that resulted from this design is available for purchase,I may make up a quick kit and make that available.

Leave a Reply

Your email address will not be published. Required fields are marked *