From 53337296441f7b962e6a424996f2deb3f95e51c9 Mon Sep 17 00:00:00 2001
From: Robert May
Date: Wed, 18 Nov 2015 15:50:44 +0000
Subject: [PATCH] Revert "Cchange random() to use libc srand()/rand()"
This reverts commit db5227872affd9cca252a1b39551d239212b9680.
return to using our own random implementation.

inc/MicroBit.h  6 ++
source/MicroBit.cpp  63 ++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 24 deletions()
diff git a/inc/MicroBit.h b/inc/MicroBit.h
index 9056492..417b300 100644
 a/inc/MicroBit.h
+++ b/inc/MicroBit.h
@@ 90,6 +90,7 @@ class MicroBit
private:
void seedRandom();
+ uint32_t randomValue;
public:
@@ 213,9 +214,8 @@ class MicroBit
/**
* Generate a random number in the given range.
 * We use libc's rand() which is sufficient for our applications and much
 * more lightweight than the hardware random number generator built into
 * the processor, which takes a long time and uses a lot of energy.
+ * We use the NRF51822 in built random number generator here
+ * TODO: Determine if we want to, given its relatively high power consumption!
*
* @param max the upper range to generate a number for. This number cannot be negative
* @return A random, natural number between 0 and the max1. Or MICROBIT_INVALID_PARAMETER if max is <= 0.
diff git a/source/MicroBit.cpp b/source/MicroBit.cpp
index cedcefa..0e74061 100644
 a/source/MicroBit.cpp
+++ b/source/MicroBit.cpp
@@ 1,5 +1,4 @@
#include "MicroBit.h"
#include /* rand(),srand() */
char MICROBIT_BLE_DEVICE_NAME[] = "BBC micro:bit [xxxxx]";
@@ 284,11 +283,13 @@ int MicroBit::sleep(int milliseconds)
/**
* Generate a random number in the given range.
 * We use libc's rand() which is sufficient for our applications and much
 * more lightweight than the hardware random number generator built into
 * the processor, which takes a long time and uses a lot of energy.
+ * We use a simple Galois LFSR random number generator here,
+ * as a Galois LFSR is sufficient for our applications, and much more lightweight
+ * than the hardware random number generator built int the processor, which takes
+ * a long time and uses a lot of energy.
*
 * KIDS: You shouldn't use this is the real world to generate cryptographic keys though...
+ * KIDS: You shouldn't use this is the real world to generte cryptographic keys though...
+ * have a think why not. :)
*
* @param max the upper range to generate a number for. This number cannot be negative
* @return A random, natural number between 0 and the max1. Or MICROBIT_INVALID_VALUE (defined in ErrorNo.h) if max is <= 0.
@@ 300,38 +301,60 @@ int MicroBit::sleep(int milliseconds)
*/
int MicroBit::random(int max)
{
 unsigned long num_bins, num_rand, bin_size, defect;
 int result;
+ uint32_t m, result;
//return MICROBIT_INVALID_VALUE if max is <= 0...
if(max <= 0)
return MICROBIT_INVALID_PARAMETER;
 num_bins = (unsigned long) max;
 num_rand = (unsigned long) RAND_MAX + 1;
 bin_size = num_rand / num_bins;
 defect = num_rand % num_bins;
+ // Our maximum return value is actually one less than passed
+ max;
do {
 result = rand();
 } while ((num_rand  defect) <= (unsigned long)result); // CARE: avoid overflow
+ m = (uint32_t)max;
+ result = 0;
+ while(m >>= 1) {
+ // Cycle the LFSR (Linear Feedback Shift Register).
+ // We use an optimal sequence with a period of 2^321, as defined by Bruce Schneider here (a true legend in the field!),
+ // For those interested, it's documented in his paper:
+ // "PseudoRandom Sequence Generator for 32Bit CPUs: A fast, machineindependent generator for 32bit Microprocessors"
+ // https://www.schneier.com/paperpseudorandomsequence.html
+ // Avoid interupts (and hence fibre context switch) while we are doing this
+
+ __disable_irq();
+
+ randomValue = ((((randomValue >> 31)
+ ^ (randomValue >> 6)
+ ^ (randomValue >> 4)
+ ^ (randomValue >> 2)
+ ^ (randomValue >> 1)
+ ^ randomValue)
+ & 0x0000001)
+ << 31 )
+  (randomValue >> 1);
+
+ __enable_irq();
+
+ result = ((result << 1)  (randomValue & 0x00000001));
+ }
+ } while (result > (uint32_t)max);
 return result/bin_size;
+ return result;
}
/**
* Seed our a random number generator (RNG).
 * We use the NRF51822 in built cryptographic random number generator to seed rand().
+ * We use the NRF51822 in built cryptographic random number generator to seed a Galois LFSR.
* We do this as the hardware RNG is relatively high power, and use the the BLE stack internally,
 * with a less than optimal application interface. rand() is sufficient for our
+ * with a less than optimal application interface. A Galois LFSR is sufficient for our
* applications, and much more lightweight.
*/
void MicroBit::seedRandom()
{
 unsigned int seed = 0;

+ randomValue = 0;
+
// Start the Random number generator. No need to leave it running... I hope. :)
NRF_RNG>TASKS_START = 1;
@@ 343,13 +366,11 @@ void MicroBit::seedRandom()
// Wait for a number ot be generated.
while ( NRF_RNG>EVENTS_VALRDY == 0);
 seed = (seed << 8)  ((int) NRF_RNG>VALUE);
+ randomValue = (randomValue << 8)  ((int) NRF_RNG>VALUE);
}
// Disable the generator to save power.
NRF_RNG>TASKS_STOP = 1;

 srand(seed);
}