You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.8 KiB
C++
169 lines
4.8 KiB
C++
/*
|
|
* TrueRandom - A true random number generator for Arduino.
|
|
* This is variant of original work originally implemented as:
|
|
* https://code.google.com/archive/p/tinkerit/ https://github.com/Cathedrow/TrueRandom
|
|
* Copyright (c) 2010 Peter Knight, Tinker.it! All rights reserved.
|
|
* Now modified for the ESP8266
|
|
*/
|
|
|
|
#include "ESP8266TrueRandom.h"
|
|
|
|
ICACHE_FLASH_ATTR ESP8266TrueRandomClass::ESP8266TrueRandomClass() {
|
|
useRNG = true;
|
|
lastYield = 0;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR int ESP8266TrueRandomClass::randomBitRaw(void) {
|
|
// Needed to keep wifi stack running smoothly
|
|
// And to avoid wdt reset
|
|
if (lastYield == 0 || millis() - lastYield >= 50) {
|
|
yield();
|
|
lastYield = millis();
|
|
}
|
|
uint8_t bit = useRNG
|
|
? (int)RANDOM_REG32 //using the onboard hardware random number generator (esp8266_peri.h)
|
|
: analogRead(A0); //using A0 / TOUT
|
|
|
|
return bit & 1;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR int ESP8266TrueRandomClass::randomBitRaw2(void) {
|
|
// Software whiten bits using Von Neumann algorithm
|
|
//
|
|
// von Neumann, John (1951). "Various techniques used in connection
|
|
// with random digits". National Bureau of Standards Applied Math Series
|
|
// 12:36.
|
|
//
|
|
for(;;) {
|
|
int a = randomBitRaw() | (randomBitRaw()<<1);
|
|
if (a==1) return 0; // 1 to 0 transition: log a zero bit
|
|
if (a==2) return 1; // 0 to 1 transition: log a one bit
|
|
// For other cases, try again.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR int ESP8266TrueRandomClass::randomBit(void) {
|
|
// Software whiten bits using Von Neumann algorithm
|
|
//
|
|
// von Neumann, John (1951). "Various techniques used in connection
|
|
// with random digits". National Bureau of Standards Applied Math Series
|
|
// 12:36.
|
|
//
|
|
for(;;) {
|
|
int a = randomBitRaw2() | (randomBitRaw2()<<1);
|
|
if (a==1) return 0; // 1 to 0 transition: log a zero bit
|
|
if (a==2) return 1; // 0 to 1 transition: log a one bit
|
|
// For other cases, try again.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR char ESP8266TrueRandomClass::randomByte(void) {
|
|
char result = 0;
|
|
uint8_t i;
|
|
for (i=8; i--;) result += result + randomBit();
|
|
return result;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR int ESP8266TrueRandomClass::rand() {
|
|
int result = 0;
|
|
uint8_t i;
|
|
for (i=15; i--;) result += result + randomBit();
|
|
return result;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR long ESP8266TrueRandomClass::random() {
|
|
long result = 0;
|
|
uint8_t i;
|
|
for (i=31; i--;) result += result + randomBit();
|
|
return result;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR long ESP8266TrueRandomClass::random(long howBig) {
|
|
long randomValue;
|
|
long topBit;
|
|
long bitPosition;
|
|
|
|
if (!howBig) return 0;
|
|
randomValue = 0;
|
|
if (howBig & (howBig-1)) {
|
|
// Range is not a power of 2 - use slow method
|
|
topBit = howBig-1;
|
|
topBit |= topBit>>1;
|
|
topBit |= topBit>>2;
|
|
topBit |= topBit>>4;
|
|
topBit |= topBit>>8;
|
|
topBit |= topBit>>16;
|
|
topBit = (topBit+1) >> 1;
|
|
|
|
bitPosition = topBit;
|
|
do {
|
|
// Generate the next bit of the result
|
|
if (randomBit()) randomValue |= bitPosition;
|
|
|
|
// Check if bit
|
|
if (randomValue >= howBig) {
|
|
// Number is over the top limit - start again.
|
|
randomValue = 0;
|
|
bitPosition = topBit;
|
|
} else {
|
|
// Repeat for next bit
|
|
bitPosition >>= 1;
|
|
}
|
|
} while (bitPosition);
|
|
} else {
|
|
// Special case, howBig is a power of 2
|
|
bitPosition = howBig >> 1;
|
|
while (bitPosition) {
|
|
if (randomBit()) randomValue |= bitPosition;
|
|
bitPosition >>= 1;
|
|
}
|
|
}
|
|
return randomValue;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR long ESP8266TrueRandomClass::random(long howSmall, long howBig) {
|
|
if (howSmall >= howBig) return howSmall;
|
|
long diff = howBig - howSmall;
|
|
return ESP8266TrueRandomClass::random(diff) + howSmall;
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR void ESP8266TrueRandomClass::memfill(char* location, int size) {
|
|
for (;size--;) *location++ = randomByte();
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR void ESP8266TrueRandomClass::mac(uint8_t* macLocation) {
|
|
memfill((char*)macLocation,6);
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR void ESP8266TrueRandomClass::uuid(uint8_t* uuidLocation) {
|
|
// Generate a Version 4 UUID according to RFC4122
|
|
memfill((char*)uuidLocation,16);
|
|
// Although the UUID contains 128 bits, only 122 of those are random.
|
|
// The other 6 bits are fixed, to indicate a version number.
|
|
uuidLocation[6] = 0x40 | (0x0F & uuidLocation[6]);
|
|
uuidLocation[8] = 0x80 | (0x3F & uuidLocation[8]);
|
|
}
|
|
|
|
ICACHE_FLASH_ATTR String ESP8266TrueRandomClass::uuidToString(uint8_t* uuidLocation) {
|
|
String string = "";
|
|
int i;
|
|
for (i=0; i<16; i++) {
|
|
if (i==4) string += "-";
|
|
if (i==6) string += "-";
|
|
if (i==8) string += "-";
|
|
if (i==10) string += "-";
|
|
int topDigit = uuidLocation[i] >> 4;
|
|
int bottomDigit = uuidLocation[i] & 0x0f;
|
|
// High hex digit
|
|
string += "0123456789abcdef"[topDigit];
|
|
// Low hex digit
|
|
string += "0123456789abcdef"[bottomDigit];
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
ESP8266TrueRandomClass ESP8266TrueRandom;
|