rp2/moduos: Implement uos.urandom().

The implementation samples rosc.randombits at a frequency lower than the
oscillator frequency.  This gives better random values.  In addition, for
an 8-bit value 8 samples are taken and fed through a 8-bit CRC,
distributing the sampling over the byte.  The resulting sampling rate is
about 120k/sec.

The RNG does not include testing of error conditions, like the ROSC being
in sync with the sampling or completely failing.  Making the interim value
static causes it to perform a little bit better in short sync or drop-out
situations.

The output of uos.urandom() performs well with the NIST800-22 test suite.
In my trial it passed all tests of the sts 2.1.2 test suite.  I also ran a
test of the random data with the Common Criteria test suite AIS 31, and it
passed all tests too.
This commit is contained in:
robert-hh 2021-03-17 07:57:27 +01:00 committed by Damien George
parent 2c9af1c1d7
commit 6f06dcaee5
2 changed files with 28 additions and 2 deletions

View File

@ -30,6 +30,7 @@
#include "py/runtime.h" #include "py/runtime.h"
#include "py/gc.h" #include "py/gc.h"
#include "py/mperrno.h" #include "py/mperrno.h"
#include "py/mphal.h"
#include "py/stackctrl.h" #include "py/stackctrl.h"
#include "lib/mp-readline/readline.h" #include "lib/mp-readline/readline.h"
#include "lib/utils/gchelper.h" #include "lib/utils/gchelper.h"
@ -168,10 +169,21 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
} }
#endif #endif
#define POLY (0xD5)
uint8_t rosc_random_u8(size_t cycles) {
static uint8_t r;
for (size_t i = 0; i < cycles; ++i) {
r = ((r << 1) | rosc_hw->randombit) ^ (r & 0x80 ? POLY : 0);
mp_hal_delay_us_fast(1);
}
return r;
}
uint32_t rosc_random_u32(void) { uint32_t rosc_random_u32(void) {
uint32_t value = 0; uint32_t value = 0;
for (size_t i = 0; i < 32; ++i) { for (size_t i = 0; i < 4; ++i) {
value = value << 1 | rosc_hw->randombit; value = value << 8 | rosc_random_u8(32);
} }
return value; return value;
} }

View File

@ -31,6 +31,8 @@
#include "extmod/vfs_lfs.h" #include "extmod/vfs_lfs.h"
#include "genhdr/mpversion.h" #include "genhdr/mpversion.h"
uint8_t rosc_random_u8(size_t cycles);
STATIC const qstr os_uname_info_fields[] = { STATIC const qstr os_uname_info_fields[] = {
MP_QSTR_sysname, MP_QSTR_nodename, MP_QSTR_sysname, MP_QSTR_nodename,
MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
@ -57,10 +59,22 @@ STATIC mp_obj_t os_uname(void) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
STATIC mp_obj_t os_urandom(mp_obj_t num) {
mp_int_t n = mp_obj_get_int(num);
vstr_t vstr;
vstr_init_len(&vstr, n);
for (int i = 0; i < n; i++) {
vstr.buf[i] = rosc_random_u8(8);
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
STATIC const mp_rom_map_elem_t os_module_globals_table[] = { STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
{ MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
{ MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
#if MICROPY_VFS #if MICROPY_VFS
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },