最近研究随机数检测,主要学习了一下NIST和国密检测,这里整理了国密15项检测规项目的原理,数学表达式以及python源码。
15项检测项目分别为单比特频数检测、块内频数检测、扑克检测、重叠子序列检测、游程总数检测、游程分布检测、块内最大“1”游程检测、二元推导检测、自相关检测、矩阵秩检测、累加和检测、近似熵检测、线性复杂度检测、 Maurer通用统计检测、离散傅立叶检测。
规定了商用密码应用中的随机性检测指标和检测方法,适用于对随机数发生器产生的二元序列的随机性检测。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2/15 块内频数检测
a) 将待检序列 ε 分成 N = |n/m| 个长度为 m 的非重叠子序列,将多余的比特舍弃。本规范取m =100 。
b) 计算每个子序列中1所占的比例
c) 计算统计量
d) 计算
igamc 为不完全伽马函数。
e) 如果 P-value ≥ α , 则认为待检序列通过块内频数检测。
原理:
块内频数检测用来检测待检序列的m位子序列中1的个数是否接近m/2。对随机序列来说,其任意长度为m位中子序列中1的个数都应该接近m/2。
参数要求:
n>=100; m>=20
不通过分析:
m位子序列0、1分布不均衡
测试demo
import math from fractions import Fraction #from scipy.special import gamma, gammainc, gammaincc from gamma_functions import * #ones_table = [bin(i)[2:].count('1') for i in range(256)] def count_ones_zeroes(bits): ones = 0 zeroes = 0 for bit in bits: if (bit == 1): ones += 1 else: zeroes += 1 return (zeroes,ones) def frequency_within_block_test(bits): # Compute number of blocks M = block size. N=num of blocks # N = floor(n/M) # miniumum block size 20 bits, most blocks 100 n = len(bits) M = 20 N = int(math.floor(n/M)) if N > 99: N=99 M = int(math.floor(n/N)) if len(bits) < 100: print ("Too little data for test. Supply at least 100 bits") #return (FAIL,1.0,None) print (" n = %d" % len(bits)) print (" N = %d" % N) print (" M = %d" % M) num_of_blocks = N block_size = M #int(math.floor(len(bits)/num_of_blocks)) #n = int(block_size * num_of_blocks) proportions = list() for i in range(num_of_blocks): block = bits[i*(block_size):((i+1)*(block_size))] zeroes,ones= count_ones_zeroes(block) proportions.append(Fraction(ones,block_size)) chisq = 0.0 for prop in proportions: # chisq += 4.0*block_size*((prop - Fraction(1,2))**2) p = gammaincc((num_of_blocks/2.0),float(chisq)/2.0) success = (p >= 0.01) return success,p,None if __name__ == "__main__": #bit2='0111011010111101111101010000110100011000111011000101010111110001010100010011110110100111010000101010111000101' bits=[1,1,0,1,0,0,1,1,0,1,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,1, 0,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0, 0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0, 0,1,1,0,0,0,1,1,1,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,1,1, 0,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,1,1,0,0,0] s1,s2,s3= frequency_within_block_test(bits) print(s1) print("p value is %s" %s2)