【兆易GD32H759I-EVAL】 硬件随机数试验
[复制链接]
真随机数生成器(TRNG)
简介
- 真随机数生成器(TRNG):与传统的伪随机数生成器(PRNG)不同,TRNG基于物理过程(如模拟噪声)来生成随机数,因此其输出在理论上不可预测且不可重复。
- NIST SP800-90B标准:这是一个由美国国家标准技术研究院(NIST)制定的标准,用于指导随机数和伪随机数的生成、使用和统计测试。
主要特征
-
LFSR模式和NIST模式:
- LFSR模式:基于线性反馈移位寄存器(Linear Feedback Shift Register)的伪随机数生成模式。由于它是基于算法的,所以生成的随机数不是真正的随机,但在许多应用中可以作为随机数的近似。
- NIST模式:遵循NIST SP800-90B标准的真随机数生成模式。它基于物理过程(如模拟噪声)来生成随机数。
-
随机数产生速率:
- LFSR模式下:两个连续随机数的间隔大约为40个
TRNG_CLK 时钟周期,每次产生32位随机数。
- NIST模式下:每次可产生32位 * 4或32位 * 8的随机数。
-
NIST SP800-90B标准健康测试:TRNG模块支持NIST推荐的统计测试,以确保生成的随机数满足随机性要求。
-
健康测试功能及错误标志:TRNG模块具有内置的健康测试功能,如果检测到随机数不满足随机性要求,将设置相关的错误标志。
-
功耗管理:关闭TRNG模块可以一定程度上降低功耗,这在不需要频繁生成随机数的应用中是有用的。
-
128位随机数种子:通过模拟信号噪声生成128位随机数种子,用于在NIST模式下初始化或重新初始化随机数生成过程。这有助于确保即使在同一设备上,每次启动或重新初始化TRNG时都能获得不同的随机数序列。
实验代码
#include "gd32h7xx.h"
#include "gd32h759i_eval.h"
#include "systick.h"
#include <stdio.h>
/*!
\brief enable the CPU cache
\param[in] none
\param[out] none
\retval none
*/
void cache_enable(void)
{
/* enable I-Cache */
SCB_EnableICache();
/* enable D-Cache */
SCB_EnableDCache();
}
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] 检查随机数准备状态
* @param 无
* @retval 0, 随机数有效;
* 1, 随机数无效;
*/
uint8_t trng_ready_check(void)
{
uint32_t timeout = 0;
FlagStatus trng_flag = RESET;
while((RESET == trng_flag) && (0xFFFF > timeout)) /* 检查随机数是否有效 */
{
timeout++;
trng_flag = trng_flag_get(TRNG_FLAG_DRDY);
}
if (SET == trng_flag) /* 随机数有效 */
{
if (RESET == trng_flag_get(TRNG_FLAG_CECS)) /* 当前是否检测到时钟错误 */
{
if (RESET == trng_flag_get(TRNG_FLAG_SECS)) /* 当前是否检测到种子错误 */
{
return 0;
}
}
}
printf("error occurred! : %x \r\n", TRNG_STAT); /* 查看TRNG状态寄存器内容 */
return 1;
}
/**
* @brief 初始化TRNG
* @param 无
* @retval 0,成功;1,失败
*/
uint8_t trng_init(void)
{
uint8_t reval = 0;
/* TRNG时钟配置 */
rcu_osci_on(RCU_IRC48M); /* 打开IRC48M振荡器 */
if (ERROR == rcu_osci_stab_wait(RCU_IRC48M)) /* 等待IRC48M振荡器时钟稳定 */
{
return 1;
}
rcu_ck48m_clock_config(RCU_CK48MSRC_IRC48M); /* 选择IRC48M作为CK48M时钟的时钟源 */
rcu_periph_clock_enable(RCU_TRNG); /* 使能TRNG时钟 */
trng_deinit(); /* 复位TRNG */
trng_conditioning_reset_enable(); /* 复位逻辑训练单元使能 */
trng_mode_config(TRNG_MODSEL_LFSR); /* 配置TRNG工作在LFSR模式 */
trng_conditioning_disable(); /* 失能TRNG训练单元 */
trng_enable(); /* 使能TRNG接口 */
reval = trng_ready_check(); /* 检查随机数是否准备就绪 */
return reval;
}
/**
* @brief 得到真随机数
* @param 无
* @retval 获取到的真随机数(32bit)
*/
uint32_t trng_get_random_num(void)
{
uint32_t random_data;
while (SUCCESS == trng_ready_check()); /* 等待随机数准备就绪 */
random_data = trng_get_true_random_data(); /* 获取真随机值 */
return random_data;
}
/**
* @brief 得到某个范围内的随机数
* @param min,max: 区间最小,最大值.
* @retval 得到的随机数(rval),满足:min<=rval<=max
*/
int trng_get_random_range(int min, int max)
{
uint32_t random_data;
while (SUCCESS == trng_ready_check()); /* 等待随机数准备就绪 */
random_data = trng_get_true_random_data(); /* 获取真随机值 */
return random_data % (max - min + 1) + min;
}
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
uint32_t random;
/* enable the CPU Cache */
cache_enable();
uint8_t x = 0;
gd_eval_com_init(EVAL_COM);
printf(" address = %02x\n\r", x);
gd_eval_led_init(LED1);
trng_init();
while(1) {
gd_eval_led_toggle(LED1);
random = trng_get_random_num(); /* 获取一次随机数 */
printf(" random_num %d\n\r", random);
random = trng_get_random_range(0, 100); /* 取[0,9]区间的随机数 */
printf(" random_range %d\n\r", random);
}
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(EVAL_COM, (uint8_t)ch);
while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TC));
return ch;
}
实验现象
|