diff --git a/src/crypto/rand/rand_baremetal.go b/src/crypto/rand/rand_baremetal.go index fe9fea2a..e4103684 100644 --- a/src/crypto/rand/rand_baremetal.go +++ b/src/crypto/rand/rand_baremetal.go @@ -1,5 +1,5 @@ -//go:build nrf52840 || stm32 || (sam && atsamd51) || (sam && atsame5x) -// +build nrf52840 stm32 sam,atsamd51 sam,atsame5x +//go:build nrf || stm32 || (sam && atsamd51) || (sam && atsame5x) +// +build nrf stm32 sam,atsamd51 sam,atsame5x package rand diff --git a/src/machine/machine_nrf.go b/src/machine/machine_nrf.go index 43a680ae..c291821c 100644 --- a/src/machine/machine_nrf.go +++ b/src/machine/machine_nrf.go @@ -350,3 +350,30 @@ func (i2c *I2C) readByte() (byte, error) { i2c.Bus.EVENTS_RXDREADY.Set(0) return byte(i2c.Bus.RXD.Get()), nil } + +var rngStarted = false + +// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise. +// According to Nordic's documentation, the random output is suitable for cryptographic purposes. +func GetRNG() (ret uint32, err error) { + // There's no apparent way to check the status of the RNG peripheral's task, so simply start it + // to avoid deadlocking while waiting for output. + if !rngStarted { + nrf.RNG.TASKS_START.Set(1) + nrf.RNG.SetCONFIG_DERCEN(nrf.RNG_CONFIG_DERCEN_Enabled) + rngStarted = true + } + + // The RNG returns one byte at a time, so stack up four bytes into a single uint32 for return. + for i := 0; i < 4; i++ { + // Wait for data to be ready. + for nrf.RNG.EVENTS_VALRDY.Get() == 0 { + } + // Append random byte to output. + ret = (ret << 8) ^ nrf.RNG.GetVALUE() + // Unset the EVENTS_VALRDY register to avoid reading the same random output twice. + nrf.RNG.EVENTS_VALRDY.Set(0) + } + + return ret, nil +} diff --git a/src/machine/machine_nrf52840_rng.go b/src/machine/machine_nrf52840_rng.go deleted file mode 100644 index 1d4eba04..00000000 --- a/src/machine/machine_nrf52840_rng.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build nrf52840 -// +build nrf52840 - -package machine - -import ( - "device/nrf" -) - -// Implementation based on Nordic Semiconductor's nRF52840 documentation version 1.7 found here: -// https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.7.pdf - -// SetRNGBiasCorrection configures the RNG peripheral's bias correction mechanism. Note that when -// bias correction is enabled, the peripheral is slower to produce random values. -func SetRNGBiasCorrection(enabled bool) { - var val uint32 - if enabled { - val = nrf.RNG_CONFIG_DERCEN_Enabled - } - nrf.RNG.SetCONFIG_DERCEN(val) -} - -// RNGBiasCorrectionEnabled determines whether the RNG peripheral's bias correction mechanism is -// enabled or not. -func RNGBiasCorrectionEnabled() bool { - return nrf.RNG.GetCONFIG_DERCEN() == nrf.RNG_CONFIG_DERCEN_Enabled -} - -// StartRNG starts the RNG peripheral core. This is automatically called by GetRNG, but can be -// manually called for interacting with the RNG peripheral directly. -func StartRNG() { - nrf.RNG.SetTASKS_START(nrf.RNG_TASKS_START_TASKS_START_Trigger) -} - -// StopRNG stops the RNG peripheral core. This is not called automatically. It may make sense to -// manually disable RNG peripheral for power conservation. -func StopRNG() { - nrf.RNG.SetTASKS_STOP(nrf.RNG_TASKS_STOP_TASKS_STOP_Trigger) -} - -// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise. -// According to Nordic's documentation, the random output is suitable for cryptographic purposes. -func GetRNG() (ret uint32, err error) { - // There's no apparent way to check the status of the RNG peripheral's task, so simply start it - // to avoid deadlocking while waiting for output. - StartRNG() - - // The RNG returns one byte at a time, so stack up four bytes into a single uint32 for return. - for i := 0; i < 4; i++ { - // Wait for data to be ready. - for nrf.RNG.GetEVENTS_VALRDY() == nrf.RNG_EVENTS_VALRDY_EVENTS_VALRDY_NotGenerated { - } - // Append random byte to output. - ret = (ret << 8) ^ nrf.RNG.GetVALUE() - // Unset the EVENTS_VALRDY register to avoid reading the same random output twice. - nrf.RNG.SetEVENTS_VALRDY(nrf.RNG_EVENTS_VALRDY_EVENTS_VALRDY_NotGenerated) - } - - return ret, nil -}