Hardware Random Number Generator with Arduino
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
compiled-files
photos Add avrhwrng v2rev1 whole pic Jul 11, 2016
presentations/ipsj-iots2015
references
schematics
sphinx-doc
LICENSE Add MIT LICENSE Jul 12, 2015
Makefile Major reorganization of the files Jun 1, 2016
README.md
avrhwrng.c

README.md

Hardware Random Number Generator for Arduino

This repository contains a sample code with avr-gcc and the schematics for a shield (extended piece of hardware) for Arduino Duemilanove / Arduino UNO.

Note: The code is solely written in C and avr-libc; no Arduino framework.

Hardware

The current circuit version is called v2rev1. The v2rev1 consists of two independent noise generator circuits, and the outputs are amplified to the CMOS digital levels, which are connected to ATmega168/328P's input pins (PD6/PD7, or Pin 6/7).

The latest fix of v2rev1fix1 adds a 10uF capacitor to the power supply of the noise diode circuit as a part of the voltage ripple filter, so that the noise diode circuit can accept the output of a DC-DC converter such as Maxim MAX662A.

Schematics and photos are available in schematics/ and photos/ directories, respectively.

Firmware

  • The current version is called v2rev1.
  • The v2rev1 gives ~10kbytes/sec of filtered output.

How the firmware works

The Timer 0 of ATmega168/328P is set to CTC mode with the closest larger value to the theoretical limit, 46 machine cycles or 2.875 microseconds. The theoretical limit of the speed is 352000bps or 2.84 microseconds, which is equal to 11000 bytes * 8 bits/byte * 2 (for von-Neumann test) * 2 (for XORing byte filter). Sampling in an equal timing improves the quality of the obtained randomness.

The MCU runs the following program without any hardware interrupt as an infinite loop:

  • Wait for the Timer 0 compare match happens, so that the sampling interval will not exceed the value given to Timer 0
  • Sample the pin inputs of PD6 and PD7
  • Treat the sampled two-bit pair into two independent bit streams
  • Apply the von Neumann algorithm for two consecutive sampled bits independently for each bit stream
  • Accumulate valid bits from two bit streams into single byte stream
  • Filter a two-byte pair from the byte stream by XORing with each other
  • Wait for finishing the USART0 transmission (serial rate: running in 111111bps for 115200bps)
  • Send each filtered byte to USART0 (non-blocking)
  • Go to the top and do it all over again

Random number stream is obtained through the tty device of Arduino as a binary byte stream.

The current sampling strategy of only applying von Neumann algorithm independently for each bit stream and mixing the output into single byte stream is chosen for reducing statistical errors.

The filtering scheme in a diagram:

Noise gen at PD7 --- von Neumann filter 1
                             |
             two bit streams mixed into one stream - two-byte XOR filter - output
                             |
Noise gen at PD6 --- von Neumann filter 2 

The code runs either on ATmega168 or ATmega328P (only a vector address difference). Tested both on Arduino Duemilanove and Arduino UNO R3 boards.

Documentation

  • See presentations/ipsj-iots2015/ for the set of the documentation (PDF paper in Japanese, slides in English) of my presentation at IPSJ IOTS2015 Symposium on 27-NOV-2015.
  • 日本語での解説は技術評論社Software Design誌2016年9月号pp. 96-101「乱数を使いこなす(2):物理乱数ハードウェアを作る」をご参照ください

How to compile

# Use GNU Make (gmake on FreeBSD)
make

how to write the image

Compiled files are in compiled-files directory.

For loading into an optiboot-ready device, use:

# for ATmega168 optiboot
# (for ATmega328p, change m168 to m328p)
avrdude -D -c arduino -p m168 -b 115200 -P /dev/cuport-name \
        -U flash:w:target-filename.hex

You need to configure the following fuse bits for a production image:

  • Set BODLEVEL to 2.7V (only BODLEVEL1 is programmed to '0')
  • Disable SPIEN (to prevent external programming)
  • Disable BOOTRST (boot from $0000)
  • Set the lock bit

Use the following command sequence for AVR Dragon with ATmega168:

# for ATmega168 AVR Dragon
avrdude -D -v -p m168 -c dragon_pp -P usb \
        -e -u -U lock:w:0xff:m \
        -U efuse:w:0xff:m -U hfuse:w:0xfd:m -U lfuse:w:0xff:m \
        -U flash:w:avrhwrng-v2rev1-ATmega168-20150925.hex \
        -U lock:w:0xef:m

Use the following command sequence for AVR Dragon with ATmega328p (the fuse bits are different from those of ATmega168):

# for ATmega328p AVR Dragon
# NOTE WELL: the fuse bits are different from those of ATmega168!
avrdude -D -v -p m328p -c dragon_pp -P usb \
        -e -u -U lock:w:0xff:m \
        -U efuse:w:0xfd:m -U hfuse:w:0xff:m -U lfuse:w:0xff:m \
        -U flash:w:avrhwrng-v2rev1-ATmega328p-20150925.hex \
        -U lock:w:0xef:m

Test results on Version 2

For the tagged binary v2rev1-20150925:

  • FIPS 140-2 failure rate: ~0.0008 (an example: 173 for 214992 blocks, tested by rngtest)
  • TestU01 Rabbit and Alphabit tests passed in most cases (~95%) on 1Mbit samples; 1432 failures detected out of 28700 tests (1 Rabbit, 6 Alphabit tests for each sample) performed on 4100 samples
  • Sampling rate: 2.875 us = ~347.8kHz
  • Output rate for v2rev1: ~10800bytes/sec = ~86.4kHz
  • Transfer rate from Arduino: 115200bps, 8-bit, no parity raw bytes

Notes

  • Compilation tested on: avr-gcc 4.9.2, OS X 10.10.5
  • Compilation tested on: avr-gcc 7.1.0, macOS 10.12.6
  • Different compilers may generate different binaries.
  • This program is compatible with optiboot bootloader.

Related tools

LICENSE

  • All AVR source code files are licensed by the MIT License.
  • All schematics files are licensed by CC-BY-4.0.

[End of README.md]