|
| 1 | +//go:build nrf && softdevice |
| 2 | + |
| 3 | +package machine |
| 4 | + |
| 5 | +import ( |
| 6 | + "device/arm" |
| 7 | + "device/nrf" |
| 8 | + |
| 9 | + "errors" |
| 10 | +) |
| 11 | + |
| 12 | +// avoid a heap allocation in GetRNG. |
| 13 | +var ( |
| 14 | + softdeviceEnabled uint8 |
| 15 | + bytesAvailable uint8 |
| 16 | + buf [4]uint8 |
| 17 | + |
| 18 | + errNoSoftDeviceSupport = errors.New("rng: softdevice not supported on this device") |
| 19 | + errNotEnoughRandomData = errors.New("rng: not enough random data available") |
| 20 | +) |
| 21 | + |
| 22 | +// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise. |
| 23 | +// According to Nordic's documentation, the random output is suitable for cryptographic purposes. |
| 24 | +func GetRNG() (ret uint32, err error) { |
| 25 | + // First check whether the SoftDevice is enabled. |
| 26 | + // sd_rand_application_bytes_available_get cannot be called when the SoftDevice is not enabled. |
| 27 | + arm.SVCall1(0x12, &softdeviceEnabled) // sd_softdevice_is_enabled |
| 28 | + |
| 29 | + if softdeviceEnabled == 0 { |
| 30 | + return getRNG() |
| 31 | + } |
| 32 | + |
| 33 | + // call into the SoftDevice to get random data bytes available |
| 34 | + switch nrf.Device { |
| 35 | + case "nrf51": |
| 36 | + // sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4 |
| 37 | + arm.SVCall1(0x2B+4, &bytesAvailable) |
| 38 | + case "nrf52", "nrf52840", "nrf52833": |
| 39 | + // sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4 |
| 40 | + arm.SVCall1(0x2C+4, &bytesAvailable) |
| 41 | + default: |
| 42 | + return 0, errNoSoftDeviceSupport |
| 43 | + } |
| 44 | + |
| 45 | + if bytesAvailable < 4 { |
| 46 | + return 0, errNotEnoughRandomData |
| 47 | + } |
| 48 | + |
| 49 | + switch nrf.Device { |
| 50 | + case "nrf51": |
| 51 | + // sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5 |
| 52 | + arm.SVCall2(0x2B+5, &buf, 4) |
| 53 | + case "nrf52", "nrf52840", "nrf52833": |
| 54 | + // sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5 |
| 55 | + arm.SVCall2(0x2C+5, &buf, 4) |
| 56 | + } |
| 57 | + |
| 58 | + return uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24, nil |
| 59 | +} |
0 commit comments