In the fenestrasX model, when the root CSPRNG is reseeded from pools due to
an (infrequent) timer, child CSPRNGs can cheaply detect this condition and
reseed. To do so, they just need to track an additional 64-bit value in the
associated state, and check the __read_mostly root seed version (generation)
on random reads.
This revision integrates arc4random(9) into that model without changing the
design or implementation of arc4random(9) much. The motivation is that
arc4random(9) is immediately reseeded when the backing random(4)
implementation has additional entropy. This is arguably most important
during boot, when fenestrasX is reseeding at 1, 3, 9, 27, etc., second
intervals, but arc4random(9) has a hardcoded 300 second reseed window.
Without this mechanism, if arc4random(9) gets weak entropy during initial
seed (and arc4random(9) is used early in boot, so this is quite possible),
it may continue to emit poorly seeded output for 5 minutes. This scheme
corrects arc4random(9) as soon as possible.
=======================================================================
This patch isn't exactly what we'd want to commit to FreeBSD.
If we want to adopt the push-seed system into random(4) and random_fortuna
(single generator), this loose coupling makes sense.
If we want to adopt the fenestrasX pcpu PRNG model, we *could* eliminate the
majority of arc4random code and just invoke read_random(9) directly. (We
would also be able to unifdef out the !RANDOM_FENESTRASX conditional code
for clarity.)
The argument against replacing arc4random(9) with read_random(9) is mostly
that fenestrasX incurs the overhead of fast key erasure on every request.
That is, every time read_random(9) returns some bytes, there is no longer
any state inside fenestrasX that can be used to recreate the returned bytes.
arc4random(9)'s API does not currently provide that property, and the
guarantee comes with additional runtime overhead. On the other hand, the
cost of rekeying Chacha is much cheaper than rekeying AES. Blake2B may be
slightly cheaper than SHA2_d-256() on 64-bit platforms. And fenestrasX'
buffered RNG design amortizes the cost of actual each reseeding over 128
bytes (or more, for larger requests) of generated output.