随机数检测(一)- 随机数自测试概述
- 1 概述
- 2 产品形态划分和检测项目
- 3 测试方式
- 3.1 概述
- 3.2 单比特频数检测方法
- 3.3块内频数检测方法
1 概述
随机数发生器设计完成后,使用随机数发生器的产品需对其执行测试,防止应用过程中产生不合规的随机数。对于密码产品而言,对随机数发生器输出数据的检测一般称为随机数自测试。这里的随机数自测试为使用过程的自测试,注意与随机数发生器设计时的自测试区分开来。
确定密码产品需执行的随机数自测试项目前,应首先按照GM/T 0062确定产品所属类型。对应不同类型的密码产品,应执行不同阶段的检测项目。检测项目的实现方式在GM/T 0005中定义。
2 产品形态划分和检测项目
按照GM/T0062要求,密码产品可分为ABCDE五种类型。依据所属类型确定随机数自测试的检测项。
类型 | 划分依据 | 典型产品 |
---|---|---|
A类 | 不能独立作为功能产品使用 | 随机数发生器芯片等 |
B类 | 用时上电,随机数检测处理能力有限,对上电响应速度有严格要求 | IC卡 |
C类 | 用时上电,随机数检测处理能力有限,对上电响应速度没有严格要求 | USBKey |
D类 | 长期加电,随机数检测处理能力有限,对上电响应速度没有严格要求 | POS机 |
E类 | 长期上电,较强的随机数检测处理能力,对上电响应速度没有严格要求 | 服务器 |
随机数检测包括送样检测、出厂检测、上电检测、周期检测和单次检测。其中:
1) 送样检测在检测机构对产品测试时执行。产品自身无需关注。
2) 出厂检测在产品出厂前执行。
3) 上电检测在产品加点时自动执行。
4) 周期检测按照一定时间周期自动执行。
5) 单次检测在每次使用随机数前自动执行。
实际上多数系统类产品都属于E类产品。以E类产品为例,各测试阶段的检测项如下图。
3 测试方式
3.1 概述
GM/T 0005-2021为最新的随机性检测规范,可以在实践中代替GB/T 32915。GM/T 0005-2021规定了15中随机性检测方法:单比特频数检测方法、块内频数检测方法、扑克检测方法、重叠子序列检测方法、游程总数检测方法、游程分布检测方法、块内最大游程检测方法、二元推导检测方法、自相关检测方法、矩阵秩检测方法、 累加和检测方法、近似熵检测方法、线性复杂度检测方法、Maurer通用统计检测方法、离散傅里叶检测方法。
规范定义的样本通过率显著性水平α=0.01。样本分布均匀性检测的显著性水平αT=0.0001,子区间数量k=10。
3.2 单比特频数检测方法
以下实现代码供参考。
def monobitFrequency(epsilon:bitarray):
sn = epsilon.count(1) - epsilon.count(0)
#2021version make change
V = sn/sqrt(len(epsilon))
pvalue = math.erfc(abs(V)/sqrt(2))
qvalue = math.erfc(V/sqrt(2))/2
return {'p':pvalue, 'q':qvalue}
#test case
if __name__ == '__main__':
# input = bitarray('11001100000101010110110001001100111000000000001001001101010100010001001111010110100000001101011111001100111001101101100010110010')
input = readInputFile('.\\pi\\data.pi')
ret = monobitFrequency(input)
print('pvalue:', ret['p'])
print('qvalue:', ret['q'])
3.3块内频数检测方法
以下实现代码供参考。
def blockFrequency(epsilon:bitarray,m):
# m = getblockFrequencyM(len(epsilon))
N = int(len(epsilon)/m)
epsilonList = epsilon.tolist()
sumOfPi = 0
for i in range(N):
pi = sum(epsilonList[i*m:(i+1)*m:1])/m
sumOfPi += (pi - 0.5)**2
V = 4*m*sumOfPi
pvalue = scipy.special.gammaincc(N/2, V/2)
qvalue = pvalue
return {'p':pvalue, 'q':qvalue}
test case
if __name__ == '__main__':
input = bitarray('1100100100001111110110101010001000100001011010001100001000110100110001001100011001100010100010111000')
# input = readInputFile('.\\pi\\data.pi')
ret = blockFrequency(input,10)
print('pvalue:', ret['p'])
print('qvalue:', ret['q'])