基于时间的(真正的)随机数?

时间:2016-11-27 04:33:10

标签: c++ c random

我需要一个随机数生成器。不是伪随机数,而是真正的随机类。我突然想到,也许我可以从循环执行中的微妙时序差异中提取位,所以我把一些东西放在一起来做到这一点:

#ifdef _WIN32
#include <windows.h>
unsigned long long tick()
{
    unsigned __int64 
        tock;
    QueryPerformanceCounter((LARGE_INTEGER *)&tock);
    return (unsigned long long)tock;
}
#else
#include <time.h>
unsigned long long tick()
{
    return (unsigned long long)clock();    
}
#endif
#include <limits.h>
unsigned long long random_bits(unsigned short bits)
{
/*
    The `threshold` setting determines the smallest sample to extract a bit 
    from. If set too low the result won't contain enough entropy to be useful. 
    We don't want to set it so high that we're just wasting CPU cycles either, 
    so we need to settle on a value somewhere in the middle. Heuristically, 
    256 seems to be a pretty good compromise.    
*/    
    const unsigned long long    
        threshold = 256;
    unsigned long long
        result = 0,
        increment,
        accumulator,    
        count,
        target;
    const unsigned short
        size = sizeof(result) * CHAR_BIT;    
    if(bits == 0 || bits > size)
        bits = size;
    while(bits-- > 0)
    {
        increment = 1;
        accumulator = 0;
    /*
        Build up the value to be extracted from. We don't know anything 
        about the clock resolution, so the increment is repeatedly doubled 
        until it's large enough to make a difference.
    */        
        while(accumulator < threshold)
        {
            count = 0;
            target = tick() + increment;
            while(tick() < target)
                ++count;            
            accumulator += count;
            increment <<= 1;                
        }
    /*
        Shift the previous bit up one position and insert the newly sampled one.
    */        
        result <<= 1;
        result |= (accumulator & 1);
    }    
    return result;
}
unsigned long long random_word(unsigned short length)
{
    return random_bits(length * CHAR_BIT);
}

//    Example useage:

#include <stdio.h>
int main(void)
{
    for(;;)
    {
        printf(" %u\n", (unsigned)random_word(sizeof(unsigned)));
        getchar();
    }
}

它似乎运作良好(通过TESTU01 test suite)......但我仍然想知道:

(1)我是否正确实施了一切

(2)做平台#defines看起来没问题

(3)在黑客获得对系统时间或某些此类时间的控制的情况下,是否有任何(合理的)可能性容易受到攻击

(4)有更好的方法来实现这个目标

(5)是否存在任何合理的论据:(a)生成的值实际上足够随机;(b)如果是,调整threshold参数是否可以补救在这种情况下的情况

修改

最终能够在几个Linux机器上测试代码之后,事实证明特定于Linux的tick()未正确实现。幸运的是,标准clock()函数似乎工作正常,所以我只是简单地将其用于那些系统。

2 个答案:

答案 0 :(得分:5)

您无法使用算法创建真正的随机性。

“任何考虑产生随机数字的算术方法的人当然都处于罪恶状态。” - John von Neumann

因为,无论如何,有人可以复制完全相同的计算环境并获得完全相同的结果。

然而,你可以相当接近。内核提供了使用尽可能多的操作噪声的方法,因为它们可以提供具有可变熵级别的一些相当可靠的随机性。例如,在Unix平台上,这是通过从/dev/random/dev/urandom抽样完成的。在Windows上,它是CryptGenRandom。他们只是在更广泛的范围内使用几乎任何东西 - 从分配的内存到CPU活动 - 进行描述,以提高熵。

如果你想要真正的随机性,没有人可以穿透,那么你将不得不使用真实世界的输入 - www.random.org例如从大气中采样他们的数字。您可以使用,例如麦克风或网络摄像头上的噪音,但根据使用情况,这些噪音很容易被挫败。

总结:

答案 1 :(得分:4)

不要自己这样做。

几乎可以确定不是一成不变的 - 试图自己实施安全关键功能只是要求灾难,除非你有资源和非常好的理由。细微的时间差异对你来说似乎是随机的,但它们是确定性系统的一部分,如果这种方法在深入的统计分析中没有破解,我会非常惊讶。

相反,查看如何安全地使用/ dev / random或/ dev / urandom,并查看公开安全随机生成函数的库。如果你真的需要真正的随机性,那么看看

的硬件随机数生成器