teensy 3.1 random bits from dueling clock entropy using LPTMR and systick

Dependencies:   USBDevice mbed

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();
    }
}