samd/mcu: Implement a hardware seed for the SAMD21 random module.

By using the phase jitter between the DFLL48M clock and the FDPLL96M clock.
Even if both use the same reference source, they have a different jitter.
SysTick is driven by FDPLL96M, the us counter by DFLL48M.  As a random
source, the us counter is read out on every SysTick and the value is used
to accumulate a simple multiply, add and xor register.  According to tests
it creates about 30 bit random bit-flips per second.  That mechanism will
pass quite a few RNG tests, has a suitable frequency distribution and
serves better than just the time after boot to seed the PRNG.
This commit is contained in:
robert-hh
2023-01-24 20:36:19 +01:00
committed by Damien George
parent 7e0b1bc95d
commit 76cf98c35b
4 changed files with 26 additions and 4 deletions

View File

@@ -78,8 +78,9 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
// CtrlB: Set the ref ource to GCLK, set the Wakup-Fast Flag.
SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_REFCLK_GCLK | SYSCTRL_DPLLCTRLB_WUF;
// Set the FDPLL ratio and enable the DPLL.
int ldr = cpu_freq_arg / FDPLL_REF_FREQ - 1;
SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(ldr);
int ldr = cpu_freq / FDPLL_REF_FREQ;
int frac = ((cpu_freq - ldr * FDPLL_REF_FREQ) / (FDPLL_REF_FREQ / 16)) & 0x0f;
SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR((frac << 16 | ldr) - 1);
SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE;
// Wait for the DPLL lock.
while (!SYSCTRL->DPLLSTATUS.bit.LOCK) {

View File

@@ -22,6 +22,9 @@
#define MICROPY_PY_CMATH (0)
#endif
#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32())
unsigned long trng_random_u32(void);
#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages;
#ifndef MICROPY_HW_UART_TXBUF

View File

@@ -42,6 +42,9 @@ extern void EIC_Handler(void);
const ISR isr_vector[];
volatile uint32_t systick_ms;
volatile uint32_t ticks_us64_upper;
#if defined(MCU_SAMD21)
volatile uint32_t rng_state;
#endif
void Reset_Handler(void) __attribute__((naked));
void Reset_Handler(void) {
@@ -91,6 +94,12 @@ void Default_Handler(void) {
}
void SysTick_Handler(void) {
#if defined(MCU_SAMD21)
// Use the phase jitter between the clocks to get some entropy
// and accumulate the random number register.
rng_state = (rng_state * 32310901 + 1) ^ (REG_TC4_COUNT32_COUNT >> 1);
#endif
uint32_t next_tick = systick_ms + 1;
systick_ms = next_tick;
@@ -99,6 +108,13 @@ void SysTick_Handler(void) {
}
}
#if defined(MCU_SAMD21)
uint32_t trng_random_u32(void) {
mp_hal_delay_ms(320); // wait for ten cycles of the rng_seed register
return rng_state;
}
#endif
void us_timer_IRQ(void) {
#if defined(MCU_SAMD21)
if (TC4->COUNT32.INTFLAG.reg & TC_INTFLAG_OVF) {