mirror of
https://github.com/polhenarejos/pico-rng.git
synced 2026-04-09 17:25:51 +02:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f009dc267c | ||
|
|
4137861a21 | ||
|
|
a79296b423 | ||
|
|
ad4119a653 | ||
|
|
80b03d4e8e |
27
README.md
27
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Raspberry Pi Pico Random Number Generator
|
# Raspberry Pi Pico Random Number Generator
|
||||||
|
|
||||||
** This fork includes an enhanced RNG to produce a true RNG. **
|
**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.
|
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.
|
||||||
|
|
||||||
@@ -89,8 +89,9 @@ Fig. 1 depicts the distribution of the bytes, from `0` to `255`. Ideally, it mus
|
|||||||
|
|
||||||
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.
|
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` and `dieharder` tests. These are the results obtained with pico-rng:
|
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
|
$ ent sample.rng
|
||||||
Entropy = 7.999999 bits per byte.
|
Entropy = 7.999999 bits per byte.
|
||||||
@@ -114,6 +115,7 @@ Serial correlation coefficient is 0.000006 (totally uncorrelated = 0.0).
|
|||||||
|
|
||||||
These results show that pico-rng is pretty random.
|
These results show that pico-rng is pretty random.
|
||||||
|
|
||||||
|
### FIPS 140-2
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cat sample.rng | rngtest
|
$ cat sample.rng | rngtest
|
||||||
@@ -140,6 +142,27 @@ 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 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`.
|
- 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
|
```bash
|
||||||
$ dieharder -a -g 201 -k 2 -Y 1 -m 2 -f sample.rng
|
$ dieharder -a -g 201 -k 2 -Y 1 -m 2 -f sample.rng
|
||||||
#=============================================================================#
|
#=============================================================================#
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ add_executable(pico_rng
|
|||||||
pico_rng.c
|
pico_rng.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(pico_rng PRIVATE pico_stdlib hardware_resets hardware_irq hardware_adc)
|
target_link_libraries(pico_rng PRIVATE pico_stdlib hardware_adc)
|
||||||
|
|
||||||
pico_enable_stdio_uart(pico_rng 1)
|
pico_enable_stdio_uart(pico_rng 1)
|
||||||
pico_add_extra_outputs(pico_rng)
|
pico_add_extra_outputs(pico_rng)
|
||||||
|
|||||||
@@ -33,6 +33,22 @@ static inline uint32_t board_millis(void)
|
|||||||
return to_ms_since_boot(get_absolute_time());
|
return to_ms_since_boot(get_absolute_time());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BLINK_NOT_MOUNTED = (250 << 16) | 250,
|
||||||
|
BLINK_MOUNTED = (250 << 16) | 250,
|
||||||
|
BLINK_SUSPENDED = (500 << 16) | 1000,
|
||||||
|
BLINK_PROCESSING = (50 << 16) | 50,
|
||||||
|
|
||||||
|
BLINK_ALWAYS_ON = UINT32_MAX,
|
||||||
|
BLINK_ALWAYS_OFF = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
|
||||||
|
|
||||||
|
void led_set_blink(uint32_t mode) {
|
||||||
|
blink_interval_ms = mode;
|
||||||
|
}
|
||||||
|
|
||||||
// Device descriptors
|
// Device descriptors
|
||||||
#include "pico_rng.h"
|
#include "pico_rng.h"
|
||||||
|
|
||||||
@@ -521,6 +537,40 @@ void isr_usbctrl(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void led_blinking_task() {
|
||||||
|
#ifdef PICO_DEFAULT_LED_PIN
|
||||||
|
static uint32_t start_ms = 0;
|
||||||
|
static uint8_t led_state = false;
|
||||||
|
static uint8_t led_color = PICO_DEFAULT_LED_PIN;
|
||||||
|
#ifdef PICO_DEFAULT_LED_PIN_INVERTED
|
||||||
|
uint32_t interval = !led_state ? blink_interval_ms & 0xffff : blink_interval_ms >> 16;
|
||||||
|
#else
|
||||||
|
uint32_t interval = led_state ? blink_interval_ms & 0xffff : blink_interval_ms >> 16;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Blink every interval ms
|
||||||
|
if (board_millis() - start_ms < interval)
|
||||||
|
return; // not enough time
|
||||||
|
start_ms += interval;
|
||||||
|
|
||||||
|
gpio_put(led_color, led_state);
|
||||||
|
led_state ^= 1; // toggle
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void led_off_all() {
|
||||||
|
#ifdef PIMORONI_TINY2040
|
||||||
|
gpio_put(TINY2040_LED_R_PIN, 1);
|
||||||
|
gpio_put(TINY2040_LED_G_PIN, 1);
|
||||||
|
gpio_put(TINY2040_LED_B_PIN, 1);
|
||||||
|
#else
|
||||||
|
#ifdef PICO_DEFAULT_LED_PIN
|
||||||
|
gpio_put(PICO_DEFAULT_LED_PIN, 0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EP0 in transfer complete. Either finish the SET_ADDRESS process, or receive a zero
|
* @brief EP0 in transfer complete. Either finish the SET_ADDRESS process, or receive a zero
|
||||||
* length status packet from the host.
|
* length status packet from the host.
|
||||||
@@ -559,6 +609,7 @@ void ep0_out_handler(uint8_t *buf, uint16_t len) {
|
|||||||
* @param len the length of the random data in bytes
|
* @param len the length of the random data in bytes
|
||||||
*/
|
*/
|
||||||
void get_random_data(char *buf, uint16_t len) {
|
void get_random_data(char *buf, uint16_t len) {
|
||||||
|
led_set_blink(BLINK_PROCESSING);
|
||||||
if (len > 64)
|
if (len > 64)
|
||||||
len = 64;
|
len = 64;
|
||||||
memset(buf, 0, len);
|
memset(buf, 0, len);
|
||||||
@@ -585,6 +636,7 @@ void get_random_data(char *buf, uint16_t len) {
|
|||||||
}
|
}
|
||||||
memcpy(buf + i, &random_word, sizeof(random_word));
|
memcpy(buf + i, &random_word, sizeof(random_word));
|
||||||
}
|
}
|
||||||
|
led_set_blink(BLINK_MOUNTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -610,6 +662,22 @@ int main(void) {
|
|||||||
// Enable uart debug messages
|
// Enable uart debug messages
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
|
#ifdef PIMORONI_TINY2040
|
||||||
|
gpio_init(TINY2040_LED_R_PIN);
|
||||||
|
gpio_set_dir(TINY2040_LED_R_PIN, GPIO_OUT);
|
||||||
|
gpio_init(TINY2040_LED_G_PIN);
|
||||||
|
gpio_set_dir(TINY2040_LED_G_PIN, GPIO_OUT);
|
||||||
|
gpio_init(TINY2040_LED_B_PIN);
|
||||||
|
gpio_set_dir(TINY2040_LED_B_PIN, GPIO_OUT);
|
||||||
|
#else
|
||||||
|
#ifdef PICO_DEFAULT_LED_PIN
|
||||||
|
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||||
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
led_off_all();
|
||||||
|
|
||||||
// ADC
|
// ADC
|
||||||
adc_init();
|
adc_init();
|
||||||
adc_gpio_init(27);
|
adc_gpio_init(27);
|
||||||
@@ -623,6 +691,8 @@ int main(void) {
|
|||||||
tight_loop_contents();
|
tight_loop_contents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
led_set_blink(BLINK_MOUNTED);
|
||||||
|
|
||||||
// Populate the TX buffer
|
// Populate the TX buffer
|
||||||
get_random_data(ep1_buf, 64);
|
get_random_data(ep1_buf, 64);
|
||||||
usb_start_transfer(usb_get_endpoint_configuration(EP1_IN_ADDR), ep1_buf, 64);
|
usb_start_transfer(usb_get_endpoint_configuration(EP1_IN_ADDR), ep1_buf, 64);
|
||||||
@@ -630,6 +700,7 @@ int main(void) {
|
|||||||
// Everything is interrupt driven so just loop here
|
// Everything is interrupt driven so just loop here
|
||||||
while (1) {
|
while (1) {
|
||||||
tight_loop_contents();
|
tight_loop_contents();
|
||||||
|
led_blinking_task();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ parser = argparse.ArgumentParser(description="Raspberry Pi Pico Random Number Ge
|
|||||||
parser.add_argument("--performance", action="store_true", help="Performance test the RNG.")
|
parser.add_argument("--performance", action="store_true", help="Performance test the RNG.")
|
||||||
parser.add_argument("--endless", action="store_true", help="Outputs random bytes endlessly.")
|
parser.add_argument("--endless", action="store_true", help="Outputs random bytes endlessly.")
|
||||||
parser.add_argument("--size", default="100", help="Number of bytes to output.")
|
parser.add_argument("--size", default="100", help="Number of bytes to output.")
|
||||||
|
parser.add_argument("--vid", default="0000", help="VID.")
|
||||||
|
parser.add_argument("--pid", default="0004", help="PID.")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# If this is set, then the /dev/pico_rng file exists
|
# If this is set, then the /dev/pico_rng file exists
|
||||||
@@ -24,7 +26,7 @@ if os.path.exists("/dev/pico_rng"):
|
|||||||
# File does not exist, test with usb.core
|
# File does not exist, test with usb.core
|
||||||
if not rng_chardev:
|
if not rng_chardev:
|
||||||
# Get the device
|
# Get the device
|
||||||
rng = usb.core.find(idVendor=0x0000, idProduct=0x0004)
|
rng = usb.core.find(idVendor=int(args.vid, base=16), idProduct=int(args.pid, base=16))
|
||||||
assert rng is not None
|
assert rng is not None
|
||||||
|
|
||||||
# Get the configuration of the device
|
# Get the configuration of the device
|
||||||
|
|||||||
Reference in New Issue
Block a user