# 随机数发生器

[English]

ESP32-S3 中包含一个硬件随机数发生器 (RNG)，可以调用 API `esp_random()` 和 `esp_fill_random()` 从中获取随机数值。

满足下列任意一个或多个条件时，硬件 RNG 会产生真随机数：

- RF 子系统已启用，即 Wi-Fi 或蓝牙 已启用。

- 调用 `bootloader_random_enable()` 启用了内部熵源，并且熵源尚未被 `bootloader_random_disable()` 禁用。

- 在 ESP-IDF 二级引导程序 运行时。这是因为默认的 ESP-IDF 引导加载程序启动时会调用 `bootloader_random_enable()`，并在执行应用程序前调用 `bootloader_random_disable()`。

当上述任一条件为真时，物理噪声样本会连续混合到内部硬件 RNG 状态中来提供熵。如需了解详情，请参阅 ESP32-S3 技术参考手册 > 随机数发生器 (RNG) [PDF] 章节。

如果上述条件都不满足，那么 RNG 的输出仅应被看作伪随机数。

## 启动

在启动过程中，ESP-IDF 引导加载程序暂时会启用一个非 RF 熵源（内部参考电压噪声），为首次生成的启动密钥提供熵。当应用程序开始执行后，一直到 Wi-Fi 或蓝牙 初始化完成前，通常只有伪随机数可用。

如需在应用程序启动期间临时重启熵源，或为不使用 Wi-Fi 或蓝牙 的应用程序临时重启熵源，请调用函数 `bootloader_random_enable()` 重启内部熵源。在使用 ADC、 或使用 Wi-Fi 或蓝牙 前，必须调用函数 `bootloader_random_disable()` 以禁用熵源。

备注

ESP-IDF 第二阶段引导加载程序在启动过程中启用的熵源会用熵来初始化内部 RNG 状态。但是，内部硬件 RNG 状态的大小并不足以提供连续的真随机数流。因此，在需要真随机数时必须启用连续的熵源。

备注

如果应用程序需要真随机数源，但无法永久性地启用硬件熵源，可以考虑使用软件 DRBG （确定性随机数发生器）来实现，如 mbedTLS CTR-DRBG 或 HMAC-DRBG，并使用来自硬件 RNG 真随机数来获取初始熵。

## 二级熵源

ESP32-S3 RNG 包含一个基于异步 8 MHz 内部振荡器采样的二级熵源（详情请参阅技术参考手册）。该熵源在 ESP-IDF 中始终处于启用状态，并通过硬件持续混合到 RNG 状态中。在测试中，即使在不启用主熵源时，这个二级熵源也足以通过 Dieharder 随机数测试套件（测试输入数据是通过连续重置 ESP32-S3 生成短样本并将其拼接来创建的）。但是，目前只有在同时启用上文所述的主熵源时，才能保证产生真随机数。

## API 参考

### Header File

- components/esp_hw_support/include/esp_random.h

- This header file can be included with:

  >     #include "esp_random.h"

### Functions

uint32_t esp_random(void)

  Get one random 32-bit word from hardware RNG.

  If Wi-Fi or Bluetooth are enabled, this function returns true random numbers. In other situations, if true random numbers are required then consult the ESP-IDF Programming Guide "Random Number Generation" section for necessary prerequisites.

  This function automatically busy-waits to ensure enough external entropy has been introduced into the hardware RNG state, before returning a new random number. This delay is very short (always less than 100 CPU cycles).

  返回:

    Random value between 0 and UINT32_MAX

void esp_fill_random(void *buf, size_t len)

  Fill a buffer with random bytes from hardware RNG.

  备注

  This function is implemented via calls to esp_random(), so the same constraints apply.

  参数:

    - buf -- Pointer to buffer to fill with random numbers.

    - len -- Length of buffer in bytes

### Header File

- components/bootloader_support/include/bootloader_random.h

- This header file can be included with:

  >     #include "bootloader_random.h"

- This header file is a part of the API provided by the `bootloader_support` component. To declare that your component depends on `bootloader_support`, add the following to your CMakeLists.txt:

  >     REQUIRES bootloader_support

  > or

  >     PRIV_REQUIRES bootloader_support

### Functions

void bootloader_random_enable(void)

  Enable an entropy source for RNG if RF subsystem is disabled.

  The exact internal entropy source mechanism depends on the chip in use but all SoCs use the SAR ADC to continuously mix random bits (an internal noise reading) into the HWRNG. Consult the SoC Technical Reference Manual for more information.

  Can also be called from app code, if true random numbers are required without initialized RF subsystem. This might be the case in early startup code of the application when the RF subsystem has not started yet or if the RF subsystem should not be enabled for power saving.

  Consult ESP-IDF Programming Guide "Random Number Generation" section for details.

  警告

  This function is not safe to use if any other subsystem is accessing the RF subsystem or the ADC at the same time!

void bootloader_random_disable(void)

  Disable entropy source for RNG.

  Disables internal entropy source. Must be called after bootloader_random_enable() and before RF subsystem features, ADC, or I2S (ESP32 only) are initialized.

  Consult the ESP-IDF Programming Guide "Random Number Generation" section for details.

void bootloader_fill_random(void *buffer, size_t length)

  Fill buffer with 'length' random bytes.

  备注

  If this function is being called from app code only, and never from the bootloader, then it's better to call esp_fill_random().

  参数:

    - buffer -- Pointer to buffer

    - length -- This many bytes of random data will be copied to buffer

## `getrandom()`

为方便移植，还提供了与 Linux 的 `getrandom()` 函数兼容的版本：

    #include <sys/random.h>

    ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);

此函数通过内部调用 `esp_fill_random()` 来实现。

`flags` 参数将被忽略。该函数始终是非阻塞的，但随机数的强度取决于本文档所述条件。

如果 `buf` 参数为 NULL，返回值为 -1，并将 `errno` 设置为 `EFAULT`。否则返回 `buflen`。

## `getentropy()`

为了便于移植，还提供了与 Linux 的 `getentropy()` 函数兼容的版本：

    #include <unistd.h>

    int getentropy(void *buffer, size_t length);

此函数通过内部调用 `getrandom()` 实现。

随机数强度取决于本文档所述条件。

如果执行成功则返回 0，否则返回 -1，同时：

> - 如果 `buffer` 参数为 NULL，`errno` 设置为 `EFAULT`。

> - 如果 `length` 超过 256，`errno` 设置为 `EIO`。

提供有关此文档的反馈