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

Committer:
manitou
Date:
Sat Jul 25 15:27:38 2015 +0000
Revision:
0:808fc29f4d37
initial

Who changed what in which revision?

UserRevisionLine numberNew contents of line
manitou 0:808fc29f4d37 1
manitou 0:808fc29f4d37 2 // random bits from systick and WDT
manitou 0:808fc29f4d37 3 // based on arduino/teensy Entropy lib
manitou 0:808fc29f4d37 4 // https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library
manitou 0:808fc29f4d37 5 // seems WDT ISR will only fire once, so check free-running WDT periodically
manitou 0:808fc29f4d37 6 // enable systick as free running 24-bit clock to beat against RTC crystal
manitou 0:808fc29f4d37 7 #include "mbed.h"
manitou 0:808fc29f4d37 8
manitou 0:808fc29f4d37 9 Timer tmr;
manitou 0:808fc29f4d37 10 Serial pc(USBTX, USBRX);
manitou 0:808fc29f4d37 11
manitou 0:808fc29f4d37 12 void kick() {
manitou 0:808fc29f4d37 13 // restart WDT countdown
manitou 0:808fc29f4d37 14 __disable_irq();
manitou 0:808fc29f4d37 15 LPC_WDT->WDFEED = 0xAA;
manitou 0:808fc29f4d37 16 LPC_WDT->WDFEED = 0x55;
manitou 0:808fc29f4d37 17 __enable_irq();
manitou 0:808fc29f4d37 18 }
manitou 0:808fc29f4d37 19
manitou 0:808fc29f4d37 20 void wdt_init() {
manitou 0:808fc29f4d37 21 LPC_WDT->WDCLKSEL = 0x02; // Set CLK src 0 IRC 1 PCLK 2 RTC
manitou 0:808fc29f4d37 22 LPC_WDT->WDTC = 0xfffffff; // max countdown
manitou 0:808fc29f4d37 23 LPC_WDT->WDMOD = 0x01; // enable but no reset
manitou 0:808fc29f4d37 24 kick();
manitou 0:808fc29f4d37 25 }
manitou 0:808fc29f4d37 26
manitou 0:808fc29f4d37 27 void systick_init() {
manitou 0:808fc29f4d37 28 SysTick->LOAD = 0x123456; // doesn't really matter
manitou 0:808fc29f4d37 29 SysTick->VAL = 0;
manitou 0:808fc29f4d37 30 SysTick->CTRL = 4 | 1; //CLKSOURCE=CPU clock | ENABLE
manitou 0:808fc29f4d37 31 }
manitou 0:808fc29f4d37 32
manitou 0:808fc29f4d37 33 #if 0
manitou 0:808fc29f4d37 34 volatile unsigned int rword;
manitou 0:808fc29f4d37 35 void ticker_isr() {
manitou 0:808fc29f4d37 36 uint32_t t;
manitou 0:808fc29f4d37 37 t= LPC_WDT->WDTV;
manitou 0:808fc29f4d37 38 while (t == LPC_WDT->WDTV); // wait til new value
manitou 0:808fc29f4d37 39 rword = SysTick->VAL;
manitou 0:808fc29f4d37 40 }
manitou 0:808fc29f4d37 41
manitou 0:808fc29f4d37 42 Ticker ticker;
manitou 0:808fc29f4d37 43 #endif
manitou 0:808fc29f4d37 44
manitou 0:808fc29f4d37 45 // entropy collection
manitou 0:808fc29f4d37 46 const uint8_t gWDT_buffer_SIZE=32;
manitou 0:808fc29f4d37 47 const uint8_t WDT_POOL_SIZE=8;
manitou 0:808fc29f4d37 48 uint8_t gWDT_buffer[gWDT_buffer_SIZE];
manitou 0:808fc29f4d37 49 uint8_t gWDT_buffer_position;
manitou 0:808fc29f4d37 50 uint8_t gWDT_loop_counter;
manitou 0:808fc29f4d37 51 volatile uint8_t gWDT_pool_start;
manitou 0:808fc29f4d37 52 volatile uint8_t gWDT_pool_end;
manitou 0:808fc29f4d37 53 volatile uint8_t gWDT_pool_count;
manitou 0:808fc29f4d37 54 volatile uint32_t gWDT_entropy_pool[WDT_POOL_SIZE];
manitou 0:808fc29f4d37 55
manitou 0:808fc29f4d37 56 static void collect() {
manitou 0:808fc29f4d37 57 uint32_t t;
manitou 0:808fc29f4d37 58 t= LPC_WDT->WDTV;
manitou 0:808fc29f4d37 59 while (t == LPC_WDT->WDTV); // wait til new value
manitou 0:808fc29f4d37 60 // TODO kick WDT to avoid reset when counter < 100000 or schedule
manitou 0:808fc29f4d37 61 gWDT_buffer[gWDT_buffer_position] = SysTick->VAL;
manitou 0:808fc29f4d37 62 gWDT_buffer_position++;
manitou 0:808fc29f4d37 63 if (gWDT_buffer_position >= gWDT_buffer_SIZE)
manitou 0:808fc29f4d37 64 {
manitou 0:808fc29f4d37 65 gWDT_pool_end = (gWDT_pool_start + gWDT_pool_count) % WDT_POOL_SIZE;
manitou 0:808fc29f4d37 66 // The following code is an implementation of Jenkin's one at a time hash
manitou 0:808fc29f4d37 67 // This hash function has had preliminary testing to verify that it
manitou 0:808fc29f4d37 68 // produces reasonably uniform random results when using WDT jitter
manitou 0:808fc29f4d37 69 // on a variety of Arduino platforms
manitou 0:808fc29f4d37 70 for(gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter)
manitou 0:808fc29f4d37 71 {
manitou 0:808fc29f4d37 72 gWDT_entropy_pool[gWDT_pool_end] += gWDT_buffer[gWDT_loop_counter];
manitou 0:808fc29f4d37 73 gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 10);
manitou 0:808fc29f4d37 74 gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 6);
manitou 0:808fc29f4d37 75 }
manitou 0:808fc29f4d37 76 gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 3);
manitou 0:808fc29f4d37 77 gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 11);
manitou 0:808fc29f4d37 78 gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 15);
manitou 0:808fc29f4d37 79 gWDT_entropy_pool[gWDT_pool_end] = gWDT_entropy_pool[gWDT_pool_end];
manitou 0:808fc29f4d37 80 gWDT_buffer_position = 0; // Start collecting the next 32 bytes of Timer 1 counts
manitou 0:808fc29f4d37 81 if (gWDT_pool_count == WDT_POOL_SIZE) // The entropy pool is full
manitou 0:808fc29f4d37 82 gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE;
manitou 0:808fc29f4d37 83 else // Add another unsigned long (32 bits) to the entropy pool
manitou 0:808fc29f4d37 84 ++gWDT_pool_count;
manitou 0:808fc29f4d37 85 }
manitou 0:808fc29f4d37 86 }
manitou 0:808fc29f4d37 87
manitou 0:808fc29f4d37 88
manitou 0:808fc29f4d37 89 uint32_t random() {
manitou 0:808fc29f4d37 90 uint32_t retVal;
manitou 0:808fc29f4d37 91
manitou 0:808fc29f4d37 92 while (gWDT_pool_count < 1) collect(); // gather entropy
manitou 0:808fc29f4d37 93
manitou 0:808fc29f4d37 94 __disable_irq(); // crtical section
manitou 0:808fc29f4d37 95 retVal = gWDT_entropy_pool[gWDT_pool_start];
manitou 0:808fc29f4d37 96 gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE;
manitou 0:808fc29f4d37 97 --gWDT_pool_count;
manitou 0:808fc29f4d37 98 __enable_irq();
manitou 0:808fc29f4d37 99 return(retVal);
manitou 0:808fc29f4d37 100 }
manitou 0:808fc29f4d37 101
manitou 0:808fc29f4d37 102 #define REPS 50
manitou 0:808fc29f4d37 103 void display() {
manitou 0:808fc29f4d37 104 uint32_t r,t;
manitou 0:808fc29f4d37 105 int i;
manitou 0:808fc29f4d37 106 float bps;
manitou 0:808fc29f4d37 107
manitou 0:808fc29f4d37 108 t=tmr.read_us();
manitou 0:808fc29f4d37 109 for (i=0;i<REPS;i++)r=random();
manitou 0:808fc29f4d37 110 t= tmr.read_us() -t;
manitou 0:808fc29f4d37 111 bps = REPS*32.e6/t;
manitou 0:808fc29f4d37 112 printf("%f bps %0x\n",bps,r);
manitou 0:808fc29f4d37 113 wait(3.0);
manitou 0:808fc29f4d37 114 }
manitou 0:808fc29f4d37 115
manitou 0:808fc29f4d37 116 void logger() {
manitou 0:808fc29f4d37 117 // await start byte from host then start sending random numbers
manitou 0:808fc29f4d37 118 // ./logger 5000000 for diehard tests
manitou 0:808fc29f4d37 119 unsigned int rng;
manitou 0:808fc29f4d37 120 char *bytes = (char *) &rng;
manitou 0:808fc29f4d37 121
manitou 0:808fc29f4d37 122 pc.getc(); // await byte from host
manitou 0:808fc29f4d37 123 while(1) {
manitou 0:808fc29f4d37 124 rng = random();
manitou 0:808fc29f4d37 125 for (int i=0; i<4;i++) pc.putc(bytes[i]);
manitou 0:808fc29f4d37 126 }
manitou 0:808fc29f4d37 127 }
manitou 0:808fc29f4d37 128
manitou 0:808fc29f4d37 129 int main() {
manitou 0:808fc29f4d37 130
manitou 0:808fc29f4d37 131 gWDT_buffer_position=0;
manitou 0:808fc29f4d37 132 gWDT_pool_start = 0;
manitou 0:808fc29f4d37 133 gWDT_pool_end = 0;
manitou 0:808fc29f4d37 134 gWDT_pool_count = 0;
manitou 0:808fc29f4d37 135 tmr.start();
manitou 0:808fc29f4d37 136 systick_init();
manitou 0:808fc29f4d37 137 wdt_init();
manitou 0:808fc29f4d37 138
manitou 0:808fc29f4d37 139 // ticker.attach_us(&ticker_isr,1000); // 1/8192 122 us
manitou 0:808fc29f4d37 140
manitou 0:808fc29f4d37 141 while(1) {
manitou 0:808fc29f4d37 142 display();
manitou 0:808fc29f4d37 143 // logger();
manitou 0:808fc29f4d37 144 // printf("rword %x\n",rword); wait(3.0);
manitou 0:808fc29f4d37 145 }
manitou 0:808fc29f4d37 146 }