teensy 3.1 random bits from dueling clock entropy using LPTMR and systick
teensy 3.1 random bits from dueling clocks entropy using LPTMR and systick
Based on Arduino/Teensy entropy library, generates random bits at 151 bits/second. More info at mbed LPC1768 entropy
main.cpp
- Committer:
- manitou
- Date:
- 2015-10-03
- Revision:
- 0:2ff6df966da0
File content as of revision 0:2ff6df966da0:
// teensy_rng entropy from dueling clocks LPTMR and systick // random bits based on arduino/teensy Entropy lib // https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library #include "mbed.h" #include "USBSerial.h" #define PRREG(x) pc.printf(#x" %0x\n",x) USBSerial pc; // Virtual serial port over USB Timer tmr; void lptmr_init() { SIM->SCGC5 |= SIM_SCGC5_LPTIMER_MASK; LPTMR0->CSR = 0x84; //0b10000100 disable LPTMR0->PSR = 0x05; //0b00000101 PCS=01 : 1 kHz clock LPTMR0->CMR = 6; // smaller number, faster random number LPTMR0->CSR = 0x45; //0b01000101 enable interrupt enable NVIC_EnableIRQ(LPTimer_IRQn); } void systick_init() { SysTick->LOAD = 0x123456; // doesn't really matter SysTick->VAL = 0; SysTick->CTRL = 4 | 1; //CLKSOURCE=CPU clock | ENABLE } // 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]; extern "C" void LPTimer_IRQHandler() { LPTMR0->CSR = 0x84; //0b10000100; LPTMR0->CSR = 0x45; //0b01000101; 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) ; // 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; pc.printf("SystemCoreClock %d %s %s\n",SystemCoreClock,__TIME__,__DATE__); t=tmr.read_us(); for (i=0;i<REPS;i++)r=random(); t= tmr.read_us() -t; bps = REPS*32.e6/t; pc.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(); lptmr_init(); while(1) { display(); //logger(); } }