
Creating randomness Without Math.random - healeycodes
https://healeycodes.com/creating-randomness/
======
kqr
There are a few algorithms I think are simple enough to memorise yet seem
universally useful enough to be bound to be good to know by heart at some
point or other. LCG is one of them!

Something else that might be useful to know are methods to transform the
uniform output of LCG into various other types of distribution shapes:

When U is uniform between 0 and 1 exclusive,

One can get an Exp(lambda) distributed variable with -log(U)/lambda

One can get a heavy-tailed Pareto(m,a) distributed variable with m/(1-u)^(1/a)

I'm still missing something easily memorable for bell-shaped distributions.
The normal distribution would be nice because it's so easy to transform N(0,1)
into a distribution with arbitrary parameters, but there's no simple way to
compute the standard normal.

~~~
kmm
By way of the central limit theorem, summing a dozen uniformly distributed
variables (and normalizing) will give a a reasonable approximation to a normal
distribution.

[https://en.wikipedia.org/wiki/Central_limit_theorem](https://en.wikipedia.org/wiki/Central_limit_theorem)

~~~
kqr
Very clever. My first instinct was that that would be inefficient, but
addition is super cheap and the uniform distribution converges rathe quickly
to normal. I like it a lot!

Even if LCG itself would be considered expensive, for quick prototyping needs
this should be sufficient.

------
syspec
Great article, I love "because why not articles".

Checkout Perlin Noise, for when you need "smooth" and "natural" looking random
numbers (making terrain, skies, waves, etc)

[https://www.youtube.com/watch?v=8ZEMLCnn8v0](https://www.youtube.com/watch?v=8ZEMLCnn8v0)

------
chrismorgan
Deterministic pseudorandomness is really useful for seeding dummy data, data
that you’d like to be fairly random (though it doesn’t need to be high-quality
randomness, so LCG is fine) but consistent across runs/page loads.

------
aloisdg
Good stack overflow answer about js implementation of pseudorandom number
generator:
[https://stackoverflow.com/a/47593316/1248177](https://stackoverflow.com/a/47593316/1248177)

------
trevoristall
I just watched a really good video explaination of this the other day:
[https://www.youtube.com/watch?v=4sYawx70iP4](https://www.youtube.com/watch?v=4sYawx70iP4)

------
ggm
The real value is the reference to the API calls which inherently represent
less predictable seed state. If you can't call out, then these are acheing to
be used alongside some kind of introspection into the runtime.

------
Someone
_“Each Math.random function created for distinct realms must produce a
distinct sequence of values from successive calls.”_

Nitpick: it would surprise me if any implementation implemented this
requirement to the letter.

I think neither of the claims (FTA) “PRNGs are deterministic” and “A PRNG
eventually repeats its sequence” are strictly required (for the first you
can’t seed Javascript’s Math.Random, so there is no need to be able to
regenerate a sequence; for the second, one could generate good pseudo random
sequences that never repeat), but the implementations I’m aware of all have
those properties, and use fixed-size state.

Given that, the number of PRNGs whose period is at most P is finite. So, one
could exhaust that set by creating realms and random number sequences in each
of them in a loop (a looooong loop)

The only ways to avoid generating a copy would be to gradually move to
generators with more state or to crash.

~~~
xsmasher
> “Each Math.random function created for distinct realms must produce a
> distinct sequence of values from successive calls.”

If this were not true, it would have security implications.

Thought experiment: If there was a single state then a web page could pull a
bunch of numbers, use that data to derive the seed AND the next number that
will be pulled without pulling it.

Then the predictor page can STOP pulling numbers when they know the next
number is an auspicious one. The predictor page has now successfully "rigged"
the dice roll for another page that shares the same state.

~~~
Someone
I know that an am not disputing it. My claim is that most, if not all,
implementations do not satisfy that requirement.

Also, that requirement isn’t sufficient to prevent such attacks, by a long
stretch.

An implementation that has only one sequence of random numbers r1, r2, r3,
r4…, but drops a single item of the sequence for each subsequent realm (the
second instance returns r2, r3, r4…, the third one r3, r4…, etc.) satisfies
the requirement, and the individual sequences are as perfectly random as the
original one), but still is vulnerable to attacks.

And it can be worse: an implementation that generates a unique r0 for each
realm (could even be an easily predictable value) and returns r0, r1, r2, r3,
r4…, with r1 and subsequent identical for all instances also satisfies the
requirement.

------
michael-ax
[https://nullprogram.com/blog/2017/09/21/](https://nullprogram.com/blog/2017/09/21/)

------
galaxyLogic
It would be great if JavaScript had also a built-in seedable random number
generator.

~~~
yesbabyyes
It depends on the implementation, e.g. Node has crypto.getRandomBytes()¹.

If you mean the standard browser implementation, Crypto.getRandomValues()² may
be what you're looking for. Note that the browser implementation of this is
only a recommendation, so YMMV:

> To guarantee enough performance, implementations are not using a truly
> random number generator, but they are using a pseudo-random number generator
> seeded with a value with enough entropy. The pseudo-random number generator
> algorithm (PRNG) may vary across user agents, but is suitable for
> cryptographic purposes. Implementations are required to use a seed with
> enough entropy, like a system-level entropy source.

> [...]

> There is no minimum degree of entropy mandated by the Web Cryptography
> specification. User agents are instead urged to provide the best entropy
> they can when generating random numbers, using a well-defined, efficient
> pseudorandom number generator built into the user agent itself, but seeded
> with values taken from an external source of pseudorandom numbers, such as a
> platform-specific random number function, the Unix /dev/urandom device, or
> other source of random or pseudorandom data.

¹
[https://nodejs.org/api/crypto.html#crypto_crypto_randombytes...](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback)

² [https://developer.mozilla.org/en-
US/docs/Web/API/Crypto/getR...](https://developer.mozilla.org/en-
US/docs/Web/API/Crypto/getRandomValues)

~~~
galaxyLogic
From what I can see at [https://developer.mozilla.org/en-
US/docs/Web/API/Crypto/getR...](https://developer.mozilla.org/en-
US/docs/Web/API/Crypto/getRandomValues) or
[https://nodejs.org/api/crypto.html#crypto_crypto_randombytes...](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback)

... neither crypto.getRandomBytes() nor Crypto.getRandomValues() are SEEDABLE.
There is no argument I could pass in that would produce the same random
sequence for the same seed-value.

A reproducible random sequence would be useful in many situations I believe. I
understand such a thing is not too difficult to program but it may be
difficult to get verifiably good quality randomness out of your own
implementation.

