当std :: random_device熵未知时,如何初始化std :: mt19937? VS C ++ / Windows

问题描述

我正在尝试构建一个简单的随机生成器,但是我想确保random_device正常工作。我从以下代码开始:

#include <random>
#include <chrono>

class Generator {
public:
    Generator()
        :
        m_DeviceSeed(rd()),m_TimeSeed(std::chrono::high_resolution_clock::Now().time_since_epoch().count()),rng(m_DeviceSeed)
    {
        if (rd.entropy() == 0.0) {
            rng.seed((unsigned)m_TimeSeed);
        }
    }
private:
    //Vars
    std::random_device rd;
    unsigned int m_DeviceSeed;
    unsigned long long m_TimeSeed;
    std::mt19937 rng;
};

我看到“ std :: chrono :: high_resolution_clock :: Now()。time_since_epoch()。count()”被推荐作为random_device的替代方案,并且我发现检查熵将使我可以将其用作后备;但是,这是用Visual Studio编写的,显然这意味着熵始终显示32,无论它是否为真。

所以,我的问题是这个 :在没有测试熵的情况下播种std :: mt19937的最可靠方法是什么? chrono更好,还是random_device?还是某种组合,或者完全是其他选择?

基于此:The implementation of random_device in VS2010?

在大多数情况下,似乎random_device是播种或生成seed_sequences的安全选择,但我想确定。

解决方法

下班后我花了一些时间来研究Microsoft文档和VS源码,我认为我应该分享!标头中包含以下内容:

_NODISCARD double entropy() const noexcept
    {   // return entropy of random number source
    return (32.0);
    }

_NODISCARD result_type operator()()
    {   // return next value
    return (_Random_device());
    }

第一部分,毕竟熵总是32.0,并且运算符调用_Random_Device。我能够将该定义追溯到xrngdev.cpp,它使用了rand_s。

_CRTIMP2_PURE unsigned int __CLRCALL_PURE_OR_CDECL _Random_device()
    {   // return a random value
    unsigned int ans;
    if (_CSTD rand_s(&ans))
        _Xout_of_range("invalid random_device value");
    return (ans);
    }

根据Microsoft文档,“ rand_s函数将0到UINT_MAX范围内的伪随机整数写入输入指针。rand_s函数使用操作系统生成加密安全的随机数。”

此外,跟踪rand_s.cpp会显示以下内容:

    if (!__acrt_RtlGenRandom(result,static_cast<ULONG>(sizeof(*result))))
{
    errno = ENOMEM;
    return errno;
}

确认使用RtlGenRandom,如下所示:The implementation of random_device in VS2010?

RtlGenRandom有点像一个黑匣子,但根据已发布的内容,它使用:

[RtlGenRandom]按照FIPS 186-2附录3.1中的指定生成,并带有 SHA-1作为G函数。并具有以下熵:

当前进程ID(GetCurrentProcessID)。

当前线程ID(GetCurrentThreadID)。

自启动以来的滴答计数(GetTickCount)。

当前时间(GetLocalTime)。

各种高精度性能计数器(QueryPerformanceCounter)。

用户环境块的MD4哈希,其中包括用户名,计算机名称和搜索路径。 [...]

高精度内部CPU计数器,例如RDTSC,RDMSR,RDPMC

[省略:低级系统信息字段和性能计数器的长列表] [4]

所以,在WindowsXP之后的几乎所有Windows应用程序中,std :: random_device似乎都是最可靠的选项。

尽管我仍将按照提供的注释并创建一个get_seed()样式函数来生成完整的std :: seed_seq,但要多加一些曲折,但这至少对我来说是std :: random_device可能更健壮的“基础” “播种选项。