Hello Tom,
I'm sorry I'm a bit late back into this discussion, I was on the road.
> To fix this reliably, we need random() and setseed() to use their own
> private random state variable.
Ok.
> Standard random(3) isn't amenable to such usage, so let's switch to
> pg_erand48().
Hmmm… bad idea?
> It's hard to say whether that's more or less "random" than any
> particular platform's version of random(3),
It looks much less pseudo-random on Linux: POSIX provides 3 pseudo-random
functions (probably 2 too many): "random", "rand" (mapped on the previous
one by glibc), and ".rand48". According to glibc documentation, "random"
has an internal state of 31 long integers i.e. 992 bits (checked into the
source code, although why it can only be seeded from 32 bits fails me)
with a "nonlinear additive feedback" PRNG, vs 48 bits of rand48 linear
congruential generator PRNG, also seeded from 32 bits.
For me, a 48 bit state is inadequate for anything but a toy application
that would need a few casual pseudo-random numbers. I recommand against
using the rand48 for a backend purpose which might have any, even remote,
security implication.
As rand48 is a LCG, it cycles on the low-order bits so that they should
not be used (although they are for erand48). The 48 bit state looks like a
80's design, when hardware was between 16 and 32 bit, and was still in use
in the 90's so that it is in POSIX and Java. I can retro-explain it as
follows: the aim was to produce reasonable 32 bit pseudo-random ints on
slow machines while not using low-order bits, so 48 was the closest
round-up possible. Why not go up to 64 bits was very probably because it
would have required more expensive mults to simulate 64 bit multiply on a
16 or 32 bit architecture. The 48-bit LCG makes it "good enough" for less
than a cubic root of size samples, i.e. 2**16 draws. This is much too
small on today GHz hardware.
ISTM that 64 bits would be on the too-low side as well. I'd shop for a 128
or 256-bit state generator. I'm unsure of the best choice, though. I have
looked at "xorshift128+" and "xoshiro256**", which have some critics
(basically, non-cryptographic PRNG can have their state rebuilt from a few
outputs, and there usually is a simple transformation on outputs which
make it fails statistical tests). ISTM that "xoshiro256**" would be a
reasonable choice, much better than "rand48". An LCG with a larger state
(>= 128) could be admissible as well.
> but it does have a wider seed value and a longer period than are required
> by POSIX, so we can hope that this isn't a big downgrade.
I'd say that it is a significant downgrade that I wish postgres woud
avoid, especially with the argument that it for better security!
I'd suggest again that (1) postgres should provide an
algorithm-independent interface to its PRNG with an external state and (2)
use an alternative to rand48, the choice of which should be discussed.
--
Fabien.