Skip to content

Instantly share code, notes, and snippets.

@endolith
Last active November 18, 2024 15:46

Revisions

  1. endolith revised this gist Nov 18, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -60,7 +60,7 @@ Histogram of output:

    ![histogram](https://farm8.staticflickr.com/7258/6985796104_cbc8d4eb3f.jpg)

    [Gallery of tests of both TrueRandom and ProbablyRandom](https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/)
    [Gallery of tests of both TrueRandom and ProbablyRandom](https://flickr.com/photos/56868697@N00/sets/72157629934367149/)

    I've also tested without the TimerOne library (`probably_random.ino`), just sampling the Arduino's constantly-cycling PWM timers instead of configuring and resetting Timer 1, and it doesn't seem to hurt the randomness:

  2. endolith renamed this gist Nov 18, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions readme.md → README.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    My attempt at a hardware random number generator in Arduino with no external components.
    The ["TrueRandom" library is *not* truly random](https://gist.github.com/endolith/2472824), and [uses whitening which obfuscates this](https://www.endolith.com/wordpress/2013/06/19/truerandom-is-not-truly-random/), so this is my attempt at a hardware random number generator in Arduino with no external components.

    Only produces ~64 bit/s because of the minimum length of the watchdog timer. :(

    @@ -18,7 +18,7 @@ randomness from its analog pins."

    Disclaimer: I have no idea what I'm doing.

    But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom). ["TrueRandom" is not truly random](https://gist.github.com/endolith/2472824):
    But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom):

    Entropy = 7.544390 bits per byte.

  3. endolith revised this gist Mar 20, 2021. 1 changed file with 21 additions and 0 deletions.
    21 changes: 21 additions & 0 deletions LICENSE.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    MIT License

    Copyright (c) 2012 endolith

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
  4. endolith revised this gist Feb 5, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -60,7 +60,7 @@ Histogram of output:

    ![histogram](https://farm8.staticflickr.com/7258/6985796104_cbc8d4eb3f.jpg)

    https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/
    [Gallery of tests of both TrueRandom and ProbablyRandom](https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/)

    I've also tested without the TimerOne library (`probably_random.ino`), just sampling the Arduino's constantly-cycling PWM timers instead of configuring and resetting Timer 1, and it doesn't seem to hurt the randomness:

  5. endolith revised this gist Feb 5, 2013. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,9 @@ It seems to work. I think the main flaw would be if the two oscillators become
    the micro-controller and conclude that it should not be used to produce
    randomness from its analog pins."

    Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom): ["TrueRandom" is not truly random.](https://gist.github.com/endolith/2472824):
    Disclaimer: I have no idea what I'm doing.

    But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom). ["TrueRandom" is not truly random](https://gist.github.com/endolith/2472824):

    Entropy = 7.544390 bits per byte.

  6. endolith revised this gist Feb 5, 2013. 1 changed file with 15 additions and 3 deletions.
    18 changes: 15 additions & 3 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -16,9 +16,21 @@ It seems to work. I think the main flaw would be if the two oscillators become
    the micro-controller and conclude that it should not be used to produce
    randomness from its analog pins."

    Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom).
    Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom): ["TrueRandom" is not truly random.](https://gist.github.com/endolith/2472824):

    [ent](http://www.fourmilab.ch/random/) says:
    Entropy = 7.544390 bits per byte.

    Optimum compression would reduce the size
    of this 92810048 byte file by 5 percent.

    Chi square distribution for 92810048 samples is 131287892.21, and randomly
    would exceed this value 0.01 percent of the times.

    Arithmetic mean value of data bytes is 93.7178 (127.5 = random).
    Monte Carlo value for Pi is 3.682216212 (error 17.21 percent).
    Serial correlation coefficient is -0.008583 (totally uncorrelated = 0.0).

    For comparison, with `probably_random_with_TimerOne.ino`, [ent](http://www.fourmilab.ch/random/) says:

    Entropy = 7.996943 bits per byte.

    @@ -48,7 +60,7 @@ Histogram of output:

    https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/

    I've also tested without the TimerOne library, just sampling the Arduino's constantly-cycling PWM timers instead of configuring and resetting Timer 1, and it doesn't seem to hurt the randomness:
    I've also tested without the TimerOne library (`probably_random.ino`), just sampling the Arduino's constantly-cycling PWM timers instead of configuring and resetting Timer 1, and it doesn't seem to hurt the randomness:

    Entropy = 7.999969 bits per byte.

  7. endolith revised this gist May 12, 2012. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,9 @@
    My attempt at a hardware random number generator in Arduino with no external components. (Tested only on a Duemilanove. May not work on other hardware. Post a comment if you try it on other hardware or if you find a scenario where it doesn't work.)
    My attempt at a hardware random number generator in Arduino with no external components.

    Only produces ~64 bit/s because of the minimum length of the watchdog timer. :(

    Tested only on a Duemilanove. May not work on other hardware. Post a comment if you try it on other hardware or if you find a scenario where it doesn't work.

    It uses the watchdog timer to sample (and reset) Timer 1. Since the watchdog timer runs on its own RC oscillator, and Timer 1 is on the crystal oscillator, there is random variation in the value read. Then the randomness is spread around to all 8 bits by reading 8 times and bit-shifting and XORing, to produce a random byte.

    The assumption is that at least one bit in each sample is truly random. Though in reality, probably multiple bits have varying amounts of entropy? The raw read from the timer sampling is estimated at 4.4 bits of entropy per byte.
  8. endolith revised this gist May 12, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    My attempt at a hardware random number generator in Arduino with no external components. (Tested only on a Duemilanove. Let me know if you try it on other hardware or if you find a scenario where it doesn't work.)
    My attempt at a hardware random number generator in Arduino with no external components. (Tested only on a Duemilanove. May not work on other hardware. Post a comment if you try it on other hardware or if you find a scenario where it doesn't work.)

    Only produces ~64 bit/s because of the minimum length of the watchdog timer. :(

  9. endolith revised this gist May 12, 2012. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -4,9 +4,9 @@ Only produces ~64 bit/s because of the minimum length of the watchdog timer. :(

    It uses the watchdog timer to sample (and reset) Timer 1. Since the watchdog timer runs on its own RC oscillator, and Timer 1 is on the crystal oscillator, there is random variation in the value read. Then the randomness is spread around to all 8 bits by reading 8 times and bit-shifting and XORing, to produce a random byte.

    The assumption is that at least one bit in each sample is truly random. Though in reality, probably multiple bits have varying amounts of entropy? The raw read from the timers is estimated at 4.4 bits of entropy per byte.
    The assumption is that at least one bit in each sample is truly random. Though in reality, probably multiple bits have varying amounts of entropy? The raw read from the timer sampling is estimated at 4.4 bits of entropy per byte.

    It seems to work. I think the main flaw would be if the two oscillators become correlated to each other in certain hardware configurations or at certain points in time, which I haven't noticed.
    It seems to work. I think the main flaw would be if the two oscillators become correlated to each other in certain hardware configurations or at certain points in time, which I haven't noticed, despite running it continuously for days.

    * [Entropy gathering for cryptographic applications in AVR - Qualification of WDT as entropy source](http://wap.taur.dk/engather.pdf) (125 bits per second)
    * [True Random Number Generation on an AtmelAVR Microcontroller](http://www.scribd.com/doc/51705150/TRUERA-1) (8 bits per second)
  10. endolith revised this gist May 11, 2012. 1 changed file with 10 additions and 10 deletions.
    20 changes: 10 additions & 10 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -48,17 +48,17 @@ https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/

    I've also tested without the TimerOne library, just sampling the Arduino's constantly-cycling PWM timers instead of configuring and resetting Timer 1, and it doesn't seem to hurt the randomness:

    Entropy = 7.997157 bits per byte.

    Entropy = 7.999969 bits per byte.
    Optimum compression would reduce the size
    of this 65536 byte file by 0 percent.

    Chi square distribution for 65536 samples is 258.33, and randomly
    would exceed this value 43.01 percent of the times.

    Arithmetic mean value of data bytes is 127.2593 (127.5 = random).
    Monte Carlo value for Pi is 3.120307636 (error 0.68 percent).
    Serial correlation coefficient is 0.003113 (totally uncorrelated = 0.0).
    of this 5489591 byte file by 0 percent.
    Chi square distribution for 5489591 samples is 233.95, and randomly
    would exceed this value 75.00 percent of the times.
    Arithmetic mean value of data bytes is 127.4536 (127.5 = random).
    Monte Carlo value for Pi is 3.145767276 (error 0.13 percent).
    Serial correlation coefficient is -0.001267 (totally uncorrelated = 0.0).

    So you should be able to use all the inputs and outputs normally, and still generate random numbers. The LSBs will still be noisy even if the MSBs are periodic, and XORing the two will preserve only the randomness of the LSBs.

  11. endolith revised this gist May 3, 2012. 1 changed file with 37 additions and 0 deletions.
    37 changes: 37 additions & 0 deletions tester.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    # -*- coding: utf-8 -*-

    from __future__ import division
    import serial
    from pylab import *
    from time import time
    import Image

    size = 2**16

    with serial.Serial('COM6', 115200) as port:
    start_time = time()
    data += port.read(size)
    elapsed_time = time() - start_time

    print 'Read ' + str(size) + ' bytes in ' + str(int(round(elapsed_time))) + ' s'
    print 'Data rate: %.1f bit/s' % (size*8 / elapsed_time)

    # Binary dump
    with open(str(int(time())) + 'out.bin','wb') as f:
    f.write(data)

    a = numpy.fromstring(data, dtype = 'uint8')

    # Plot
    figure()
    plot(a, 'bo', alpha=0.1) # Transparent to show stackups

    # Histogram
    figure()
    hist(a, bins=64, range=[0,255])

    # Image
    repeat = int(sqrt(size))
    b = reshape(a[:len(a) - len(a)%repeat], (-1, repeat))
    im = Image.fromarray(b)
    im.save(str(int(time())) + 'out.png')
  12. endolith revised this gist May 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    My attempt at a hardware random number generator in Arduino with no external components. Tested only on a Duemilanove.
    My attempt at a hardware random number generator in Arduino with no external components. (Tested only on a Duemilanove. Let me know if you try it on other hardware or if you find a scenario where it doesn't work.)

    Only produces ~64 bit/s because of the minimum length of the watchdog timer. :(

  13. endolith revised this gist May 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -64,6 +64,6 @@ So you should be able to use all the inputs and outputs normally, and still gene

    Obviously if your program turns off Timer 1 completely, this will no longer produce random numbers. (But it doesn't use any obfuscation or whitening other than the XOR shifting, so if you feed it nothing but 0s, it will output nothing but 0s and it will be obvious.)

    Using *Clear Timer on Compare* mode should be ok.
    Using *Clear Timer on Compare* mode should be ok, as long as the compare isn't correlated with the watchdog. If you use the watchdog timer to reset Timer 1 before reading it, for instance, you won't get random numbers. :)

    Not sure about switching Timer 1 to other prescalers. Is it possible to run Timer 1 so slowly that it doesn't change between samples? That would be bad.
  14. endolith revised this gist May 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -36,7 +36,7 @@ Output as an image:

    ![noise](https://farm8.staticflickr.com/7095/6985793444_74c6359a4b_o.png)

    Output scatter plotted (`plot(a[1:], 'bo', alpha=0.1)`):
    Output scatter plotted (`plot(a, 'bo', alpha=0.1)`):

    ![plot](https://farm8.staticflickr.com/7099/6985796316_e9d7e3e2a0.jpg)

  15. endolith revised this gist May 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    My attempt at a hardware random number generator in Arduino with no external components.
    My attempt at a hardware random number generator in Arduino with no external components. Tested only on a Duemilanove.

    Only produces ~64 bit/s because of the minimum length of the watchdog timer. :(

  16. endolith revised this gist May 2, 2012. 3 changed files with 73 additions and 40 deletions.
    62 changes: 28 additions & 34 deletions probably_random.ino
    Original file line number Diff line number Diff line change
    @@ -1,66 +1,60 @@
    #include <stdint.h>
    #include <avr/interrupt.h>
    #include <avr/wdt.h>
    #include <TimerOne.h>

    byte result = 0;
    boolean result_waiting = false;
    byte sample = 0;
    boolean sample_waiting = false;
    byte current_bit = 0;
    byte working_byte = 0;

    // Rotate bits to the left
    // https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts
    byte rotl(const byte value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
    return value;
    return (value << shift) | (value >> (sizeof(value)*8 - shift));
    }
    byte result = 0;

    void setup() {
    Serial.begin(115200);
    wdtSetup();
    Timer1.initialize(30000); // set a timer of length somewhat longer than watchdog length
    }

    void loop()
    {
    if (result_waiting) {
    result_waiting = false;
    if (sample_waiting) {
    sample_waiting = false;

    working_byte = rotl(working_byte, 1);
    working_byte ^= result;
    result = rotl(result, 1); // Spread randomness around
    result ^= sample; // XOR preserves randomness

    current_bit++;
    if (current_bit > 7)
    if (current_bit > 7)
    {
    Serial.write(working_byte); // raw binary
    //Serial.println(working_byte, DEC); // decimal text
    //binprint(working_byte); // bits
    current_bit = 0;
    Serial.write(result); // raw binary
    }
    }
    }

    // Rotate bits to the left
    // https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts
    byte rotl(const byte value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
    return value;
    return (value << shift) | (value >> (sizeof(value)*8 - shift));
    }

    // Setup of the watchdog timer.
    void wdtSetup() {
    cli();
    MCUSR = 0;
    WDTCSR |= B00011000;
    WDTCSR = B01000000; // interrupt mode, shortest rate: 2048 cycles ~= 16 ms
    sei();
    }

    /* Start timed sequence */
    WDTCSR |= _BV(WDCE) | _BV(WDE);

    void binprint(int input) {
    for (unsigned int mask = 0x80; mask; mask >>= 1) {
    Serial.print(mask&input?'1':'0');
    }
    Serial.println();
    /* Put WDT into interrupt mode */
    /* Set shortest prescaler(time-out) value = 2048 cycles (~16 ms) */
    WDTCSR = _BV(WDIE);

    sei();
    }

    // Watchdog Timer Interrupt
    // Watchdog Timer Interrupt Service Routine
    ISR(WDT_vect)
    {
    result = TCNT1L; // Ignore higher bits
    TCNT1 = 0; // Clear Timer 1
    result_waiting = true;
    sample = TCNT1L; // Ignore higher bits
    sample_waiting = true;
    }
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    #include <stdint.h>
    #include <avr/interrupt.h>
    #include <avr/wdt.h>
    #include <TimerOne.h>

    byte sample = 0;
    boolean sample_waiting = false;
    @@ -10,6 +11,7 @@ byte result = 0;
    void setup() {
    Serial.begin(115200);
    wdtSetup();
    Timer1.initialize(30000); // set a timer of length somewhat longer than watchdog length
    }

    void loop()
    @@ -25,11 +27,14 @@ void loop()
    {
    current_bit = 0;
    Serial.write(result); // raw binary
    //Serial.println(result, DEC); // decimal text
    //binprint(result); // bits
    }
    }
    }

    // Rotate bits to the left
    // Rotate bits to the left
    // https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts
    byte rotl(const byte value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
    return value;
    @@ -55,5 +60,15 @@ void wdtSetup() {
    ISR(WDT_vect)
    {
    sample = TCNT1L; // Ignore higher bits
    TCNT1 = 0; // Clear Timer 1
    sample_waiting = true;
    }

    // Print binary numbers
    // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1193507343/5#5
    void binprint(int input) {
    for (unsigned int mask = 0x80; mask; mask >>= 1) {
    Serial.print(mask&input?'1':'0');
    }
    Serial.println();
    }
    34 changes: 29 additions & 5 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,19 @@
    My attempt at a hardware random number generator in Arduino with no external components.

    Only produces 60 bit/s because of the minimum length of the watchdog timer. :(
    Only produces ~64 bit/s because of the minimum length of the watchdog timer. :(

    It uses the watchdog timer to sample (and reset) Timer 1. Since the watchdog timer runs on its own RC oscillator, and Timer 1 is on the crystal oscillator, there is random variation in the value read. Assuming at least one bit in each value is truly random, the randomness is spread around to all 8 bits by reading 8 times and bit-shifting and XORing, to produce a random byte. The raw read from the timers is estimated at 4.4 bits of entropy per byte. It seems to work. I think the main flaw would be if the two oscillators become correlated to each other in certain hardware configurations or at certain points in time, which I haven't noticed.
    It uses the watchdog timer to sample (and reset) Timer 1. Since the watchdog timer runs on its own RC oscillator, and Timer 1 is on the crystal oscillator, there is random variation in the value read. Then the randomness is spread around to all 8 bits by reading 8 times and bit-shifting and XORing, to produce a random byte.

    The assumption is that at least one bit in each sample is truly random. Though in reality, probably multiple bits have varying amounts of entropy? The raw read from the timers is estimated at 4.4 bits of entropy per byte.

    It seems to work. I think the main flaw would be if the two oscillators become correlated to each other in certain hardware configurations or at certain points in time, which I haven't noticed.

    * [Entropy gathering for cryptographic applications in AVR - Qualification of WDT as entropy source](http://wap.taur.dk/engather.pdf) (125 bits per second)
    * [True Random Number Generation on an AtmelAVR Microcontroller](http://www.scribd.com/doc/51705150/TRUERA-1) (8 bits per second)
    * [Ardrand: The Arduino as a Hardware Random-Number Generator](http://benedikt.sudo.is/ardrand.pdf) "We explore various methods to extract true randomness from
    the micro-controller and conclude that it should not be used to produce
    randomness from its analog pins."

    Could probably be modified to just read Arduino's constantly-cycling timers instead of configuring and resetting Timer 1, without hurting the randomness. The LSBs will still be noisy even if the MSBs are periodic, and XORing the two will preserve the randomness.

    Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom).

    [ent](http://www.fourmilab.ch/random/) says:
    @@ -42,4 +44,26 @@ Histogram of output:

    ![histogram](https://farm8.staticflickr.com/7258/6985796104_cbc8d4eb3f.jpg)

    https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/
    https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/

    I've also tested without the TimerOne library, just sampling the Arduino's constantly-cycling PWM timers instead of configuring and resetting Timer 1, and it doesn't seem to hurt the randomness:

    Entropy = 7.997157 bits per byte.

    Optimum compression would reduce the size
    of this 65536 byte file by 0 percent.

    Chi square distribution for 65536 samples is 258.33, and randomly
    would exceed this value 43.01 percent of the times.

    Arithmetic mean value of data bytes is 127.2593 (127.5 = random).
    Monte Carlo value for Pi is 3.120307636 (error 0.68 percent).
    Serial correlation coefficient is 0.003113 (totally uncorrelated = 0.0).

    So you should be able to use all the inputs and outputs normally, and still generate random numbers. The LSBs will still be noisy even if the MSBs are periodic, and XORing the two will preserve only the randomness of the LSBs.

    Obviously if your program turns off Timer 1 completely, this will no longer produce random numbers. (But it doesn't use any obfuscation or whitening other than the XOR shifting, so if you feed it nothing but 0s, it will output nothing but 0s and it will be obvious.)

    Using *Clear Timer on Compare* mode should be ok.

    Not sure about switching Timer 1 to other prescalers. Is it possible to run Timer 1 so slowly that it doesn't change between samples? That would be bad.
  17. endolith revised this gist May 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    My attempt at a hardware random number generator in Arduino with no external components.

    Only produces 68 bit/s because of the minimum length of the watchdog timer. :(
    Only produces 60 bit/s because of the minimum length of the watchdog timer. :(

    It uses the watchdog timer to sample (and reset) Timer 1. Since the watchdog timer runs on its own RC oscillator, and Timer 1 is on the crystal oscillator, there is random variation in the value read. Assuming at least one bit in each value is truly random, the randomness is spread around to all 8 bits by reading 8 times and bit-shifting and XORing, to produce a random byte. The raw read from the timers is estimated at 4.4 bits of entropy per byte. It seems to work. I think the main flaw would be if the two oscillators become correlated to each other in certain hardware configurations or at certain points in time, which I haven't noticed.

  18. endolith revised this gist May 2, 2012. 2 changed files with 61 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions probably_random.ino
    Original file line number Diff line number Diff line change
    @@ -27,11 +27,11 @@ void loop()
    if (result_waiting) {
    result_waiting = false;

    working_byte ^= result;
    working_byte = rotl(working_byte, 1);
    working_byte ^= result;

    current_bit++;
    if (current_bit = 7)
    if (current_bit > 7)
    {
    Serial.write(working_byte); // raw binary
    //Serial.println(working_byte, DEC); // decimal text
    59 changes: 59 additions & 0 deletions probably_random_no_TimerOne.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    #include <stdint.h>
    #include <avr/interrupt.h>
    #include <avr/wdt.h>

    byte sample = 0;
    boolean sample_waiting = false;
    byte current_bit = 0;
    byte result = 0;

    void setup() {
    Serial.begin(115200);
    wdtSetup();
    }

    void loop()
    {
    if (sample_waiting) {
    sample_waiting = false;

    result = rotl(result, 1); // Spread randomness around
    result ^= sample; // XOR preserves randomness

    current_bit++;
    if (current_bit > 7)
    {
    current_bit = 0;
    Serial.write(result); // raw binary
    }
    }
    }

    // Rotate bits to the left
    byte rotl(const byte value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
    return value;
    return (value << shift) | (value >> (sizeof(value)*8 - shift));
    }

    // Setup of the watchdog timer.
    void wdtSetup() {
    cli();
    MCUSR = 0;

    /* Start timed sequence */
    WDTCSR |= _BV(WDCE) | _BV(WDE);

    /* Put WDT into interrupt mode */
    /* Set shortest prescaler(time-out) value = 2048 cycles (~16 ms) */
    WDTCSR = _BV(WDIE);

    sei();
    }

    // Watchdog Timer Interrupt
    ISR(WDT_vect)
    {
    sample = TCNT1L; // Ignore higher bits
    sample_waiting = true;
    }
  19. endolith revised this gist May 1, 2012. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -28,6 +28,8 @@ Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRan
    Monte Carlo value for Pi is 3.126899835 (error 0.47 percent).
    Serial correlation coefficient is -0.007752 (totally uncorrelated = 0.0).

    Generating the 13 GB required by [dieharder](http://www.phy.duke.edu/~rgb/General/dieharder.php) would take about 48 years. :D

    Output as an image:

    ![noise](https://farm8.staticflickr.com/7095/6985793444_74c6359a4b_o.png)
  20. endolith revised this gist May 1, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@ randomness from its analog pins."

    Could probably be modified to just read Arduino's constantly-cycling timers instead of configuring and resetting Timer 1, without hurting the randomness. The LSBs will still be noisy even if the MSBs are periodic, and XORing the two will preserve the randomness.

    Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom):
    Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom).

    [ent](http://www.fourmilab.ch/random/) says:

  21. endolith revised this gist May 1, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    My attempt at a hardware random number generator in Arduino with no external components.

    Produces 68 bit/s because of the minimum length of the watchdog timer.
    Only produces 68 bit/s because of the minimum length of the watchdog timer. :(

    It uses the watchdog timer to sample (and reset) Timer 1. Since the watchdog timer runs on its own RC oscillator, and Timer 1 is on the crystal oscillator, there is random variation in the value read. Assuming at least one bit in each value is truly random, the randomness is spread around to all 8 bits by reading 8 times and bit-shifting and XORing, to produce a random byte. The raw read from the timers is estimated at 4.4 bits of entropy per byte. It seems to work. I think the main flaw would be if the two oscillators become correlated to each other in certain hardware configurations or at certain points in time, which I haven't noticed.

  22. endolith revised this gist May 1, 2012. 1 changed file with 10 additions and 1 deletion.
    11 changes: 10 additions & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,17 @@ My attempt at a hardware random number generator in Arduino with no external com

    Produces 68 bit/s because of the minimum length of the watchdog timer.

    Could probably be modified to read Arduino's constantly-cycling timers instead of configuring and resetting Timer 1 without hurting the randomness.
    It uses the watchdog timer to sample (and reset) Timer 1. Since the watchdog timer runs on its own RC oscillator, and Timer 1 is on the crystal oscillator, there is random variation in the value read. Assuming at least one bit in each value is truly random, the randomness is spread around to all 8 bits by reading 8 times and bit-shifting and XORing, to produce a random byte. The raw read from the timers is estimated at 4.4 bits of entropy per byte. It seems to work. I think the main flaw would be if the two oscillators become correlated to each other in certain hardware configurations or at certain points in time, which I haven't noticed.

    * [Entropy gathering for cryptographic applications in AVR - Qualification of WDT as entropy source](http://wap.taur.dk/engather.pdf) (125 bits per second)
    * [True Random Number Generation on an AtmelAVR Microcontroller](http://www.scribd.com/doc/51705150/TRUERA-1) (8 bits per second)
    * [Ardrand: The Arduino as a Hardware Random-Number Generator](http://benedikt.sudo.is/ardrand.pdf) "We explore various methods to extract true randomness from
    the micro-controller and conclude that it should not be used to produce
    randomness from its analog pins."

    Could probably be modified to just read Arduino's constantly-cycling timers instead of configuring and resetting Timer 1, without hurting the randomness. The LSBs will still be noisy even if the MSBs are periodic, and XORing the two will preserve the randomness.

    Disclaimer: I have no idea what I'm doing. But it measures better than [TrueRandom](https://code.google.com/p/tinkerit/wiki/TrueRandom):

    [ent](http://www.fourmilab.ch/random/) says:

  23. endolith revised this gist May 1, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,7 @@ Output as an image:

    ![noise](https://farm8.staticflickr.com/7095/6985793444_74c6359a4b_o.png)

    Output scatter plotted:
    Output scatter plotted (`plot(a[1:], 'bo', alpha=0.1)`):

    ![plot](https://farm8.staticflickr.com/7099/6985796316_e9d7e3e2a0.jpg)

  24. endolith revised this gist May 1, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@ My attempt at a hardware random number generator in Arduino with no external com

    Produces 68 bit/s because of the minimum length of the watchdog timer.

    Could probably be modified to read Arduino's constantly-cycling timers instead of configuring and resetting Timer 1.
    Could probably be modified to read Arduino's constantly-cycling timers instead of configuring and resetting Timer 1 without hurting the randomness.


    [ent](http://www.fourmilab.ch/random/) says:
  25. endolith revised this gist May 1, 2012. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -20,12 +20,15 @@ Could probably be modified to read Arduino's constantly-cycling timers instead o
    Serial correlation coefficient is -0.007752 (totally uncorrelated = 0.0).

    Output as an image:

    ![noise](https://farm8.staticflickr.com/7095/6985793444_74c6359a4b_o.png)

    Output scatter plotted:

    ![plot](https://farm8.staticflickr.com/7099/6985796316_e9d7e3e2a0.jpg)

    Histogram of output:

    ![histogram](https://farm8.staticflickr.com/7258/6985796104_cbc8d4eb3f.jpg)

    https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/
  26. endolith created this gist May 1, 2012.
    66 changes: 66 additions & 0 deletions probably_random.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    #include <stdint.h>
    #include <avr/interrupt.h>
    #include <avr/wdt.h>
    #include <TimerOne.h>

    byte result = 0;
    boolean result_waiting = false;
    byte current_bit = 0;
    byte working_byte = 0;

    // Rotate bits to the left
    // https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts
    byte rotl(const byte value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
    return value;
    return (value << shift) | (value >> (sizeof(value)*8 - shift));
    }

    void setup() {
    Serial.begin(115200);
    wdtSetup();
    Timer1.initialize(30000); // set a timer of length somewhat longer than watchdog length
    }

    void loop()
    {
    if (result_waiting) {
    result_waiting = false;

    working_byte ^= result;
    working_byte = rotl(working_byte, 1);

    current_bit++;
    if (current_bit = 7)
    {
    Serial.write(working_byte); // raw binary
    //Serial.println(working_byte, DEC); // decimal text
    //binprint(working_byte); // bits
    current_bit = 0;
    }
    }
    }

    // Setup of the watchdog timer.
    void wdtSetup() {
    cli();
    MCUSR = 0;
    WDTCSR |= B00011000;
    WDTCSR = B01000000; // interrupt mode, shortest rate: 2048 cycles ~= 16 ms
    sei();
    }

    void binprint(int input) {
    for (unsigned int mask = 0x80; mask; mask >>= 1) {
    Serial.print(mask&input?'1':'0');
    }
    Serial.println();
    }

    // Watchdog Timer Interrupt
    ISR(WDT_vect)
    {
    result = TCNT1L; // Ignore higher bits
    TCNT1 = 0; // Clear Timer 1
    result_waiting = true;
    }
    31 changes: 31 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    My attempt at a hardware random number generator in Arduino with no external components.

    Produces 68 bit/s because of the minimum length of the watchdog timer.

    Could probably be modified to read Arduino's constantly-cycling timers instead of configuring and resetting Timer 1.


    [ent](http://www.fourmilab.ch/random/) says:

    Entropy = 7.996943 bits per byte.

    Optimum compression would reduce the size
    of this 65536 byte file by 0 percent.

    Chi square distribution for 65536 samples is 277.59, and randomly
    would exceed this value 15.83 percent of the times.

    Arithmetic mean value of data bytes is 127.8158 (127.5 = random).
    Monte Carlo value for Pi is 3.126899835 (error 0.47 percent).
    Serial correlation coefficient is -0.007752 (totally uncorrelated = 0.0).

    Output as an image:
    ![noise](https://farm8.staticflickr.com/7095/6985793444_74c6359a4b_o.png)

    Output scatter plotted:
    ![plot](https://farm8.staticflickr.com/7099/6985796316_e9d7e3e2a0.jpg)

    Histogram of output:
    ![histogram](https://farm8.staticflickr.com/7258/6985796104_cbc8d4eb3f.jpg)

    https://secure.flickr.com/photos/56868697@N00/sets/72157629934367149/