Files
pico-rng/README.md
Pol Henarejos 4137861a21 Update README.md
Added SP800-90B results.
2022-08-22 14:08:58 +02:00

443 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
* Raspberry Pi Pico development environment. See [Raspberry Pi Pico Getting Started Documentation](https://www.raspberrypi.org/documentation/pico/getting-started/)
* Linux Kernel development headers
## Building
The entire project uses CMake to keep with Rasberry Pi Pico's development environment and project setup instructions.
```bash
# 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.
```bash
# 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](firmware/pico_rng_test.py) script.
```bash
# 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](pico-rng.gif)
## Analysis
A set of random samples can be analyzed with the [pico_rng_analyze.py](firmware/pico_rng_analyze.py) script.
For generating a set of samples, the following code can be executed:
```bash
$ python3 firmware/pico_rng_test.py --size 1073741824 > sample.rng
```
will produce a 1 GB file containing random bytes.
Then
```bash
$ python3 firmware/pico_rng_analyze.py sample.rng
```
will produce two figures:
![fig1](https://user-images.githubusercontent.com/55573252/185908242-9fac9e7c-bfd2-440b-bd1d-045b571ed010.png)
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](https://user-images.githubusercontent.com/55573252/185908272-42973878-7c4f-45ec-8492-6878f8a0bfa6.png)
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
```bash
$ 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](https://github.com/usnistgov/SP800-90B_EntropyAssessment).
```bash
$ ./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.
```bash
$ 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
```bash
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 FowlerNollVo 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](firmware/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](LICENSE.md) file for details
### References
* https://github.com/raspberrypi/pico-examples/tree/master/usb/device/dev_lowlevel