-1

My overall goal is to create a round-based game. So, I need some seemingly randomly generated numbers, example in fights - but not only, there are some different occasions. Anyway, I want those numbers to be reliably the same if certain parameters are the same.

Those parameters will be an integer seed - it will take the value of a generalRandomSeed, changing every round; but I need more parameters, like IDs of attacker and defender. I would be very convenient to call this function with the parameters (maybe all combined in a vector) like getRandom(generalRandomSeed,id1,id2).

So, in the end I am hoping for a function that takes one or more ints as parameters (ideally, a vector), returning one single integer: int getRandom(std::vector<int> parameters);

I canot quite figure out how I could solve that problem; if it was only about one parameter, I might just create a new mt19937 every time with my seed generalRandomSeed.

Sam Mason
  • 15,216
  • 1
  • 41
  • 60
  • 3
    _" So, in the end I am hoping for a function that takes one or more ints as parameters (ideally, a vector), returning one single integer"_: there's a name for that, it's called a [hash function](https://en.wikipedia.org/wiki/Hash_function). – Brian61354270 Feb 11 '23 at 00:34
  • It's not clear to me why you can't just use one RNG for everything? – 500 - Internal Server Error Feb 11 '23 at 00:35
  • @500-InternalServerError They say _"I want those numbers to be reliably the same if certain parameters are the same."_ They're asking how to generate seeds from said parameters. – Brian61354270 Feb 11 '23 at 00:39
  • The 19937 in "mt19937" means its state size is 19937 bits or almost 2.5KB. So it is hard to imagine what you ask? Are the "parameters" all together larger than 19937 bits? Then perhaps make 19937 bit hash of those. Are these shorter? Then extend with something. – Öö Tiib Feb 11 '23 at 00:40
  • Well, I do not know (I tried, but I forgot to mention it) how to put a hash function into my program either. "seeds from said parameters" seems plausible to me. – truberfighter Feb 11 '23 at 00:42
  • 4
    Perhaps use https://en.cppreference.com/w/cpp/numeric/random/seed_seq for that. – Öö Tiib Feb 11 '23 at 00:47
  • This might be the solution I had been searching for. Thank you! – truberfighter Feb 11 '23 at 00:57
  • Normally you'd use something like a stream cipher to generate the bits using the seed as a key, but adding the random number extraction may be somewhat tricky if you're not used to this kind of programming. – Maarten Bodewes Feb 11 '23 at 22:40
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Feb 12 '23 at 19:55

2 Answers2

1

To explain Maarten's issues with std::seed_seq (and to make sure I understand things correctly!) I'll attempt an answer.

The main issue I'd have with potentially suggesting using it (and it sounds like Maarten has the same one) is that the algorithm used by std::seed_seq isn't defined by the standard. Hence it's possible for other standard libraries (e.g. if you use a different compiler or even a different version of the same compiler) to change the implementation and you'd get different values back from the same inputs. Depending on your use case this lack of stability may, or may not, matter. That's a domain specific issue you'd have to decide on as you haven't specified it.

The cryptographic approach suggested would would be to use something like a HKDF, where you use a cryptographic hash (like SHA256) to extract the entropy (i.e. "randomness") from your input values in a deterministic manner (e.g. taking care of endianness) and then use another cryptographic primitive to "stretch" this entropy out to produce your random output. If you're not familiar with the cryptographic world these things can be awkward as there's a lot of terminology.

As a minor point, I'd suggest against using the MT19937 PRNG as it's relatively expensive to seed and it sounds like you'd be doing this a lot. There are other algorithms that are much cheaper, I personally like Sebastiano's xoshiro256 family or you could use Melissa's PCG family. Melissa O'Neill's site is a very useful resource if you're new to PRNGs.

That said, if you're going the HKDF route you may as well just use the "expansion" step as a PRNG as it will directly produce uniform values. These can be transformed into bounded/uniform values easily: Melissa has a good review for ints here, or Vigna describes a conventional transform for binary IEEE-754 floats at the bottom of here (so is valid for float and double on most common CPUs).

update: The MT19937 would seem to be difficult to predict given its enormous state space, but in fact it's been shown almost trivial. For example, searching for "predicting mt19937" leads to https://github.com/kmyk/mersenne-twister-predictor which will give you the state of the RNG from 624 consecutive 32bit integer draws. Using a CSPRNG would protect you from this, and is what using the output of a HKDF would give you. PCG makes this more difficult than the Mersenne Twister, but given that it's optimised for speed can't expend too much work doing this.

Sam Mason
  • 15,216
  • 1
  • 41
  • 60
0

Apparently, it was indeed a seed_seq that I was looking for.

  • Wouldn't recommend that. Biggest issue is to make sure that both the random bit generator and the algorithm that extracts the values (which I presume are in a specific range 0..N) remain the same over several runtime versions. I don't see much of that in the weird `seed_seq` algorithm. Weird because it makes values *look* more random than the entropy provided. – Maarten Bodewes Feb 11 '23 at 22:34
  • @MaartenBodewes I do not really understand what you mean (since I am a bit of a noob) If I set seed_seq theSeq(71,2,3,4}) and generate a few integers landing in a vector, then the output seems to be consistent. At least, I ran that a couple of times, always with the same results. Precisely, I ran that code: std::seed_seq theSeq({1,2,3,4}); std::vector theVector(10); theSeq.generate(theVector.begin(), theVector.end()); for(int i: theVector) cout< – truberfighter Feb 12 '23 at 23:21
  • Maybe this is and remains fine as it is, but it's more a warning about future developments. I think the API isn't as clear as it should be about that. At least be warned about differences in output between different / future versions of the library. E.g. I've seen random generators that suddenly really output just random values instead of values directly created from a seed. And if you e.g. use such an algorithm to derive a secret key for encryption then you may not be able to decrypt. – Maarten Bodewes Feb 12 '23 at 23:45
  • 1
    @MaartenBodewes have attempted to explain in more detail, hope I got things about right! – Sam Mason Feb 13 '23 at 16:12
  • Yeah, that was what I was trying to explain + a lot of detail. Melissa's site is great, but if I remember correctly there was something about security claims that didn't fare very well at [crypto.se]. So, uh, as long as you don't use it as a Cryptographically Secure PRNG, then fine. – Maarten Bodewes Feb 13 '23 at 18:05
  • @MaartenBodewes yup, PCG is certainly not a CSPRNG, but feeding output of a stream cipher into any of her "bounded rand" algorithms would be fine. that said, given that OP only seems to be pulling a few (i.e. one) value from the stream it wouldn't hurt. will add a link to how quickly/easily the the MT19937 can be broken in my answer – Sam Mason Feb 14 '23 at 15:07