From db5227872affd9cca252a1b39551d239212b9680 Mon Sep 17 00:00:00 2001
From: Robert May
Date: Wed, 18 Nov 2015 14:15:17 +0000
Subject: [PATCH] Cchange random() to use libc srand()/rand()
Uisng libc's implementation is likely to be safer than rolling our own. At least
the failure modes are well documented. (glibc's implementation of rand() is
actually not bad).

inc/MicroBit.h  6 ++
source/MicroBit.cpp  63 +++++++++++++++
2 files changed, 24 insertions(+), 45 deletions()
diff git a/inc/MicroBit.h b/inc/MicroBit.h
index 417b300..9056492 100644
 a/inc/MicroBit.h
+++ b/inc/MicroBit.h
@@ 90,7 +90,6 @@ class MicroBit
private:
void seedRandom();
 uint32_t randomValue;
public:
@@ 214,8 +213,9 @@ class MicroBit
/**
* Generate a random number in the given range.
 * We use the NRF51822 in built random number generator here
 * TODO: Determine if we want to, given its relatively high power consumption!
+ * 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.
*
* @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 0e74061..cedcefa 100644
 a/source/MicroBit.cpp
+++ b/source/MicroBit.cpp
@@ 1,4 +1,5 @@
#include "MicroBit.h"
+#include /* rand(),srand() */
char MICROBIT_BLE_DEVICE_NAME[] = "BBC micro:bit [xxxxx]";
@@ 283,13 +284,11 @@ int MicroBit::sleep(int milliseconds)
/**
* Generate a random number in the given range.
 * 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.
+ * 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.
*
 * KIDS: You shouldn't use this is the real world to generte cryptographic keys though...
 * have a think why not. :)
+ * KIDS: You shouldn't use this is the real world to generate cryptographic keys though...
*
* @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.
@@ 301,60 +300,38 @@ int MicroBit::sleep(int milliseconds)
*/
int MicroBit::random(int max)
{
 uint32_t m, result;
+ unsigned long num_bins, num_rand, bin_size, defect;
+ int result;
//return MICROBIT_INVALID_VALUE if max is <= 0...
if(max <= 0)
return MICROBIT_INVALID_PARAMETER;
 // Our maximum return value is actually one less than passed
 max;
+ num_bins = (unsigned long) max;
+ num_rand = (unsigned long) RAND_MAX + 1;
+ bin_size = num_rand / num_bins;
+ defect = num_rand % num_bins;
do {
 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);
+ result = rand();
+ } while ((num_rand  defect) <= (unsigned long)result); // CARE: avoid overflow
 return result;
+ return result/bin_size;
}
/**
* Seed our a random number generator (RNG).
 * We use the NRF51822 in built cryptographic random number generator to seed a Galois LFSR.
+ * We use the NRF51822 in built cryptographic random number generator to seed rand().
* 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. A Galois LFSR is sufficient for our
+ * with a less than optimal application interface. rand() is sufficient for our
* applications, and much more lightweight.
*/
void MicroBit::seedRandom()
{
 randomValue = 0;

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