I am attempting to build a simple random number generator, but I wanted to make sure random_device was working properly. 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; however, this is written in Visual Studio, and apparently that means entropy always shows 32, regardless of if it is true or not.
So, my question is this: what is the most robust way to seed std::mt19937 without a means of testing entropy? Is chrono better, or random_device? Or some combination, or other option entirely?
Based off of this: The implementation of random_device in VS2010?
It seems random_device is a safe pick for seeding or generating seed_sequences in most situations, but I want to be sure.
I took some time after work to dig into Microsoft documentation and the VS source, and I figured I should share! The header had this:
First part, looks like entropy is always 32.0 after all, and the operator calls _Random_Device. I was able to track that definition down to xrngdev.cpp, which used rand_s.
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."
Also, tracking down the rand_s.cpp showed this:
Which confirms it uses RtlGenRandom, as seen here:The implementation of random_device in VS2010?
RtlGenRandom is sort of a black box, but from what has been released, it uses:
So yeah, std::random_device appears to be the most robust option on pretty much any Windows application post-WindowsXP.
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.