proof-of-concept: generate random bits on LPC1768 using dueling clocks (systick and WDT/RTC)

Dependencies:   mbed

random bits from dueling clocks

Using dueling clocks to generate random bits is described by Walter Anderson at https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library

There are implementations for AVR(UNO etc.) and ARM-based (teensy) MCUs.

This mbed LPC1768 implementation uses systick clock versus the RTC crystal (32khz) as a source to the WDT timer. The LPC1768 WDT interrupt cannot be cleared, so this implementation generates the random bits when they are requested. The WDT scales the source clock by /4, so the random bit rate is about 8192 bits/second. If your board doesn't have a 32khz crystal, it is also possible to source the WDT from the 4 MHz IRC oscillator.

I collected several megabytes of random bits and they passed various random-bit testers (rngtest, ent, NIST's STS).

/media/uploads/manitou/mbed.png

Another mbed random bit generator using ADC noise and mixing with SHA256 is desribed at https://developer.mbed.org/users/Remco/notebook/secure-hardware-random-number-using-the-mbed and an mbed teensy 3.1 generator

One could also just use these generators to create a seed for a hash-based PRNG.

Some ARM chips have builtin hardware TRNG's (DUE, pyboard, Raspberry PI) and Intel Edison.

FYI, RNG data on other MCUs https://github.com/manitou48/DUEZoo/blob/master/RNGperf.txt

and Anderson's spreadsheet

https://docs.google.com/spreadsheet/pub?key=0AukiKiYKrSl9dHNIX19oZ0ZqNDc1RDNMa042SzhZT0E&output=html

Files at this revision

API Documentation at this revision

Comitter:
manitou
Date:
Sat Jul 25 15:27:38 2015 +0000
Commit message:
initial

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Jul 25 15:27:38 2015 +0000
@@ -0,0 +1,146 @@
+
+// random bits from systick and WDT
+// based on arduino/teensy Entropy lib
+// https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library
+// seems WDT ISR will only fire once, so check free-running WDT periodically
+// enable systick as free running 24-bit clock to beat against RTC crystal
+#include "mbed.h"
+
+Timer tmr;
+Serial pc(USBTX, USBRX);
+
+void kick() {
+    // restart WDT countdown
+    __disable_irq();
+    LPC_WDT->WDFEED = 0xAA;
+    LPC_WDT->WDFEED = 0x55;
+    __enable_irq();
+}
+
+void wdt_init() {
+    LPC_WDT->WDCLKSEL = 0x02;               // Set CLK src 0 IRC  1 PCLK   2 RTC
+    LPC_WDT->WDTC = 0xfffffff;    // max countdown
+    LPC_WDT->WDMOD = 0x01;  // enable but no reset
+    kick();
+}
+
+void systick_init() {
+    SysTick->LOAD = 0x123456;   // doesn't really matter
+    SysTick->VAL  = 0;
+    SysTick->CTRL  = 4 |  1; //CLKSOURCE=CPU clock | ENABLE
+}
+
+#if 0
+volatile unsigned int rword;
+void ticker_isr() {
+    uint32_t t;
+    t= LPC_WDT->WDTV;
+    while (t == LPC_WDT->WDTV);  // wait til new value
+    rword = SysTick->VAL;
+}
+
+Ticker ticker;
+#endif
+
+// entropy collection
+ const uint8_t gWDT_buffer_SIZE=32;
+ const uint8_t WDT_POOL_SIZE=8;
+ uint8_t gWDT_buffer[gWDT_buffer_SIZE];
+ uint8_t gWDT_buffer_position;
+ uint8_t gWDT_loop_counter;
+ volatile uint8_t gWDT_pool_start;
+ volatile uint8_t gWDT_pool_end;
+ volatile uint8_t gWDT_pool_count;
+ volatile uint32_t gWDT_entropy_pool[WDT_POOL_SIZE];
+
+static void collect() {
+    uint32_t t;
+    t= LPC_WDT->WDTV;
+    while (t == LPC_WDT->WDTV);  // wait til new value
+    //  TODO kick WDT to avoid reset when counter < 100000 or schedule
+  gWDT_buffer[gWDT_buffer_position] = SysTick->VAL;
+  gWDT_buffer_position++; 
+  if (gWDT_buffer_position >= gWDT_buffer_SIZE)
+  {
+    gWDT_pool_end = (gWDT_pool_start + gWDT_pool_count) % WDT_POOL_SIZE;
+    // The following code is an implementation of Jenkin's one at a time hash
+    // This hash function has had preliminary testing to verify that it
+    // produces reasonably uniform random results when using WDT jitter
+    // on a variety of Arduino platforms
+    for(gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter)
+      {
+    gWDT_entropy_pool[gWDT_pool_end] += gWDT_buffer[gWDT_loop_counter];
+    gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 10);
+    gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 6);
+      }
+    gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 3);
+    gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 11);
+    gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 15);
+    gWDT_entropy_pool[gWDT_pool_end] = gWDT_entropy_pool[gWDT_pool_end];
+    gWDT_buffer_position = 0; // Start collecting the next 32 bytes of Timer 1 counts
+    if (gWDT_pool_count == WDT_POOL_SIZE) // The entropy pool is full
+      gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE;
+    else // Add another unsigned long (32 bits) to the entropy pool
+      ++gWDT_pool_count;
+  }
+}
+
+
+uint32_t random() {
+    uint32_t retVal;
+
+    while (gWDT_pool_count < 1) collect(); // gather entropy
+    
+    __disable_irq();  // crtical section
+    retVal = gWDT_entropy_pool[gWDT_pool_start];
+    gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE;
+    --gWDT_pool_count;
+    __enable_irq();
+    return(retVal);
+}
+
+#define REPS 50
+void display() {
+    uint32_t r,t;
+    int i;
+    float bps;
+
+    t=tmr.read_us();
+    for (i=0;i<REPS;i++)r=random();
+    t= tmr.read_us() -t;
+    bps = REPS*32.e6/t;
+    printf("%f bps  %0x\n",bps,r);
+    wait(3.0);
+}
+
+void logger() {
+    // await start byte from host then start sending random numbers
+    //  ./logger 5000000  for diehard tests
+    unsigned int rng;
+    char *bytes = (char *) &rng;
+
+    pc.getc();    // await byte from host
+    while(1) {
+        rng = random();
+        for (int i=0; i<4;i++) pc.putc(bytes[i]);
+    }
+}
+
+int main() {
+
+    gWDT_buffer_position=0;
+    gWDT_pool_start = 0;
+    gWDT_pool_end = 0;
+    gWDT_pool_count = 0;
+    tmr.start();
+    systick_init();
+    wdt_init();
+
+ //   ticker.attach_us(&ticker_isr,1000);  // 1/8192  122 us
+
+    while(1) {
+        display(); 
+      //   logger();
+   //     printf("rword %x\n",rword); wait(3.0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Jul 25 15:27:38 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/bad568076d81
\ No newline at end of file