Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RNG seeding updates, update default RNG to MT64 #6565

Merged
merged 2 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ set(COMMON_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/timer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/timer.h
${CMAKE_CURRENT_SOURCE_DIR}/xirand.h
${CMAKE_CURRENT_SOURCE_DIR}/xirand.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils.h
${CMAKE_CURRENT_SOURCE_DIR}/uuid.h
Expand Down
28 changes: 7 additions & 21 deletions src/common/rng/mersennetwister.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include <array>
#include <random>

// Forward declare sysrandom which is built in the xirand.h/cpp compilation unit
extern size_t sysrandom(void* dst, size_t dstlen);

class xirand
{
public:
Expand All @@ -38,27 +41,10 @@ class xirand
{
ShowInfo("Seeding Mersenne Twister 32 bit RNG");

std::array<uint32_t, std::mt19937::state_size> seed_data;

// Certain systems were noted to have bad seeding via only std::random_device,
// the following indicated how we could mix in std::random_device with other seed sources
// https://stackoverflow.com/a/68382489
for (auto it = seed_data.begin(); it != seed_data.end(); ++it)
{
// start with a C++ equivalent of time(nullptr) - UNIX time in seconds
*it = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();

// mix with a high precision time in microseconds
*it ^= std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();

// *it ^= more_external_random_stuff;
}
std::seed_seq seq(seed_data.cbegin(), seed_data.cend());
rng().seed(seq);
uint32_t seed;
sysrandom(&seed, sizeof(seed));

rng().seed(seed);
}

/*
Expand Down
28 changes: 7 additions & 21 deletions src/common/rng/mersennetwister64.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include <array>
#include <random>

// Forward declare sysrandom which is built in the xirand.h/cpp compilation unit
extern size_t sysrandom(void* dst, size_t dstlen);

class xirand
{
public:
Expand All @@ -38,27 +41,10 @@ class xirand
{
ShowInfo("Seeding Mersenne Twister 64 bit RNG");

std::array<uint64_t, std::mt19937_64::state_size> seed_data;

// Certain systems were noted to have bad seeding via only std::random_device,
// the following indicated how we could mix in std::random_device with other seed sources
// https://stackoverflow.com/a/68382489
for (auto it = seed_data.begin(); it != seed_data.end(); ++it)
{
// start with a C++ equivalent of time(nullptr) - UNIX time in seconds
*it = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();

// mix with a high precision time in microseconds
*it ^= std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();

// *it ^= more_external_random_stuff;
}
std::seed_seq seq(seed_data.cbegin(), seed_data.cend());
rng().seed(seq);
uint64_t seed;
sysrandom(&seed, sizeof(seed));

rng().seed(seed);
}

/*
Expand Down
23 changes: 9 additions & 14 deletions src/common/rng/pcg.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <array>
#include <random>

// Forward declare sysrandom which is built in the xirand.h/cpp compilation unit
extern size_t sysrandom(void* dst, size_t dstlen);

class xirand
{
public:
Expand All @@ -41,25 +44,17 @@ class xirand
{
ShowInfo("Seeding PCG32 RNG");

std::array<uint32_t, sizeof(pcg32::state_type) / 4> seed_data; // get enough data to seed an N byte state with sets of 32 bit ints
std::array<pcg32::state_type, 2> seed_data; // PCG states seem to be bit size * 2 * 2, here 64 bit numbers * 2

pcg32::state_type seed;

// Certain systems were noted to have bad seeding via only std::random_device,
// the following indicated how we could mix in std::random_device with other seed sources
// https://stackoverflow.com/a/68382489
for (auto it = seed_data.begin(); it != seed_data.end(); ++it)
{
// start with a C++ equivalent of time(nullptr) - UNIX time in seconds
*it = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
sysrandom(&seed, sizeof(seed));

// mix with a high precision time in microseconds
*it ^= std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();

// *it ^= more_external_random_stuff;
*it = seed;
}

std::seed_seq seq(seed_data.cbegin(), seed_data.cend());
rng().seed(seq);
}
Expand Down
23 changes: 9 additions & 14 deletions src/common/rng/pcg64.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <array>
#include <random>

// Forward declare sysrandom which is built in the xirand.h/cpp compilation unit
extern size_t sysrandom(void* dst, size_t dstlen);

class xirand
{
public:
Expand All @@ -41,25 +44,17 @@ class xirand
{
ShowInfo("Seeding PCG64 RNG");

std::array<uint32_t, sizeof(pcg64::state_type) / 4> seed_data; // get enough data to seed an N byte state with sets of 32 bit ints
std::array<pcg64::state_type, 2> seed_data;

pcg64::state_type seed;

// Certain systems were noted to have bad seeding via only std::random_device,
// the following indicated how we could mix in std::random_device with other seed sources
// https://stackoverflow.com/a/68382489
for (auto it = seed_data.begin(); it != seed_data.end(); ++it)
{
// start with a C++ equivalent of time(nullptr) - UNIX time in seconds
*it = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
sysrandom(&seed, sizeof(seed));

// mix with a high precision time in microseconds
*it ^= std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();

// *it ^= more_external_random_stuff;
*it = seed;
}

std::seed_seq seq(seed_data.cbegin(), seed_data.cend());
rng().seed(seq);
}
Expand Down
67 changes: 67 additions & 0 deletions src/common/xirand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <fstream>
#include <stddef.h>

// https://stackoverflow.com/a/45069417
#ifdef _WIN32

#include <windows.h>

#include <wincrypt.h>

bool acquire_context(HCRYPTPROV* ctx)
{
if (!CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, 0))
{
return CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET);
}

return true;
}

size_t sysrandom(void* dst, size_t dstlen)
{
HCRYPTPROV ctx;
if (!acquire_context(&ctx))
{
throw std::runtime_error("Unable to initialize Win32 crypt library.");
}

BYTE* buffer = reinterpret_cast<BYTE*>(dst);
if (!CryptGenRandom(ctx, static_cast<DWORD>(dstlen), buffer))
{
throw std::runtime_error("Unable to generate random bytes.");
}

if (!CryptReleaseContext(ctx, 0))
{
throw std::runtime_error("Unable to release Win32 crypt library.");
}

return dstlen;
}
#elif defined(__linux__) || defined(linux) || defined(__linux)

#include <linux/random.h>
#include <sys/syscall.h>
#include <unistd.h>

size_t sysrandom(void* dst, size_t dstlen)
{
int bytes = syscall(SYS_getrandom, dst, dstlen, 0);
if (bytes != dstlen)
{
throw std::runtime_error("Unable to read N bytes from CSPRNG.");
}

return dstlen;
}
#else // OSX
size_t sysrandom(void* dst, size_t dstlen)
{
char* buffer = reinterpret_cast<char*>(dst);
std::ifstream stream("/dev/urandom", std::ios_base::binary | std::ios_base::in);
stream.read(buffer, dstlen);

return dstlen;
}
#endif
7 changes: 5 additions & 2 deletions src/common/xirand.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
#define _XIRAND_H_

// You can choose an RNG by commenting/uncommenting this line. The default is Mersenne Twister in 32 bit.
#include "rng/mersennetwister.h"
// #include "rng/mersennetwister64.h"
// #include "rng/mersennetwister.h"
#include "rng/mersennetwister64.h"
// #include "rng/pcg.h"
// #include "rng/pcg64.h"

Expand Down Expand Up @@ -138,4 +138,7 @@ inline T xirand::GetRandomElement(std::initializer_list<T> list)
return GetRandomElement(container);
}

// Get secure random numbers
size_t sysrandom(void* dst, size_t dstlen);

#endif // _XIRAND_H_
Loading