微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决在 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 举报,一经查实,本站将立刻删除。