Better seeding of global rand

Currently the global rand is seeded using time.Now().UnixNano(). That approach has its` drawbacks:

  • The randomness is presented in the lower bits only, whereas the higher bits remain the same and very predictable.
  • Some systems do not provide the granularity of single nanoseconds, sometimes it’s up to tens of milliseconds. That also increases predictability significantly.

Although for cryptographically strong random values the crypto/rand must be used, that’s not always the case where it’s needed. And some innocently looking predictable values may lead to serious exploits. Like jitter value for retries back-off.

  1. Versions: Nakama 3.9.0
  2. Server Framework Runtime language Go

At the same time, the fix is quite straightforward and comparatively easy to implement. Here’s example I came up with:

func getSeedForGlobalRand() (int64, error) {
	var seed int64
	err := binary.Read(cryptorand.Reader, binary.BigEndian, &seed)
	if err != nil {
		return time.Now().UnixNano(), err
	}
	return seed, nil
}

Thanks @f1avalanche - What’s the issue you are seeing with the current impl of the global rand - what exactly are you trying to solve / issue you’ve hit?

Hey @mofirouz! I want to use global rand in my code to get various random values, and I want to be sure it is seeded properly. I may re-seed it in my main function of course, but as I mentioned, the change looks like it can bring benefits overall and it’s worth to consider including in the main code base.

ok understood - if you are open to this, can you kindly open a PR on Nakama:

Oh, my pleasure! Here you go: Seed global random using crypto/rand by shpikat · Pull Request #786 · heroiclabs/nakama · GitHub