ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

生成随机性检测测试样本——e、pi、√2、√3的前一亿比特

生成随机性检测测试样本——e、pi、√2、√3的前一亿比特

1. 背景

随机性检测文档NIST SP800-22rev1a (A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications)中提到,他们提供了四个样本——由Mathematica生成的经典常数的二进制展开,长度均超过 100 万位,分别为

  1. data.e(自然常数 e 的二进制展开)、
  2. data.pi(圆周率 π 的二进制展开)、
  3. data.sqrt2(√2 的二进制展开)
  4. data.sqrt3(√3 的二进制展开)。

生成这些文件所使用的 Mathematica 程序见NIST SP800-22rev1a的附录 F。在NIST SP800-22rev1a的附录 B 给出这些样本数据的实证结果,对每个数据文件,均应用了NIST SP800-22rev1a的所有统计测试,并将结果记录在表格中。

GM/T 00052021《随机性检测规范》中给出三种样本长度,分别是20,000比特、1,000,000比特、100,000,000比特。NIST SP800-22rev1a中给出的四个样本可用于GM/T 00052021中的前两种样本长度的检测,但无法满足100,000,000比特的要求。

以下给出生成这四种样本的100,000,000比特的python代码,以便测试使用。

2. python代码

python代码生成四种样本(eπ√2√3)的前100,000,000比特。注意,这里沿用NIST的设定——输出的比特是包括整数部分的比特序列,而不是仅小数部分的二进制展开。

例如,NIST提供的data.pi就是把整个pi进行二进制展开。data.pi的第一行给出了24比特数据,为“110010010000111111011010”,这里的前两比特“11”就是表示整数部分3。如果认为这24比特是纯小数部分的展开,则“110010010000111111011010= 1/2 + 1/4 + 0/8 + 0/16 + 1/32... = 0.785398126,这显然不等于pi的纯小数部分。

AI生成的python代码如下。

import mpmath import time def set_precision(bit_length: int) -> None: """设置mpmath的二进制精度(添加10位冗余抵消误差)""" mpmath.mp.prec = bit_length + 10 # 冗余位确保计算精度 def get_high_precision_number(num_type: str): """获取指定类型的高精度数(mpmath.mpf类型)""" if num_type == "e": return mpmath.e elif num_type == "pi": return mpmath.pi elif num_type == "sqrt2": return mpmath.sqrt(2) elif num_type == "sqrt3": return mpmath.sqrt(3) else: raise ValueError(f"不支持的数类型:{num_type},可选值:e、pi、sqrt2、sqrt3") def number_to_binary(fname: str, num, num_type: str, total_bits: int, chunk_size: int = 10**6) -> None: """ 将高精度数转换为指定长度的二进制串(块级处理优化版) :param num: 高精度数(mpmath.mpf类型) :param num_type: 数的类型(用于文件名) :param total_bits: 目标二进制总长度 :param chunk_size: 每次处理的块大小(比特) """ start_time = time.perf_counter() #fname = f"{num_type}_binary_{total_bits}.txt" print(f"正在计算{num_type}的{total_bits}比特二进制串,将写入文件:{fname}") print(f"write int(num)...") # 步骤1:处理整数部分 int_part = mpmath.floor(num) frac_part = num - int_part # 纯小数部分(0 ≤ frac_part < 1) int_bin = bin(int(mpmath.nint(int_part)))[2:] # 整数部分二进制(不含'0b') write_bits = len(int_bin) # 若整数部分已超过总长度,直接截断 if write_bits >= total_bits: with open(fname, "w", encoding="ascii") as f: f.write(int_bin[:total_bits]) print(f"整数部分过长,已截断为{total_bits}比特") return # 步骤2:处理小数部分(块级批量处理) print(f"write frac(num)...") remaining = total_bits - write_bits # 还需生成的小数位数 current_frac = frac_part with open(fname, "w", encoding="ascii") as f: f.write(int_bin) # 先写入整数部分 while remaining > 0: # 本次处理的块大小(最后一块可能不足chunk_size) current_chunk = min(chunk_size, remaining) # 计算2^current_chunk(用于批量提取位) scale = mpmath.power(2, current_chunk) # 批量获取当前块的整数部分 product = current_frac * scale c = int(mpmath.floor(product)) # 块内二进制对应的整数 # 转换为二进制字符串,不足current_chunk位则在前面补0 bin_str = format(c, f'0{current_chunk}b') # 写入文件 f.write(bin_str) # 更新剩余小数部分和计数 current_frac = product - c # 仅保留小数部分 remaining -= current_chunk # 打印进度 print(f".", end='') print(f"\n成功生成{total_bits}比特的二进制串,文件:{fname}") end_time = time.perf_counter() print(f"number_to_binary 耗时:{end_time - start_time:.3f}秒") if __name__ == "__main__": # 配置参数 num_type = "pi" # 可选:e、pi、sqrt2、sqrt3 total_bits = 10**8 # 目标二进制长度(1亿比特) chunk_size = 10**6 # 块大小(100万比特/块,可根据内存调整) fname = f"d:\\{num_type}_binary_{total_bits}.txt"#生成的比特序列文件 # 执行流程 set_precision(total_bits) high_prec_num = get_high_precision_number(num_type) number_to_binary(fname, high_prec_num, num_type, total_bits, chunk_size)

以上代码生成的π的前一百万比特已与NIST提供的data.pi核对通过。

如果需要将比特序列转为字节序列,请自行增补相关功能。

附录 样本数据的测试结果

以下数据来自NIST SP800-22rev1a的附录B。

示例 1:圆周率(π)的二进制展开

统计测试

P

频率测试

0.578211

块频率测试(m=128)

0.380615

累积和测试 - 正向

0.628308

累积和测试 - 反向

0.663369

游程测试

0.419268

最长连续 1 串测试

0.024390

秩测试

0.083553

频谱 DFT 测试

0.010186

非重叠模板匹配测试(m=9,模板 B=000000001)

0.165757

重叠模板匹配测试(m=9)

0.296897

通用统计测试

0.669012

近似熵测试(m=10)

0.361595

随机游走测试(状态 x=+1)

0.844143

随机游走变体测试(状态 x=-1)

0.760966

线性复杂度测试(M=500)

0.255475

串行测试(m=16,∇Ψ²ᵐ)

0.143005

示例 2:自然常数(e)的二进制展开

统计测试

P

频率测试

0.953749

块频率测试(m=128)

0.211072

累积和测试 - 正向

0.669887

累积和测试 - 反向

0.724266

游程测试

0.561917

最长连续 1 串测试

0.718945

秩测试

0.306156

频谱 DFT 测试

0.847187

非重叠模板匹配测试(m=9,模板 B=000000001)

0.078790

重叠模板匹配测试(m=9)

0.110434

通用统计测试

0.282568

近似熵测试(m=10)

0.700073

随机游走测试(状态 x=+1)

0.786868

随机游走变体测试(状态 x=-1)

0.826009

线性复杂度测试(M=500)

0.826335

串行测试(m=16,∇Ψ²ᵐ)

0.766182

示例 4:√2 的二进制展开

统计测试

P

频率测试

0.811881

块频率测试(m=128)

0.833222

累积和测试 - 正向

0.879009

累积和测试 - 反向

0.957206

游程测试

0.313427

最长连续 1 串测试

0.012117

秩测试

0.823810

频谱 DFT 测试

0.581909

非重叠模板匹配测试(m=9,模板 B=000000001)

0.569461

重叠模板匹配测试(m=9)

0.791982

通用统计测试

0.130805

近似熵测试(m=10)

0.884740

随机游走测试(状态 x=+1)

0.216235

随机游走变体测试(状态 x=-1)

0.566118

线性复杂度测试(M=500)

0.317127

串行测试(m=16,∇Ψ²ᵐ)

0.861925

示例 5:√3 的二进制展开

统计测试

P

频率测试

0.610051

块频率测试(m=128)

0.473961

累积和测试 - 正向

0.917121

累积和测试 - 反向

0.689519

游程测试

0.261123

最长连续 1 串测试

0.446726

秩测试

0.314498

频谱 DFT 测试

0.776046

非重叠模板匹配测试(m=9,模板 B=000000001)

0.532235

重叠模板匹配测试(m=9)

0.082716

通用统计测试

0.165981

近似熵测试(m=10)

0.180481

随机游走测试(状态 x=+1)

0.783283

随机游走变体测试(状态 x=-1)

0.155066

线性复杂度测试(M=500)

0.346469

串行测试(m=16,∇Ψ²ᵐ)

0.157500


返回列表