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++

/*
* 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;