适用于任何FPGA(甚至 ASIC)的小型且独立于平台的真随机数生成器。
neoTRNG 的目标是成为一个小型且与平台无关的真随机数生成器 (TRNG),可以针对任何目标技术(FPGA 甚至 ASIC)进行合成。它基于简单的自由运行环形振荡器,通过特殊技术对其进行了增强,以便可以针对任何平台进行合成。对自由运行的环形振荡器进行采样时出现的相位噪声被用作物理熵源。
该项目是 NEORV32 RISC-V 处理器的“衍生项目”,其中 neoTRNG 作为默认 SoC 模块实现。
主要特点
警告
内部/外部信号/事件与生成的随机数之间可能至少存在一些互相关性。因此,根本无法保证neoTRNG 提供完美的甚至加密安全的随机数!查看提供的评估结果或(更好)自己测试。此外,还没有可用的篡改检测机制或在线健康监控来检查生成的随机数据的完整性/质量。
警告
保持 neoTRNG永久启用会增加动态功耗,还可能导致芯片局部发热(当使用非常大的配置时)。此外,设计可能会发出额外的电磁干扰 (EMI)。
整个设计作为单个 VHDL 文件rtl/neoTRNG.vhd
实现,完全没有依赖项(如特殊库、包或子模块)。
entity neoTRNG is
generic (
NUM_CELLS : natural range 1 to 99 := 3 ; -- number of ring-oscillator cells
NUM_INV_START : natural range 3 to 99 := 5 ; -- number of inverters in first cell, has to be odd
SIM_MODE : boolean := false -- enable simulation mode (no physical random if enabled!)
);
port (
clk_i : in std_ulogic ; -- module clock
rstn_i : in std_ulogic ; -- module reset, low-active, async, optional
enable_i : in std_ulogic ; -- module enable (high-active)
valid_o : out std_ulogic ; -- data_o is valid when set (high for one cycle)
data_o : out std_ulogic_vector ( 7 downto 0 ) -- random data byte output
);
end neoTRNG ;
neoTRNG 使用由clk_i
信号驱动的单个时钟域。模块的复位信号rstn_i
是可选的(如果未使用,则连接至'1'
)。随机数据是通过使用简单的数据/有效接口获得的:每当有新的有效随机字节可用时, valid_o
输出将在一个周期内保持高电平,因此用户逻辑可以对data_o
输出进行采样。
enable_i
信号用于初始化和启动 TRNG。在使用 TRNG 之前,该信号应保持低电平至少 100 个时钟周期(取决于配置),以确保内部移位寄存器的所有位再次被清除。当设置了enable_i
并且设置了valid_o
时,TRNG第一次运行。禁用 TRNG 还要求enable_i
在相同数量的时钟周期内保持低电平。当enable_i
变低时,所有环形振荡器将停止,减少动态开关活动和功耗。
提供了三个泛型来配置 neoTRNG。 NUM_CELLS
定义熵单元的总数。 NUM_INV_START
定义第一个单元中的反相器数量(= 环形振荡器的长度)。这两个泛型将在下面的架构部分中进一步描述。最后一个通用SIM_MODE
可以设置为允许在普通 RTL 模拟中模拟 TRNG。
neoTRNG 基于可配置数量 ( NUM_CELLS
) 的熵单元。每个单元提供一个简单的环形振荡器(“RO”),它是使用奇数个逆变器构建的。 RO 的振荡频率由环内元件的传播延迟定义。该频率不是静态的,因为它受到热噪声电子散粒噪声引起的最小波动的影响。 RO 最后一个反相器的状态通过使用静态时钟 ( clk_i
) 采样到触发器中。由于 RO 的频率随时间混乱变化,采样数据的固有相位噪声被用作实际的熵源。
每个熵单元生成 1 位随机数据流。在通过简单的随机性提取器对流进行去偏置之前,使用宽异或门混合所有单元的输出。采样单元对几个去偏置位进行采样/去串行化,以提供字节范围的随机数。采样单元还应用简单的后处理,以改善随机数的频谱分布。
每个熵单元由一个环形振荡器组成,该环形振荡器由奇数个反相锁存器构建。第一个熵单元中环的长度由NUM_INV_START
泛型定义。每个额外的熵单元都会在这个初始链长度上添加另外 2 个反相器。因此,每个额外的熵单元以比之前更低的频率振荡。
像环形振荡器这样的异步元件很难以独立于平台的方式实现,因为它们通常需要使用特定于平台/技术的原语、属性或综合设置。为了提供真正的目标不可知架构,可以针对任何目标技术进行综合,应用了一种特殊技术:RO 内的每个反相器后面都有一个锁存器,该锁存器提供全局复位以及用于切换的单独锁存使能将锁存器设置为透明模式。
各个锁存器使能由长移位寄存器控制,该寄存器为 RO 链中的每个锁存器提供不同的 FF。当 TRNG 使能时,该移位寄存器开始填充 1。因此,锁存器是逐一单独启用的,使得综合工具不可能从 RO 链中修剪任何逻辑/元件,因为每个锁存器的启动状态(理论上)可以由外部逻辑监控。所有熵单元的使能移位寄存器均以菊花链方式连接,以在整个熵阵列上继续此启动过程。
下图显示了第一个熵单元的简化原理图,该熵单元由用于环形振荡器的 5 个反相器锁存器元件、用于使能移位寄存器的 5 个触发器以及用于同步器的另外 2 个触发器组成。
此处可以看到显示 FPGA 第一个熵单元的映射结果(由 Intel Quartus Prime 生成)的图像。它表明环形振荡器链的所有锁存器+反相器元件均已成功映射到各个 LUT4。
一旦设置了熵单元菊花链使能移位寄存器的最后一位,去偏置单元就会启动。该单元实现了一个简单的“约翰·冯·诺依曼随机性提取器”来对获得的随机数据流进行去偏。提取器实现了一个 2 位移位寄存器,用于对来自熵单元阵列的异或随机位进行采样。在每个第二个周期中,提取器都会评估两个采样位,以检查非重叠位对的边缘。
每当检测到边缘时,就会将“有效”信号发送到后续采样单元。上升沿( 01
)发出1
数据位,下降沿( 10
)发出0
数据位。因此,去偏置单元需要至少两个时钟周期来生成单个随机位。如果未检测到边沿( 00
或11
),则有效信号保持低电平并且采样单元停止。
采样单元实现了一个8位移位寄存器,将串行去偏比特流转换为字节宽度的随机数。此外,样本单元提供了简单的后处理,以改善所获得的随机样本的光谱分布。
为了生成一个字节的随机数据,采样单元将其内部移位寄存器重置为全零,并开始消耗 64 位的去偏置随机流。移位寄存器被实现为线性反馈移位寄存器(LFSR),它将输入流与寄存器的最后一位进行异或,以进一步加扰和混合随机比特流。
neoTRNG 作为 NEORV32 处理器的一部分进行评估,其中 neoTRNG 可作为标准 SoC 模块。该处理器针对运行频率为 100MHz 的 Intel Cyclone IV EP4CE22F17C6N
FPGA 进行综合。为了进行评估,使用了非常小的默认配置:实现了三个熵单元,其中第一个实现了 5 个反相器,第二个实现了 9 个反相器,第三个实现了 11 个反相器。具有更多/更大熵单元的更复杂配置可能提供“更好”的随机质量。
NUM_CELLS = 3
NUM_INV_START = 5
SIM_MODE = false
笔记
总共获得了4MB的随机数据用于评估。该数据集在发布资产中以entropy.bin
二进制文件形式提供。
为了进行简单的直方图分析,从 neoTRNG 中采样了 4MB 的随机字节。获得的字节根据其出现次数进行累积,并分类到 bin 中,其中每个 bin 代表一种特定的字节模式(1 字节 = 8 位 = 256 种不同的模式)。然后分析结果的统计特性:
[NOTE] integer numbers only
Number of samples: 4194304
Arithmetic mean: 127 (optimum would be 127)
Histogram occurrence
Average: 16384 (optimum would be 4194304/256 = 16384)
Min: 16051 = average - 333 (deviation) at bin 183 (optimum deviation would be 0)
Max: 16706 = average + 322 (deviation) at bin 144 (optimum deviation would be 0)
Average dev.: +/- 96 (optimum would be 0)
$ ent entropy.bin
Entropy = 7.994306 bits per byte.
Optimum compression would reduce the size
of this 4194304 byte file by 0 percent.
Chi square distribution for 4194304 samples is 16726.32, and randomly
would exceed this value less than 0.01 percent of the times.
Arithmetic mean value of data bytes is 127.9417 (127.5 = random).
Monte Carlo value for Pi is 3.132416851 (error 0.29 percent).
Serial correlation coefficient is 0.000496 (totally uncorrelated = 0.0).
$ rngtest < entropy.bin
rngtest 5
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 33554432
rngtest: FIPS 140-2 successes: 1676
rngtest: FIPS 140-2 failures: 1
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 0
rngtest: FIPS 140-2(2001-10-10) Runs: 1
rngtest: FIPS 140-2(2001-10-10) Long run: 0
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=138.214; avg=1557.190; max=2119.276)Mibits/s
rngtest: FIPS tests speed: (min=32.660; avg=106.337; max=111.541)Mibits/s
rngtest: Program run time: 330110 microseconds
Robert G. Brown 的 dieharder 随机数测试套件(维基百科,主页)是一个很好的工具集,用于压力测试和表征随机数生成器。
重要的
?工作正在进行中吗?
dieharder 需要大量随机样本(大约 4GB)。否则,随机数据会倒带,明显降低整体熵。现在,我使用简单的 UART 连接将数据从 FPGA 传输到 PC。但即使是更高的波特率,4GB 的数据集也需要很长时间才能发送。在我有更好的转移渠道(或者只是很多时间)之前,这个评估是“正在进行中的工作” 。
使用默认配置在 NEORV32 RISC-V 处理器内实现的 neoTRNG 的映射结果。使用 Intel Quartus Prime 为以 100MHz 运行的 Intel Cyclone EP4CE22F17C6N
FPGA 生成的结果。
Module Hierarchy Logic Cells Logic Registers
------------------------------------------------------------------------------------
neoTRNG:neoTRNG_inst 56 (27) 46 (19)
neoTRNG_cell:entropy_source:0:neoTRNG_cell_inst 8 (8) 7 (7)
neoTRNG_cell:entropy_source:1:neoTRNG_cell_inst 10 (10) 9 (9)
neoTRNG_cell:entropy_source:2:neoTRNG_cell_inst 14 (14) 11 (11)
笔记
综合工具可能会发出警告,表明已检测到锁存器和组合循环。然而,这并不是设计缺陷,因为这正是我们想要的。
neoTRNG 的最大生成率由两个因素定义:
因此,neoTRNG至少需要A * B = 2 * 64 = 128
时钟周期才能发出一个随机字节。 FPGA评估表明实际采样时间约为300个时钟周期。因此,以 100 MHz 运行的实现每秒可以生成大约 330kB 的随机数据。通过并行运行多个 neoTRNG 实例可以实现更高的生成率。
由于异步环形振荡器无法进行 RTL 仿真(由于组合循环),neoTRNG 提供了由SIM_MODE
通用函数启用的专用仿真模式。启用后,将作为简单触发器实现的“传播延迟”添加到环形振荡器的反相器中。
重要的
模拟模式仅用于模拟/调试!启用SIM_MODE
的设计可以被合成,但根本不会提供任何真实/物理随机数!
sim
文件夹使用默认配置为 neoTRNG 提供了一个简单的测试平台。测试平台会将获得的随机数据字节以十进制值输出到模拟器控制台。可以使用提供的脚本使用 GHDL 模拟测试平台:
neoTRNG/sim$ sh ghdl.sh
../rtl/neoTRNG.vhd:105:3:@0ms:(assertion note): [neoTRNG] The neoTRNG (v3.2) - A Tiny and Platform-Independent True Random Number Generator, https://github.com/stnolting/neoTRNG
../rtl/neoTRNG.vhd:112:3:@0ms:(assertion warning): [neoTRNG] Simulation-mode enabled (NO TRUE/PHYSICAL RANDOM)!
18
210
147
5
79
94
70
100
185
246
203
220
ghdl:info: simulation stopped by --stop-time @100us
GHDL 波形数据存储到sim/neoTRNG_tb.ghw
中,可以使用gtkwave
查看:
neoTRNG/sim$ gtkwave neoTRNG_tb.ghw
简单的模拟运行由项目的neoTRNG-sim
GitHub 操作工作流程执行。