ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RNG.cpp
1 /*
2  * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "RNG.h"
24 #include "NoiseSource.h"
25 #include "ChaCha.h"
26 #include "Crypto.h"
27 #include "utility/ProgMemUtil.h"
28 #include <Arduino.h>
29 #if defined (__arm__) && defined (__SAM3X8E__)
30 // The Arduino Due does not have any EEPROM natively on the main chip.
31 // However, it does have a TRNG and flash memory.
32 #define RNG_DUE_TRNG 1
33 #elif defined(__AVR__)
34 #define RNG_EEPROM 1 // Use EEPROM to save the seed.
35 #define RNG_WATCHDOG 1 // Harvest entropy from watchdog jitter.
36 #include <avr/eeprom.h>
37 #include <avr/wdt.h>
38 #include <avr/io.h>
39 #define RNG_EEPROM_ADDRESS (E2END + 1 - RNGClass::SEED_SIZE)
40 #endif
41 #include <string.h>
42 
136 RNGClass RNG;
137 
146 // Number of ChaCha hash rounds to use for random number generation.
147 #define RNG_ROUNDS 20
148 
149 // Force a rekey after this many blocks of random data.
150 #define RNG_REKEY_BLOCKS 16
151 
152 // Maximum entropy credit that can be contained in the pool.
153 #define RNG_MAX_CREDITS 384
154 
157 // Imported from Crypto.cpp.
158 extern uint8_t crypto_crc8(uint8_t tag, const void *data, unsigned size);
159 
160 // Tag for 256-bit ChaCha20 keys. This will always appear in the
161 // first 16 bytes of the block. The remaining 48 bytes are the seed.
162 static const char tagRNG[16] PROGMEM = {
163  'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
164  '2', '-', 'b', 'y', 't', 'e', ' ', 'k'
165 };
166 
167 // Initialization seed. This is the ChaCha20 output of hashing
168 // "expand 32-byte k" followed by 48 bytes set to the numbers 1 to 48.
169 // The ChaCha20 output block is then truncated to the first 48 bytes.
170 //
171 // This value is intended to start the RNG in a semi-chaotic state if
172 // we don't have a previously saved seed in EEPROM.
173 static const uint8_t initRNG[48] PROGMEM = {
174  0xB0, 0x2A, 0xAE, 0x7D, 0xEE, 0xCB, 0xBB, 0xB1,
175  0xFC, 0x03, 0x6F, 0xDD, 0xDC, 0x7D, 0x76, 0x67,
176  0x0C, 0xE8, 0x1F, 0x0D, 0xA3, 0xA0, 0xAA, 0x1E,
177  0xB0, 0xBD, 0x72, 0x6B, 0x2B, 0x4C, 0x8A, 0x7E,
178  0x34, 0xFC, 0x37, 0x60, 0xF4, 0x1E, 0x22, 0xA0,
179  0x0B, 0xFB, 0x18, 0x84, 0x60, 0xA5, 0x77, 0x72
180 };
181 
182 #if defined(RNG_WATCHDOG)
183 
184 // Use jitter between the watchdog timer and the main CPU clock to
185 // harvest some entropy on AVR-based systems. This technique comes from:
186 //
187 // https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library
188 //
189 // The watchdog generates entropy very slowly - it can take around 32 seconds
190 // to generate 256 bits of entropy credit. This is a "better than nothing"
191 // entropy source but a real noise source is definitely recommended.
192 
193 // Helper macros for specific 32-bit shift counts.
194 #define leftShift3(value) ((value) << 3)
195 #define leftShift10(value) ((value) << 10)
196 #define leftShift15(value) ((value) << 15)
197 #define rightShift6(value) ((value) >> 6)
198 #define rightShift11(value) ((value) >> 11)
199 
200 static uint32_t volatile hash = 0;
201 static uint8_t volatile outBits = 0;
202 
203 // Watchdog interrupt handler. This fires off every 16ms. We collect
204 // 32 bits and then pass them off onto RNGClass::loop().
205 ISR(WDT_vect)
206 {
207  // Read the low byte of Timer 1. We assume that the timer was
208  // initialized by the Arduino startup code for PWM use or that the
209  // application is free-running Timer 1 for its own purposes.
210  // Timer 0 is used on systems that don't have a Timer 1.
211 #if defined(TCNT1L)
212  unsigned char value = TCNT1L;
213 #elif defined(TCNT0L)
214  unsigned char value = TCNT0L;
215 #else
216  unsigned char value = TCNT0;
217 #endif
218  // Use Jenkin's one-at-a-time hash function to scatter the entropy a bit.
219  // https://en.wikipedia.org/wiki/Jenkins_hash_function
220  hash += value;
221  hash += leftShift10(hash);
222  hash ^= rightShift6(hash);
223  ++outBits;
224 }
225 
226 #endif // RNG_WATCHDOG
227 
239  : credits(0)
240  , firstSave(1)
241  , timer(0)
242  , timeout(3600000UL) // 1 hour in milliseconds
243  , count(0)
244  , trngPosn(0)
245 {
246 }
247 
252 {
253 #if defined(RNG_DUE_TRNG)
254  // Disable the TRNG in the Arduino Due.
255  REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
256 #endif
257 #if defined(RNG_WATCHDOG)
258  // Disable interrupts and reset the watchdog.
259  cli();
260  wdt_reset();
261 
262  // Clear the "reset due to watchdog" flag.
263  MCUSR &= ~(1 << WDRF);
264 
265  // Disable the watchdog.
266  _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
267  _WD_CONTROL_REG = 0;
268 
269  // Re-enable interrupts. The watchdog should be stopped.
270  sei();
271 #endif
272  clean(block);
273  clean(stream);
274 }
275 
276 #if defined(RNG_DUE_TRNG)
277 
278 // Find the flash memory of interest. Allow for the possibility
279 // of other SAM-based Arduino variants in the future.
280 #if defined(IFLASH1_ADDR)
281 #define RNG_FLASH_ADDR IFLASH1_ADDR
282 #define RNG_FLASH_SIZE IFLASH1_SIZE
283 #define RNG_FLASH_PAGE_SIZE IFLASH1_PAGE_SIZE
284 #define RNG_EFC EFC1
285 #elif defined(IFLASH0_ADDR)
286 #define RNG_FLASH_ADDR IFLASH0_ADDR
287 #define RNG_FLASH_SIZE IFLASH0_SIZE
288 #define RNG_FLASH_PAGE_SIZE IFLASH0_PAGE_SIZE
289 #define RNG_EFC EFC0
290 #else
291 #define RNG_FLASH_ADDR IFLASH_ADDR
292 #define RNG_FLASH_SIZE IFLASH_SIZE
293 #define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
294 #define RNG_EFC EFC
295 #endif
296 
297 // Address of the flash page to use for saving the seed on the Due.
298 // All SAM variants have a page size of 256 bytes or greater so there is
299 // plenty of room for the 48 byte seed in the last page of flash memory.
300 #define RNG_SEED_ADDR (RNG_FLASH_ADDR + RNG_FLASH_SIZE - RNG_FLASH_PAGE_SIZE)
301 #define RNG_SEED_PAGE ((RNG_FLASH_SIZE / RNG_FLASH_PAGE_SIZE) - 1)
302 
303 // Stir in the unique identifier for the Arduino Due's CPU.
304 // This function must be in RAM because programs running out of
305 // flash memory are not allowed to access the unique identifier.
306 // Info from: http://forum.arduino.cc/index.php?topic=289190.0
307 __attribute__((section(".ramfunc")))
308 static void stirUniqueIdentifier(void)
309 {
310  uint32_t id[4];
311 
312  // Start Read Unique Identifier.
313  RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
314  while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
315  ; // do nothing until FRDY falls.
316 
317  // Read the identifier.
318  id[0] = *((const uint32_t *)RNG_FLASH_ADDR);
319  id[1] = *((const uint32_t *)(RNG_FLASH_ADDR + 4));
320  id[2] = *((const uint32_t *)(RNG_FLASH_ADDR + 8));
321  id[3] = *((const uint32_t *)(RNG_FLASH_ADDR + 12));
322 
323  // Stop Read Unique Identifier.
324  RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
325  while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
326  ; // do nothing until FRDY rises.
327 
328  // Stir the unique identifier into the entropy pool.
329  RNG.stir((uint8_t *)id, sizeof(id));
330 }
331 
332 // Erases the flash page containing the seed and then writes the new seed.
333 // It is assumed the seed has already been loaded into the latch registers.
334 __attribute__((section(".ramfunc")))
335 static void eraseAndWriteSeed()
336 {
337  // Execute the "Erase and Write Page" command.
338  RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
339 
340  // Wait for the FRDY bit to be raised.
341  while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
342  ; // do nothing until FRDY rises.
343 }
344 
345 #endif
346 
360 void RNGClass::begin(const char *tag)
361 {
362  // Initialize the ChaCha20 input block from the saved seed.
363  memcpy_P(block, tagRNG, sizeof(tagRNG));
364  memcpy_P(block + 4, initRNG, sizeof(initRNG));
365 #if defined(RNG_EEPROM)
366  int address = RNG_EEPROM_ADDRESS;
367  eeprom_read_block(stream, (const void *)address, SEED_SIZE);
368  if (crypto_crc8('S', stream, SEED_SIZE - 1) ==
369  ((const uint8_t *)stream)[SEED_SIZE - 1]) {
370  // We have a saved seed: XOR it with the initialization block.
371  // Note: the CRC-8 value is included. No point throwing it away.
372  for (int posn = 0; posn < 12; ++posn)
373  block[posn + 4] ^= stream[posn];
374  }
375 #elif defined(RNG_DUE_TRNG)
376  // Do we have a seed saved in the last page of flash memory on the Due?
377  int posn, counter;
378  if (crypto_crc8('S', ((const uint32_t *)RNG_SEED_ADDR) + 1, SEED_SIZE)
379  == ((const uint32_t *)RNG_SEED_ADDR)[0]) {
380  // XOR the saved seed with the initialization block.
381  for (posn = 0; posn < 12; ++posn)
382  block[posn + 4] ^= ((const uint32_t *)RNG_SEED_ADDR)[posn + 1];
383  }
384 
385  // If the device has just been reprogrammed, there will be no saved seed.
386  // XOR the initialization block with some output from the CPU's TRNG
387  // to permute the state in a first boot situation after reprogramming.
388  pmc_enable_periph_clk(ID_TRNG);
389  REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
390  REG_TRNG_IDR = TRNG_IDR_DATRDY; // Disable interrupts - we will poll.
391  for (posn = 0; posn < 12; ++posn) {
392  // According to the documentation the TRNG should produce a new
393  // 32-bit random value every 84 clock cycles. If it still hasn't
394  // produced a value after 200 iterations, then assume that the
395  // TRNG is not producing output and stop.
396  for (counter = 0; counter < 200; ++counter) {
397  if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
398  break;
399  }
400  if (counter >= 200)
401  break;
402  block[posn + 4] ^= REG_TRNG_ODATA;
403  }
404 #endif
405 
406  // No entropy credits for the saved seed.
407  credits = 0;
408 
409  // Trigger an automatic save once the entropy credits max out.
410  firstSave = 1;
411 
412  // Rekey the random number generator immediately.
413  rekey();
414 
415  // Stir in the supplied tag data but don't credit any entropy to it.
416  if (tag)
417  stir((const uint8_t *)tag, strlen(tag));
418 
419 #if defined(RNG_DUE_TRNG)
420  // Stir in the unique identifier for the CPU so that different
421  // devices will give different outputs even without seeding.
422  stirUniqueIdentifier();
423 #else
424  // AVR devices don't have anything like a serial number so it is
425  // difficult to make every device unique. Use the compilation
426  // time and date to provide a little randomness across applications
427  // if not across devices running the same pre-compiled application.
428  tag = __TIME__ __DATE__;
429  stir((const uint8_t *)tag, strlen(tag));
430 #endif
431 
432 #if defined(RNG_WATCHDOG)
433  // Disable interrupts and reset the watchdog.
434  cli();
435  wdt_reset();
436 
437  // Clear the "reset due to watchdog" flag.
438  MCUSR &= ~(1 << WDRF);
439 
440  // Enable the watchdog with the smallest duration (16ms)
441  // and interrupt-only mode.
442  _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
443  _WD_CONTROL_REG = (1 << WDIE);
444 
445  // Re-enable interrupts. The watchdog should be running.
446  sei();
447 #endif
448 
449  // Re-save the seed to obliterate the previous value and to ensure
450  // that if the system is reset without a call to save() that we won't
451  // accidentally generate the same sequence of random data again.
452  save();
453 }
454 
468 {
469  #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
470  if (count < MAX_NOISE_SOURCES) {
471  noiseSources[count++] = &source;
472  source.added();
473  }
474 }
475 
492 void RNGClass::setAutoSaveTime(uint16_t minutes)
493 {
494  if (!minutes)
495  minutes = 1; // Just in case.
496  timeout = ((uint32_t)minutes) * 60000U;
497 }
498 
516 void RNGClass::rand(uint8_t *data, size_t len)
517 {
518  // Decrease the amount of entropy in the pool.
519  if (len > (credits / 8))
520  credits = 0;
521  else
522  credits -= len * 8;
523 
524  // Generate the random data.
525  uint8_t count = 0;
526  while (len > 0) {
527  // Force a rekey if we have generated too many blocks in this request.
528  if (count >= RNG_REKEY_BLOCKS) {
529  rekey();
530  count = 1;
531  } else {
532  ++count;
533  }
534 
535  // Increment the low counter word and generate a new keystream block.
536  ++(block[12]);
537  ChaCha::hashCore(stream, block, RNG_ROUNDS);
538 
539  // Copy the data to the return buffer.
540  if (len < 64) {
541  memcpy(data, stream, len);
542  break;
543  } else {
544  memcpy(data, stream, 64);
545  data += 64;
546  len -= 64;
547  }
548  }
549 
550  // Force a rekey after every request.
551  rekey();
552 }
553 
593 bool RNGClass::available(size_t len) const
594 {
595  if (len >= (RNG_MAX_CREDITS / 8))
596  return credits >= RNG_MAX_CREDITS;
597  else
598  return len <= (credits / 8);
599 }
600 
626 void RNGClass::stir(const uint8_t *data, size_t len, unsigned int credit)
627 {
628  // Increase the entropy credit.
629  if ((credit / 8) >= len && len)
630  credit = len * 8;
631  if ((RNG_MAX_CREDITS - credits) > credit)
632  credits += credit;
633  else
634  credits = RNG_MAX_CREDITS;
635 
636  // Process the supplied input data.
637  if (len > 0) {
638  // XOR the data with the ChaCha input block in 48 byte
639  // chunks and rekey the ChaCha cipher for each chunk to mix
640  // the data in. This should scatter any "true entropy" in
641  // the input across the entire block.
642  while (len > 0) {
643  size_t templen = len;
644  if (templen > 48)
645  templen = 48;
646  uint8_t *output = ((uint8_t *)block) + 16;
647  len -= templen;
648  while (templen > 0) {
649  *output++ ^= *data++;
650  --templen;
651  }
652  rekey();
653  }
654  } else {
655  // There was no input data, so just force a rekey so we
656  // get some mixing of the state even without new data.
657  rekey();
658  }
659 
660  // Save if this is the first time we have reached max entropy.
661  // This provides some protection if the system is powered off before
662  // the first auto-save timeout occurs.
663  if (firstSave && credits >= RNG_MAX_CREDITS) {
664  firstSave = 0;
665  save();
666  }
667 }
668 
696 {
697  // Generate random data from the current state and save
698  // that as the seed. Then force a rekey.
699  ++(block[12]);
700  ChaCha::hashCore(stream, block, RNG_ROUNDS);
701 #if defined(RNG_EEPROM)
702  // We shorten the seed from 48 bytes to 47 to leave room for
703  // the CRC-8 value. We do this to align the data on an 8-byte
704  // boundary in EERPOM.
705  int address = RNG_EEPROM_ADDRESS;
706  eeprom_write_block(stream, (void *)address, SEED_SIZE - 1);
707  eeprom_write_byte((uint8_t *)(address + SEED_SIZE - 1),
708  crypto_crc8('S', stream, SEED_SIZE - 1));
709 #elif defined(RNG_DUE_TRNG)
710  unsigned posn;
711  ((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8('S', stream, SEED_SIZE);
712  for (posn = 0; posn < 12; ++posn)
713  ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
714  for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
715  ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
716  eraseAndWriteSeed();
717 #endif
718  rekey();
719  timer = millis();
720 }
721 
729 {
730  // Stir in the entropy from all registered noise sources.
731  for (uint8_t posn = 0; posn < count; ++posn)
732  noiseSources[posn]->stir();
733 
734 #if defined(RNG_DUE_TRNG)
735  // If there is data available from the Arudino Due's TRNG, then XOR
736  // it with the state block and increase the entropy credit. We don't
737  // call stir() yet because that will seriously slow down the system
738  // given how fast the TRNG is. Instead we save up the XOR'ed TRNG
739  // data until the next rand() call and then hash it to generate the
740  // desired output.
741  //
742  // The CPU documentation claims that the TRNG output is very good so
743  // this should only make the pool more and more random as time goes on.
744  // However there is a risk that the CPU manufacturer was pressured by
745  // government or intelligence agencies to insert a back door that
746  // generates predictable output. Or the manufacturer was overly
747  // optimistic about their TRNG design and it is actually flawed in a
748  // way they don't realise.
749  //
750  // If you are concerned about such threats, then make sure to mix in
751  // data from other noise sources. By hashing together the TRNG with
752  // the other noise data, rand() should produce unpredictable data even
753  // if one of the sources is actually predictable.
754  if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
755  block[4 + trngPosn] ^= REG_TRNG_ODATA;
756  if (++trngPosn >= 12)
757  trngPosn = 0;
758  if (credits < RNG_MAX_CREDITS) {
759  // Credit 1 bit of entropy for the word. The TRNG should be
760  // better than this but it is so fast that we want to collect
761  // up more data before passing it to the application.
762  ++credits;
763  }
764  }
765 #elif defined(RNG_WATCHDOG)
766  // Read the 32 bit buffer from the WDT interrupt.
767  cli();
768  if (outBits >= 32) {
769  uint32_t value = hash;
770  hash = 0;
771  outBits = 0;
772  sei();
773 
774  // Final steps of the Jenkin's one-at-a-time hash function.
775  // https://en.wikipedia.org/wiki/Jenkins_hash_function
776  value += leftShift3(value);
777  value ^= rightShift11(value);
778  value += leftShift15(value);
779 
780  // XOR the word with the state. Stir once we accumulate 48 bytes,
781  // which happens about once every 6.4 seconds.
782  block[4 + trngPosn] ^= value;
783  if (++trngPosn >= 12) {
784  trngPosn = 0;
785 
786  // Credit 1 bit of entropy for each byte of input. It can take
787  // between 30 and 40 seconds to accumulate 256 bits of credit.
788  stir(0, 0, 48);
789  }
790  } else {
791  sei();
792  }
793 #endif
794 
795  // Save the seed if the auto-save timer has expired.
796  if ((millis() - timer) >= timeout)
797  save();
798 }
799 
820 {
821  clean(block);
822  clean(stream);
823 #if defined(RNG_EEPROM)
824  int address = RNG_EEPROM_ADDRESS;
825  for (int posn = 0; posn < SEED_SIZE; ++posn)
826  eeprom_write_byte((uint8_t *)(address + posn), 0xFF);
827 #elif defined(RNG_DUE_TRNG)
828  for (unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
829  ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF;
830  eraseAndWriteSeed();
831 #endif
832 }
833 
837 void RNGClass::rekey()
838 {
839  // Rekey the cipher for the next request by generating a new block.
840  // This is intended to make it difficult to wind the random number
841  // backwards if the state is captured later. The first 16 bytes of
842  // "block" remain set to "tagRNG".
843  ++(block[12]);
844  ChaCha::hashCore(stream, block, RNG_ROUNDS);
845  memcpy(block + 4, stream, 48);
846 
847  // Permute the high word of the counter using the system microsecond
848  // counter to introduce a little bit of non-stir randomness for each
849  // request. Note: If random data is requested on a predictable schedule
850  // then this may not help very much. It is still necessary to stir in
851  // high quality entropy data on a regular basis using stir().
852  block[13] ^= micros();
853 }
void save()
Saves the random seed to EEPROM.
Definition: RNG.cpp:695
void rand(uint8_t *data, size_t len)
Generates random bytes into a caller-supplied buffer.
Definition: RNG.cpp:516
void begin(const char *tag)
Initializes the random number generator.
Definition: RNG.cpp:360
Abstract base class for random noise sources.
Definition: NoiseSource.h:29
~RNGClass()
Destroys this random number generator instance.
Definition: RNG.cpp:251
virtual void added()
Called when the noise source is added to RNG with RNG.addNoiseSource().
Definition: NoiseSource.cpp:95
void addNoiseSource(NoiseSource &source)
Adds a noise source to the random number generator.
Definition: RNG.cpp:467
RNGClass()
Constructs a new random number generator instance.
Definition: RNG.cpp:238
void destroy()
Destroys the data in the random number pool and the saved seed in EEPROM.
Definition: RNG.cpp:819
bool available(size_t len) const
Determine if there is sufficient entropy available for a specific request size.
Definition: RNG.cpp:593
void loop()
Run periodic housekeeping tasks on the random number generator.
Definition: RNG.cpp:728
Pseudo random number generator suitable for cryptography.
Definition: RNG.h:31
static const int SEED_SIZE
Size of a saved random number seed in EEPROM space.
Definition: RNG.h:53
static void hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds)
Executes the ChaCha hash core on an input memory block.
Definition: ChaCha.cpp:253
void stir(const uint8_t *data, size_t len, unsigned int credit=0)
Stirs additional entropy data into the random pool.
Definition: RNG.cpp:626
void setAutoSaveTime(uint16_t minutes)
Sets the amount of time between automatic seed saves.
Definition: RNG.cpp:492