Should I use a random engine seeded from std::rand

2020-02-24 12:43发布

I have a class that contains two sources of randomness.

std::random_device rd;
std::mt19937 random_engine;

I seed the std::mt19937 with a call to std::random_device. If I want to generate a number and I don't care about repeatability, should I call rd() or random_engine()?

In my particular case, I'm sure both would work just fine, because this is going to be called in some networking code where performance is not at a premium, and the results are not especially sensitive. However, I am interested in some "rules of thumb" on when to use hardware entropy and when to use pseudo-random numbers.

Currently, I am only using std::random_device to seed my std::mt19937 engine, and any random number generation I need for my program, I use the std::mt19937 engine.

edit: Here's an explanation for exactly what I am using this particular example for:

This is for a game playing program. This particular game allows the user to customize their 'team' prior to beginning a round against an opponent. Part of setting up a battle involves sending a team to the server. My program has several teams and uses the random number to determine which team to load. Each new battle makes a call to std::random_device to seed the pseudo-random number generator. I log the initial state of the battle, which includes this team that I'm randomly selecting and the initial seed.

The particular random number I'm asking about in this question is for the random team selection (where it is beneficial to not have the opponent know ahead of time what team I'm using, but not mission-critical), but what I'm really looking for is a rule of thumb. Is it fine to always use std::random_device if I don't need repeatability of my numbers, or is there a real risk of using up entropy faster than it can be collected?

标签: c++ random c++11
6条回答
老娘就宠你
2楼-- · 2020-02-24 13:00

If you need randomness for a simulation or a game, then that you're doing is fine. Call the random device just once, and do everything else with a randomly seeded pseudo-RNG. As a bonus, you should store the seed value in a log file so you can later replay the pseudo-random sequence:

auto const seed = std::random_device()();
// save "seed" to log file
std::mt19937 random_engine(seed);

(For multiple threads, use the PRNG in the main thread to generate seeds for further PRNGs in the spawned threads.)

If you need a lot of true randomness for cryptographic purposes, then a PRNG is never a good idea, though, since a long sequence of output contains a lot less randomness than true randomness, i.e. you can predict all of it from a small subset. If you need true randomness, you should collect it from some unpredictable source (e.g. heat sensors, user keyboard/mouse activity, etc.). Unix's /dev/random may be such a "true randomness" source, but it may not fill up very quickly.

查看更多
做个烂人
3楼-- · 2020-02-24 13:07

If you are not using it for encryption it is fine and well to repeatedly use mt19937 which is seeded by random_engine.

For the rest of this answer, I assume you are using the random numbers for encryption in your networking code. In short, mt19937 is not suitable for that use.

http://en.wikipedia.org/wiki/Mersenne_twister#Disadvantages

There is a potential risk that you will leak information (perhaps indirectly) over time so that an attacker could start to predict the random numbers. At least in theory, but this is what it's about. From Wikipedia

...since this figure is the size of the state vector from
which future iterates are produced) allows one to predict all future iterates.

A simple means of preventing random number generation information to leak to the user is to use one-way hash functions, but there's much more to it. You should use a random number generator designed for that purpose:

http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator

Various examples (with code) are found here http://xlinux.nist.gov/dads/HTML/pseudorandomNumberGen.html

查看更多
Emotional °昔
4楼-- · 2020-02-24 13:10

The answer is platform dependent. I seem to remember that with Visual C++ 2010, std::random_device is just mt19937 seeded in some undocumented way.

Of course you realize that any ad hoc encryption scheme based on a random number generator is likely to be very weak.

查看更多
老娘就宠你
5楼-- · 2020-02-24 13:15

The standard practice, as far as I am aware, is to seed the random number generator with a number that is not calculated by the computer (but comes from some external, unpredictable source). That should be the case with your rd() function. From then on, you call the pseudo-random number generator(PRNG) for each and every pseudo-random number that you need.

If you are worried about the numbers not being random enough, then you should pick a different PRNG. Entropy is a scarce and precious resource and should be treated as such. Although, you may not be needing that many random numbers right now, you may in the future; or other applications could need them. You want that entropy to be available whenever an application asks for it.

It sounds like, for your application, that the mersenne twister will suit your needs just fine. No one who plays your game will ever feel like the teams that are loaded aren't random.

查看更多
Juvenile、少年°
6楼-- · 2020-02-24 13:16

Assuming this is not for cryptographic purposes, the most important thing to remember about random number generation is to think of how you want the distribution of the random numbers to be and what is the range you are expecting.

Usually standard random number generators within libraries are designed to give out uniform distribution. So the numbers will range between 0 and some RAND_MAX ( say on 32 bit machine it is 2^31 -1 )

Now here is the thing to remember with pseudo random number generators. Most of them are designed to generate random numbers and not random bits. The difference is subtle. If you need numbers between 0 and 8 most programmers will say rand()%8 This is bad because the algorithm was for randomizing 32 bits. But you are using only the bottom 3 bits. No good. This will not give you a uniform distribution (assuming that is what you are looking for)

You should use 8 * (rand() + 1) / (RAND_MAX) which will now give you a uniformly random number between 0 and 8.

Now with hardware random number generators you may have random bits being produced. If that is indeed the case, then you have each bit independently being generated. Then it is more like a set of identical independent random bits. The modeling here would have to be a bit different. Keep that in mind, especially in simulations the distribution becomes important.

查看更多
Luminary・发光体
7楼-- · 2020-02-24 13:23

You may want to have a look at http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful that explains why you should use uniform_int_distribution, and the relatives strengths of random_device / mt19937.

In this video, Stephan T. Lavavej specifically states that on visual C++, random_device can be used for cryptographic purposes.

查看更多
登录 后发表回答