News for hackers. Stuff that matters.
Re:There's Math.random(), and then there's Math.random() by rkangel on Friday February 07, 2025 @05:22AM (#42971148)
They're call PRNG because they are pseudo random. If you know the starting state, you know what sequence they're going to generate. Putting it another way, if you always start them in the same state, they'll always produce the same sequence.

So a PRNG needs "seeding". You need some value to put in at the start that is different every time. Using the time on the computer results in a different seed on each run, and so a different number sequence each time.

If you need random numbers for cryptography (very good quality random numbers are important for lots of crypto processes) then you need to do more - they need to be completely unpredictable. If you just used the time, someone could seed a copy of the RNG with the same time, and predict the randomness sequence. So what we want is a seed that comes from actual randomness (also called "entropy"). That entropy has to come from somewhere - ideally some hardware source using some statistically random physical effect.

Re:There's Math.random(), and then there's Math.random() by magicalhippo on Friday February 07, 2025 @06:07AM (#42971350)
> Putting it another way, if you always start them in the same state, they'll always produce the same sequence.

This can be easy to bump into in fairly trivial cases.

For example, initializing by time alone can be problematic if you spawn N threads at once which all do their own seeding. Then they can all reach the seeding process at the same time, relative to the clock used for the seeding.

I had that problem with one of my earlier ray tracers, and so had to add add the thread id into the mix to seed the PRNGs.

Re:There's Math.random(), and then there's Math.random() by markh1967 on Friday February 07, 2025 @06:37AM (#42971508)
A demonstration of exactly this problem (only in older versions of .Net, newer versions use a different seeding method)

https://dotnetfiddle.net/tLGMp6

Re:There's Math.random(), and then there's Math.random() by mturmon on Friday February 07, 2025 @01:53PM (#42976113)
Agreed. I do a lot of Monte Carlo simulations of physical systems (radars, scientific models) in which same or close seeds will cause trouble.

You do want a deterministic PRNG (for repeatability of the simulation). But if you seed with time alone, and spawn 100 parallel jobs, you will see repeats or near-repeats which will bias the Monte Carlo averages resulting from your simulation ensemble.

In ancient times, you could xor in the PID and the IP address of the host to ensure no seed overlap. Nowadays there are other ways to introduce entropy to the seed, e.g. with dedicated system calls or /dev/random.

Re:There's Math.random(), and then there's Math.random() by simonmales on Friday February 07, 2025 @05:45AM (#42971256)
Well written, h/t.
Re:There's Math.random(), and then there's Math.random() by UncleMeat on Friday February 07, 2025 @08:57AM (#42972544)
The key thing with crypto is not the source of the seed, but the algorithm. Throwing true randomness into a random number generator that isn't mean to provide cryptographic hardness won't save you and a cryptographically secure pseudo random number generator is often just fine when seeded without true randomness.
Re:There's Math.random(), and then there's Math.random() by toast0 on Friday February 07, 2025 @10:10AM (#42973497)
It's both. Cryptographic generators do have better properties on their outputs than noncryptographic hashes (usually at a cost in cpu time, although the cost is often small enough to ignore); but if the seed is guessable, the output sequence is guessable too.

Using timestamp in seconds and process id for example would be easy enough to guess. There was some good work about a decade ago to provide more usable apis to get a quality seed from the OS (getentropy, getrandom), so using a self built seed is pretty suboptimal unless you have a case where you need to repeat the sequence later (recording the seed from the OS is also an option)

Re:There's Math.random(), and then there's Math.random() by UncleMeat on Friday February 07, 2025 @11:29AM (#42974535)
It depends on what you mean by guessable. Guessing a few bits of the seed with confidence won't help you crack a csprng. Yes, people shouldn't be using a timestamp in seconds as a seed. But you also don't need to spring for hardware randomness in order to get strong protections.
Re:There's Math.random(), and then there's Math.random() by kbolino on Friday February 07, 2025 @01:18PM (#42975732)
The problem with using the current time is that "guessing a few bits with confidence" is the same as guessing the whole thing because there's only a few bits that need to be guessed. You might think a time_t value has 55 and growing years worth of values to guess, but in reality, if I'm attacking you or something related to you, I have probably narrowed it down to days, hours, or even just minutes worth of values to guess. Higher-precision timers confer some additional entropy but even then it's usually not enough -- if I'm intercepting live traffic I have a very good idea of the current time, if I'm forging a signature from a certificate I know when it was issued, if I'm trying to decrypt emails or files I usually have attached metadata to narrow my guesses, etc.

The CSPRNG has only made it practically impossible to predict future outputs from past outputs alone; however, if I can guess the seed, I can predict every output past, present, and future. CSPRNGs aren't magic and have to be used properly, and in any security-sensitive context, properly means with a truly random seed. The best CSPRNG in the world cannot create entropy out of thin air. It can, however, stretch a good source of entropy very far. There are cases when using a CSPRNG with a low-quality seed is appropriate, but the minimum acceptable entropy in the seed depends on the application, not on the RNG.

Re:There's Math.random(), and then there's Math.random() by UncleMeat on Friday February 07, 2025 @01:57PM (#42976161)
I'm not saying to use the current time in seconds. I'm saying that the need for "actual randomness" and being "completely unpredictable" in the comment I responded to is largely overblown. Seeds that aren't drawn from true randomness can be totally fine. Seeds that have a handful of highly biased bits can be fine.

There are some cases in crypto where a secret that has even a single bit biased more than epsilon will break a whole scheme. CSPRNGs don't tend to work that way.

Re:There's Math.random(), and then there's Math.random() by kbolino on Friday February 07, 2025 @02:24PM (#42976449)
Ok, yes, there were some algorithms in the past which had problems with carrying input biases to their output and sometimes even getting totally broken with certain seeds/keys. Nowadays, this isn't the case, and the view is that such issues are fundamental weaknesses rather than mere errata to be worked around.

However, the quality of a modern CSPRNG doesn't save you from a low-entropy seed. A couple biased bits in a 128-bit seed may not be a serious issue (but why take the chance?!), however good entropy estimation is a difficult task which is best left to the operating system. Modern operating systems will ingest sources of hardware randomness and seed their system-level CSPRNGs, which should then be used directly by application software (for key material) or as seeds to local CSPRNGs (for less security-sensitive but more performance-sensitive needs). Do not play around with seed entropy just to be clever.

In the absence of a full-fledged operating system, then things like high-precision boot timers can be used for seeds, but only because there's nothing better available. The lack of good randomness is a real problem in resource-constrained environments, though usually there are easier-to-exploit vulnerabilities that get hit first.