简体   繁体   English

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

[英]How to initialize std::mt19937 when std::random_device entropy is unknown? (VS C++/Windows)

I am attempting to build a simple random number generator, but I wanted to make sure random_device was working properly.我正在尝试构建一个简单的随机数生成器,但我想确保 random_device 正常工作。 I started with the following code:我从以下代码开始:

#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;
};

I had seen "std::chrono::high_resolution_clock::now().time_since_epoch().count()" recommended as an alternative to random_device, and I figured checking entropy would allow me to use it as a fallback;我曾看到“std::chrono::high_resolution_clock::now().time_since_epoch().count()”被推荐为 random_device 的替代方案,我认为检查熵可以让我将其用作后备; however, this is written in Visual Studio, and apparently that means entropy always shows 32, regardless of if it is true or not.然而,这是在 Visual Studio 中编写的,显然这意味着熵总是显示 32,无论它是否为真。

So, my question is this : what is the most robust way to seed std::mt19937 without a means of testing entropy?所以,我的问题是:在没有测试熵的方法的情况下,播种 std::mt19937 的最稳健方法是什么? Is chrono better, or random_device? chrono 好还是 random_device 好? Or some combination, or other option entirely?还是某种组合,或者完全是其他选择?

Based off of this: The implementation of random_device in VS2010?基于此: VS2010 中 random_device 的实现?

It seems random_device is a safe pick for seeding or generating seed_sequences in most situations, but I want to be sure.在大多数情况下,random_device 似乎是播种或生成 seed_sequences 的安全选择,但我想确定一下。

I took some time after work to dig into Microsoft documentation and the VS source, and I figured I should share!下班后我花了一些时间深入研究 Microsoft 文档和 VS 源代码,我想我应该分享一下! The header had this:标题是这样的:

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

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

First part, looks like entropy is always 32.0 after all, and the operator calls _Random_Device.第一部分,看起来熵终究是32.0,算子调用_Random_Device。 I was able to track that definition down to xrngdev.cpp, which used rand_s.我能够将该定义跟踪到使用 rand_s 的 xrngdev.cpp。

_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);
    }

As per Microsoft documentation, "The rand_s function writes a pseudorandom integer in the range 0 to UINT_MAX to the input pointer. The rand_s function uses the operating system to generate cryptographically secure random numbers."根据 Microsoft 文档,“rand_s 函数将 0 到 UINT_MAX 范围内的伪随机整数写入输入指针。rand_s 函数使用操作系统生成加密安全的随机数。”

Also, tracking down the rand_s.cpp showed this:此外,追踪 rand_s.cpp 显示:

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

Which confirms it uses RtlGenRandom, as seen here: The implementation of random_device in VS2010?这证实了它使用 RtlGenRandom,如下所示: VS2010 中 random_device 的实现?

RtlGenRandom is sort of a black box, but from what has been released, it uses: RtlGenRandom 有点像一个黑匣子,但从已发布的内容来看,它使用:

[RtlGenRandom] generates as specified in FIPS 186-2 appendix 3.1 with SHA-1 as the G function. [RtlGenRandom] 按照 FIPS 186-2 附录 3.1 中的规定生成,使用 SHA-1 作为 G 函数。 And with entropy from:和熵来自:

The current process ID (GetCurrentProcessID).当前进程 ID (GetCurrentProcessID)。

The current thread ID (GetCurrentThreadID).当前线程 ID (GetCurrentThreadID)。

The tick count since boot time (GetTickCount).自启动以来的滴答计数 (GetTickCount)。

The current time (GetLocalTime).当前时间 (GetLocalTime)。

Various high-precision performance counters (QueryPerformanceCounter).各种高精度性能计数器(QueryPerformanceCounter)。

An MD4 hash of the user's environment block, which includes username, computer name, and search path.用户环境块的 MD4 哈希,其中包括用户名、计算机名称和搜索路径。 [...] [...]

High-precision internal CPU counters, such as RDTSC, RDMSR, RDPMC高精度内部CPU计数器,如RDTSC、RDMSR、RDPMC

[omitted: long lists of low-level system information fields and performance counters] [4] [省略:低级系统信息字段和性能计数器的长列表] [4]

So yeah, std::random_device appears to be the most robust option on pretty much any Windows application post-WindowsXP.所以是的,std::random_device 似乎是 Windows XP 后几乎所有 Windows 应用程序上最强大的选项。

While I will still follow the provided comments and create a get_seed() style function to generate a full std::seed_seq with some extra twists, this at least answers for me that std::random_device is likely the more robust "base" seeding option.虽然我仍然会遵循提供的评论并创建一个 get_seed() 样式函数来生成一个完整的 std::seed_seq 和一些额外的曲折,但这至少对我来说回答了 std::random_device 可能是更强大的“基础”播种选项.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM