Skip to content

polhenarejos/pico-rng

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Raspberry Pi Pico Random Number Generator

This fork includes an enhanced RNG to transform a Pico onto a true hardware RNG.

A basic random number generator that generates numbers from enviromental noise with the onboard DAC of the Raspberry Pi Pico. The project uses the Raspberry Pi Pico USB dev_lowlevel as a starting point. The Pico RNG is not meant to be FIPS 140-2 compliant as a stand-alone device by any means. However it does supply the Linux Kernel with random bits that is used with the appropriate entropy to achieve FIPS 140-2 compliant random numbers. Maybe one day the next gen Pico's will include an onboard crypto module.

Project Goals

  • Raspberry Pi Pico firmware generates random numbers as a USB Endpoint.
  • Linux Kernel Module (aka driver) provides random numbers to the Kernel.
  • Driver can transmit random numbers on demand to the system and/or user processes via a character device.

Prerequisites

Building

The entire project uses CMake to keep with Rasberry Pi Pico's development environment and project setup instructions.

# Create build directory
mkdir build

# Change to the build directory
cd build

# Run cmake
cmake ..

# Run make
make

Install

The driver can be installed from the build directory using the traditional insmod command.

# Assumes CWD is 'build/'
# debug will enable debug log level
# timeout will set the usb endpoint timeout. Currently defaults to 100 msecs
sudo insmod driver/pico_rng.ko [debug=1] [timeout=<msec timeout>]

The Pico firmware is installed thorugh the normal process as outlined in the Raspberry Pi Pico Development Documentation.

  • Unplug the Pico from the host.
  • Plug the Pico into the host while holding the 'boot' button.
  • Mount the Pico sudo mount /dev/sdb1 /mnt. Note /dev/sdb1 could be different you. Use sudo dmesg to find out what device the Pico shows up as on your system.
  • Copy the uf2 file to the Pico sudo cp firmware/pico_rng.uf2 /mnt.
  • Umount the pico sudo umount /mnt.

Testing

You can test Pico RNG firmware with the pico_rng_test.py script.

# Running with --performance will measure the devices' KB/s.
# if the kernel module has been installed, then the test tool will use /dev/pico_rng otherwise python's libusb implementation will be used.
sudo firmware/pico_rng_test.py [--performance] [--size] [--endless]

You can also test the Kernel's random number pool that contains random numbers from the Pico Pico Random Numbers

Analysis

A set of random samples can be analyzed with the pico_rng_analyze.py script.

For generating a set of samples, the following code can be executed:

$ python3 firmware/pico_rng_test.py --size 1073741824 > sample.rng

will produce a 1 GB file containing random bytes.

Then

$ python3 firmware/pico_rng_analyze.py sample.rng

will produce two figures:

fig1

Fig. 1 depicts the distribution of the bytes, from 0 to 255. Ideally, it must be a uniform distribution, with mean equal to 127.5.

fig2

Fig. 2 depicts the distribution of chi square tests and excess percentages. Ideally, the distribution of chi square tests must follow a chi square distribution with mean at 255. Excess percentage distribution must follow a uniform distribution.

Pico-rng is also tested with ent, rngtest, sp800-90b and dieharder tests. These are the results obtained with pico-rng:

Ent

$ ent sample.rng
Entropy = 7.999999 bits per byte.

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

Chi square distribution for 1073741824 samples is 839.56, and randomly
would exceed this value less than 0.01 percent of the times.

Arithmetic mean value of data bytes is 127.4993 (127.5 = random).
Monte Carlo value for Pi is 3.141625006 (error 0.00 percent).
Serial correlation coefficient is 0.000006 (totally uncorrelated = 0.0).
  • Entropy test should produce an ideal result of 8, as each byte has 8 bits.
  • Optimum compression test should produce an ideal result of 0 percent.
  • Chi square should be called with different sample tests and produce a chi square distribution.
  • Arithmetic mean should produce an ideal result of 127.5.
  • Pi test should be equal to pi number.
  • Serial correlation should be 0.

These results show that pico-rng is pretty random.

FIPS 140-2

$ cat sample.rng | rngtest
rngtest 2-unofficial-mt.14
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source exhausted!
rngtest: bits received from input: 8589934592
rngtest: FIPS 140-2 successes: 429141
rngtest: FIPS 140-2 failures: 355
rngtest: FIPS 140-2(2001-10-10) Monobit: 42
rngtest: FIPS 140-2(2001-10-10) Poker: 41
rngtest: FIPS 140-2(2001-10-10) Runs: 138
rngtest: FIPS 140-2(2001-10-10) Long run: 136
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=9661835.749; avg=23078154805.083; max=0.000)bits/s
rngtest: FIPS tests speed: (min=5.699; avg=239.429; max=261.281)Mibits/s
rngtest: Program run time: 34612429 microseconds

In these results, we have a total number of trials 429496 (429141+355).

  • The acceptable result of Monobit test is 1 failed trial for every 9662 trials. For 429496 trials, the number of failed trials should be less than 429496/9662=44.45.
  • The acceptable result of Poker test is 1 failed trial for every 10078 trials. For 429496 trials, the number of failed trials should be less than 42.62.

SP800-90B

SP800-90b is the superseded version of FIPS 140-2 (rngtest). Can be obtained from here https://github.com/usnistgov/SP800-90B_EntropyAssessment.

$ ./ea-iid sample.rng
Calculating baseline statistics...
H_original: 7.995587
H_bitstring: 0.999863
min(H_original, 8 X H_bitstring): 7.995587
** Passed chi square tests

** Passed length of longest repeated substring test

** Passed IID permutation tests

Diehard

It is a set of different tests.

$ dieharder -a -g 201 -k 2 -Y 1 -m 2 -f sample.rng
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |           filename             |rands/second|
 file_input_raw|                      batch1.rng|  3.57e+07  |
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     200|0.17739498|  PASSED
      diehard_operm5|   0|   1000000|     200|0.97387049|  PASSED
# The file file_input_raw was rewound 1 times
  diehard_rank_32x32|   0|     40000|     200|0.37394022|  PASSED
# The file file_input_raw was rewound 2 times
    diehard_rank_6x8|   0|    100000|     200|0.09038266|  PASSED
# The file file_input_raw was rewound 2 times
   diehard_bitstream|   0|   2097152|     200|0.71785604|  PASSED
# The file file_input_raw was rewound 4 times
        diehard_opso|   0|   2097152|     200|0.37146068|  PASSED
# The file file_input_raw was rewound 5 times
        diehard_oqso|   0|   2097152|     200|0.35763562|  PASSED
# The file file_input_raw was rewound 5 times
         diehard_dna|   0|   2097152|     200|0.01889729|  PASSED
# The file file_input_raw was rewound 5 times
diehard_count_1s_str|   0|    256000|     200|0.63258197|  PASSED
# The file file_input_raw was rewound 6 times
diehard_count_1s_byt|   0|    256000|     200|0.65359815|  PASSED
# The file file_input_raw was rewound 6 times
 diehard_parking_lot|   0|     12000|     200|0.83176205|  PASSED
# The file file_input_raw was rewound 6 times
    diehard_2dsphere|   2|      8000|     200|0.64543002|  PASSED
# The file file_input_raw was rewound 6 times
    diehard_3dsphere|   3|      4000|     200|0.01258942|  PASSED
# The file file_input_raw was rewound 8 times
     diehard_squeeze|   0|    100000|     200|0.67578527|  PASSED
# The file file_input_raw was rewound 8 times
        diehard_sums|   0|       100|     200|0.23981668|  PASSED
# The file file_input_raw was rewound 8 times
        diehard_runs|   0|    100000|     200|0.77427455|  PASSED
        diehard_runs|   0|    100000|     200|0.08390099|  PASSED
# The file file_input_raw was rewound 9 times
       diehard_craps|   0|    200000|     200|0.59348655|  PASSED
       diehard_craps|   0|    200000|     200|0.23828837|  PASSED
# The file file_input_raw was rewound 24 times
 marsaglia_tsang_gcd|   0|  10000000|     200|0.15517856|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     200|0.00447239|   WEAK
# The file file_input_raw was rewound 31 times
 marsaglia_tsang_gcd|   0|  10000000|     300|0.02554040|  PASSED
 marsaglia_tsang_gcd|   0|  10000000|     300|0.00100578|   WEAK
# The file file_input_raw was rewound 39 times
 marsaglia_tsang_gcd|   0|  10000000|     400|0.00299305|   WEAK
 marsaglia_tsang_gcd|   0|  10000000|     400|0.00008767|   WEAK
# The file file_input_raw was rewound 46 times
 marsaglia_tsang_gcd|   0|  10000000|     500|0.00201489|   WEAK
 marsaglia_tsang_gcd|   0|  10000000|     500|0.00004067|   WEAK
# The file file_input_raw was rewound 54 times
 marsaglia_tsang_gcd|   0|  10000000|     600|0.00028460|   WEAK
 marsaglia_tsang_gcd|   0|  10000000|     600|0.00000323|   WEAK
# The file file_input_raw was rewound 61 times
 marsaglia_tsang_gcd|   0|  10000000|     700|0.00004334|   WEAK
 marsaglia_tsang_gcd|   0|  10000000|     700|0.00000055|  FAILED
# The file file_input_raw was rewound 61 times
         sts_monobit|   1|    100000|     200|0.11868265|  PASSED
# The file file_input_raw was rewound 61 times
            sts_runs|   2|    100000|     200|0.55674493|  PASSED
# The file file_input_raw was rewound 61 times
          sts_serial|   1|    100000|     200|0.99669244|   WEAK
          sts_serial|   2|    100000|     200|0.46102720|  PASSED
          sts_serial|   3|    100000|     200|0.44562932|  PASSED
          sts_serial|   3|    100000|     200|0.84230024|  PASSED
          sts_serial|   4|    100000|     200|0.98548763|  PASSED
          sts_serial|   4|    100000|     200|0.57495245|  PASSED
          sts_serial|   5|    100000|     200|0.77085975|  PASSED
          sts_serial|   5|    100000|     200|0.56476358|  PASSED
          sts_serial|   6|    100000|     200|0.45650075|  PASSED
          sts_serial|   6|    100000|     200|0.05289356|  PASSED
          sts_serial|   7|    100000|     200|0.27201114|  PASSED
          sts_serial|   7|    100000|     200|0.76400695|  PASSED
          sts_serial|   8|    100000|     200|0.62348338|  PASSED
          sts_serial|   8|    100000|     200|0.57277685|  PASSED
          sts_serial|   9|    100000|     200|0.38071419|  PASSED
          sts_serial|   9|    100000|     200|0.07625829|  PASSED
          sts_serial|  10|    100000|     200|0.47989859|  PASSED
          sts_serial|  10|    100000|     200|0.11112817|  PASSED
          sts_serial|  11|    100000|     200|0.92833035|  PASSED
          sts_serial|  11|    100000|     200|0.69376394|  PASSED
          sts_serial|  12|    100000|     200|0.84887524|  PASSED
          sts_serial|  12|    100000|     200|0.97617601|  PASSED
          sts_serial|  13|    100000|     200|0.65397230|  PASSED
          sts_serial|  13|    100000|     200|0.56436970|  PASSED
          sts_serial|  14|    100000|     200|0.51868029|  PASSED
          sts_serial|  14|    100000|     200|0.92953669|  PASSED
          sts_serial|  15|    100000|     200|0.85158213|  PASSED
          sts_serial|  15|    100000|     200|0.93993540|  PASSED
          sts_serial|  16|    100000|     200|0.35998600|  PASSED
          sts_serial|  16|    100000|     200|0.20807684|  PASSED
# The file file_input_raw was rewound 61 times
          sts_serial|   1|    100000|     300|0.19573096|  PASSED
          sts_serial|   2|    100000|     300|0.85406665|  PASSED
          sts_serial|   3|    100000|     300|0.06590447|  PASSED
          sts_serial|   3|    100000|     300|0.45707402|  PASSED
          sts_serial|   4|    100000|     300|0.44442263|  PASSED
          sts_serial|   4|    100000|     300|0.52775404|  PASSED
          sts_serial|   5|    100000|     300|0.40217529|  PASSED
          sts_serial|   5|    100000|     300|0.06010705|  PASSED
          sts_serial|   6|    100000|     300|0.08040223|  PASSED
          sts_serial|   6|    100000|     300|0.00547743|  PASSED
          sts_serial|   7|    100000|     300|0.24575210|  PASSED
          sts_serial|   7|    100000|     300|0.28977315|  PASSED
          sts_serial|   8|    100000|     300|0.36868885|  PASSED
          sts_serial|   8|    100000|     300|0.49522777|  PASSED
          sts_serial|   9|    100000|     300|0.40957917|  PASSED
          sts_serial|   9|    100000|     300|0.09110499|  PASSED
          sts_serial|  10|    100000|     300|0.77559781|  PASSED
          sts_serial|  10|    100000|     300|0.19716611|  PASSED
          sts_serial|  11|    100000|     300|0.80459107|  PASSED
          sts_serial|  11|    100000|     300|0.44572782|  PASSED
          sts_serial|  12|    100000|     300|0.20184427|  PASSED
          sts_serial|  12|    100000|     300|0.60780140|  PASSED
          sts_serial|  13|    100000|     300|0.76273905|  PASSED
          sts_serial|  13|    100000|     300|0.60473178|  PASSED
          sts_serial|  14|    100000|     300|0.24687487|  PASSED
          sts_serial|  14|    100000|     300|0.66722555|  PASSED
          sts_serial|  15|    100000|     300|0.85162176|  PASSED
          sts_serial|  15|    100000|     300|0.81632309|  PASSED
          sts_serial|  16|    100000|     300|0.72398028|  PASSED
          sts_serial|  16|    100000|     300|0.26061444|  PASSED
# The file file_input_raw was rewound 61 times
         rgb_bitdist|   1|    100000|     200|0.80303319|  PASSED
# The file file_input_raw was rewound 62 times
         rgb_bitdist|   2|    100000|     200|0.44511426|  PASSED
# The file file_input_raw was rewound 62 times
         rgb_bitdist|   3|    100000|     200|0.15306427|  PASSED
# The file file_input_raw was rewound 63 times
         rgb_bitdist|   4|    100000|     200|0.52424083|  PASSED
# The file file_input_raw was rewound 64 times
         rgb_bitdist|   5|    100000|     200|0.62602197|  PASSED
# The file file_input_raw was rewound 64 times
         rgb_bitdist|   6|    100000|     200|0.27582205|  PASSED
# The file file_input_raw was rewound 65 times
         rgb_bitdist|   7|    100000|     200|0.83928387|  PASSED
# The file file_input_raw was rewound 67 times
         rgb_bitdist|   8|    100000|     200|0.78920891|  PASSED
# The file file_input_raw was rewound 68 times
         rgb_bitdist|   9|    100000|     200|0.10426661|  PASSED
# The file file_input_raw was rewound 69 times
         rgb_bitdist|  10|    100000|     200|0.56345552|  PASSED
# The file file_input_raw was rewound 71 times
         rgb_bitdist|  11|    100000|     200|0.67837353|  PASSED
# The file file_input_raw was rewound 73 times
         rgb_bitdist|  12|    100000|     200|0.77285406|  PASSED
# The file file_input_raw was rewound 73 times
rgb_minimum_distance|   2|     10000|    2000|0.99326519|  PASSED
# The file file_input_raw was rewound 73 times
rgb_minimum_distance|   3|     10000|    2000|0.89490386|  PASSED
# The file file_input_raw was rewound 74 times
rgb_minimum_distance|   4|     10000|    2000|0.63482997|  PASSED
# The file file_input_raw was rewound 74 times
rgb_minimum_distance|   5|     10000|    2000|0.04956198|  PASSED
# The file file_input_raw was rewound 74 times
    rgb_permutations|   2|    100000|     200|0.59389551|  PASSED
# The file file_input_raw was rewound 74 times
    rgb_permutations|   3|    100000|     200|0.84473217|  PASSED
# The file file_input_raw was rewound 75 times
    rgb_permutations|   4|    100000|     200|0.67098621|  PASSED
# The file file_input_raw was rewound 75 times
    rgb_permutations|   5|    100000|     200|0.71477222|  PASSED
# The file file_input_raw was rewound 76 times
      rgb_lagged_sum|   0|   1000000|     200|0.20844392|  PASSED
# The file file_input_raw was rewound 77 times
      rgb_lagged_sum|   1|   1000000|     200|0.52704060|  PASSED
# The file file_input_raw was rewound 79 times
      rgb_lagged_sum|   2|   1000000|     200|0.68631913|  PASSED
# The file file_input_raw was rewound 82 times
      rgb_lagged_sum|   3|   1000000|     200|0.04971017|  PASSED
# The file file_input_raw was rewound 86 times
      rgb_lagged_sum|   4|   1000000|     200|0.11342937|  PASSED
# The file file_input_raw was rewound 91 times
      rgb_lagged_sum|   5|   1000000|     200|0.08126696|  PASSED
# The file file_input_raw was rewound 96 times
      rgb_lagged_sum|   6|   1000000|     200|0.20866831|  PASSED
# The file file_input_raw was rewound 102 times
      rgb_lagged_sum|   7|   1000000|     200|0.52239049|  PASSED
# The file file_input_raw was rewound 109 times
      rgb_lagged_sum|   8|   1000000|     200|0.68232225|  PASSED
# The file file_input_raw was rewound 116 times
      rgb_lagged_sum|   9|   1000000|     200|0.13755031|  PASSED
# The file file_input_raw was rewound 124 times
      rgb_lagged_sum|  10|   1000000|     200|0.82473876|  PASSED
# The file file_input_raw was rewound 133 times
      rgb_lagged_sum|  11|   1000000|     200|0.10861154|  PASSED
# The file file_input_raw was rewound 143 times
      rgb_lagged_sum|  12|   1000000|     200|0.10432254|  PASSED
# The file file_input_raw was rewound 153 times
      rgb_lagged_sum|  13|   1000000|     200|0.18082599|  PASSED
# The file file_input_raw was rewound 164 times
      rgb_lagged_sum|  14|   1000000|     200|0.13220862|  PASSED
# The file file_input_raw was rewound 176 times
      rgb_lagged_sum|  15|   1000000|     200|0.08158678|  PASSED
# The file file_input_raw was rewound 189 times
      rgb_lagged_sum|  16|   1000000|     200|0.02760994|  PASSED
# The file file_input_raw was rewound 202 times
      rgb_lagged_sum|  17|   1000000|     200|0.14079614|  PASSED
# The file file_input_raw was rewound 217 times
      rgb_lagged_sum|  18|   1000000|     200|0.23268911|  PASSED
# The file file_input_raw was rewound 231 times
      rgb_lagged_sum|  19|   1000000|     200|0.50758360|  PASSED
# The file file_input_raw was rewound 247 times
      rgb_lagged_sum|  20|   1000000|     200|0.66798605|  PASSED
# The file file_input_raw was rewound 263 times
      rgb_lagged_sum|  21|   1000000|     200|0.13844382|  PASSED
# The file file_input_raw was rewound 281 times
      rgb_lagged_sum|  22|   1000000|     200|0.44084188|  PASSED
# The file file_input_raw was rewound 299 times
      rgb_lagged_sum|  23|   1000000|     200|0.90104158|  PASSED
# The file file_input_raw was rewound 317 times
      rgb_lagged_sum|  24|   1000000|     200|0.80347842|  PASSED
# The file file_input_raw was rewound 337 times
      rgb_lagged_sum|  25|   1000000|     200|0.07703809|  PASSED
# The file file_input_raw was rewound 357 times
      rgb_lagged_sum|  26|   1000000|     200|0.69854447|  PASSED
# The file file_input_raw was rewound 377 times
      rgb_lagged_sum|  27|   1000000|     200|0.26315861|  PASSED
# The file file_input_raw was rewound 399 times
      rgb_lagged_sum|  28|   1000000|     200|0.58852190|  PASSED
# The file file_input_raw was rewound 421 times
      rgb_lagged_sum|  29|   1000000|     200|0.42224280|  PASSED
# The file file_input_raw was rewound 445 times
      rgb_lagged_sum|  30|   1000000|     200|0.18274721|  PASSED
# The file file_input_raw was rewound 468 times
      rgb_lagged_sum|  31|   1000000|     200|0.18647377|  PASSED
# The file file_input_raw was rewound 493 times
      rgb_lagged_sum|  32|   1000000|     200|0.83130153|  PASSED
# The file file_input_raw was rewound 493 times
     rgb_kstest_test|   0|     10000|    2000|0.05507241|  PASSED
# The file file_input_raw was rewound 494 times
     dab_bytedistrib|   0|  51200000|       2|0.22222222|  PASSED
# The file file_input_raw was rewound 494 times
             dab_dct| 256|     50000|       2|0.98359769|  PASSED
Preparing to run test 207.  ntuple = 0
# The file file_input_raw was rewound 495 times
        dab_filltree|  32|  15000000|       2|0.75609132|  PASSED
        dab_filltree|  32|  15000000|       2|1.00000000|  FAILED
Preparing to run test 208.  ntuple = 0
# The file file_input_raw was rewound 495 times
       dab_filltree2|   0|   5000000|       2|1.00000000|  FAILED
       dab_filltree2|   1|   5000000|       2|1.00000000|  FAILED
Preparing to run test 209.  ntuple = 0
# The file file_input_raw was rewound 496 times
        dab_monobit2|  12|  65000000|       2|1.00000000|  FAILED

Remove

sudo rmmod pico_rng

About the random number generator

Raspberry Pi Pico has a Ring Oscillator (ROSC) that produces a random bit, despite that it is not intended for secure applications. In general, ROSC produce weak/correlated random bits. Thus, we increase the randomness by adding more entropy sources:

  • A random word produced by ROSC.
  • A current timestamp.
  • A read from an open GPIO pin.

The produced random word is then passed through a whitener. In particular, the Fowler–Noll–Vo hash function is used as a whitener.

Finally, the word is packed into a byte array and returned to the host.

The performance of this RNG can be analyzed with pico_rng_analyze.py script and typical tools, such as ent, rngtest or dierharder. See results above.

License

This project is licensed under the BSD 3-Clause "New" or "Revised" License - see the LICENSE.md file for details

References