在 Python 中使用 NIST CTR DRBG 从总体中生成随机样本

问题描述

我正在尝试从使用 cryptographically secure DRBG 而不是 Python 中认使用的“不安全”梅森扭曲器的总体中生成随机样本。

This library 提供了 DRBG,我重新利用了 Python 源代码中的 random.sample 生成算法作为我的采样算法的基础。

代码有效,但仅适用于远小于总体的样本,而内置的 Mersenne Twister 即使样本和总体大小相等也不会失败。

程序将随机选择数组中的位置,让字符驻留在其中。不允许覆盖,因为在将字符串放入数组后必须从数组中重建字符串(这部分代码显示,但会进行解释以帮助解释问题)。

代码

import string
import secrets as secret
import random as rd
import numpy as np
from math import ceil,log
from aes_drbg import AES_DRBG
import timeit


# Initialize the AES DRBG
key = 1
aes_drbg = AES_DRBG(256)
aes_drbg.instantiate(bytes(key))

def random_number(limit):
    """Generate a random number within the limit using the AES DRBG."""
    sequence_length = 1
    if limit >= 4_294_967_296:
        sequence_length = 8
    elif limit >= 65_536:
        sequence_length = 4
    elif limit >= 256:
        sequence_length = 2

    random_number_bytes = aes_drbg.generate(sequence_length)
    random_number = int.from_bytes(random_number_bytes,byteorder="big")

    return random_number % limit

def sample(population,k):
    """Generate a random sample of size k from the given population"""
    randbelow = random_number
    n = len(population)
    if not 0 <= k <= n:
        raise ValueError("Sample larger than population or is negative")
    result = [None] * k
    setsize = 21  # size of a small set minus size of an empty list
    if k > 5:
        setsize += 4 ** ceil(log(k * 3,4))  # table size for big sets
    if n <= setsize:
        # An n-length list is smaller than a k-length set
        pool = list(population)
        for i in range(k):  # invariant:  non-selected at [0,n-i)
            j = randbelow(n - i)
            result[i] = pool[j]
            pool[j] = pool[n - i - 1]  # move non-selected item into vacancy
    else:
        selected = set()
        selected_add = selected.add
        for i in range(k):
            j = randbelow(n)
            while j in selected:
                j = randbelow(n)
            selected_add(j)
            result[i] = population[j]
    return result

def string_generator(size):
    """Generate a random string of a given size."""
    chars = string.ascii_uppercase + string.ascii_lowercase
    return ''.join(secret.choice(chars) for _ in range(size))

def main():
    test = string_generator(50_000_000)  # Generate random string as test data.

    array = np.zeros([100_000_000])  # Initialize empty array.

    rd.seed(1)

    start_time = timeit.default_timer()
    rand_sample = sample(range(len(array)),len(test))  # use `sample` for AES DRBG; `rd.sample` for the Mersenne Twister
    end_time = timeit.default_timer()

    print(rand_sample)
    print(f"Execution time: {end_time - start_time}")

if __name__ == "__main__":
    main()

随着 len(test) 的值接近 len(array) 的值,DRBG 停止输出并无限期运行。我不确定我哪里出错了,但我无法诊断错误

MWE 是对我的实际代码的简化,但就我所能收集到的而言,它充分说明了问题。 testarray数量在生产中要大得多(十亿),所以我愿意接受任何其他更有效的算法或其他加密安全的 DRBG,例如 XCHACHA20 甚至其他具有安全 DRBG 可用的库这样可以完全控制种子,从而可以重复结果。非常感谢任何指导。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)