Skip to content

Future of thread_rng #463

@dhardy

Description

@dhardy

Status: proposal to allow hardware-dependent generators and replace HC128 with a faster variant of ChaCha (start reading here).


This topic comes up quite a bit from various angles; I think it's time to get some ideas down about the future of thread_rng (regarding the 0.6 release or later).

I see the following potential uses for thread_rng:

  • convenient random numbers in small games and simulations
  • use in randomised algorithms
  • as a source of secret data for various cryptographic applications

Also, I think it's worth mentioning where we do not expect thread_rng to be used:

  • anywhere reproducibility is required
  • complex simulations and games, due to above point, and also since thread_rng may not be the fastest option
  • where security is very important

And an important note on security: we should aim to provide a secure source of random data, but ultimately it is up to users to decide how much they trust our implementation and what their risks are. thread_rng does not have the simplest code to review and is currently young and subject to further change. Also we may or may not implement forward secrecy (backtracking resistance), and for ultimate security solutions using no local state may be preferred.


Our current implementation of thread_rng tries to satisfy the above with a fast, secure PRNG, but at the cost of high memory usage and initialisation time per thread. For applications with a low number of long-running threads this is reasonable, but for many worker threads may not be ideal.

There are two ways we can let users influence the implementation:

  • via feature flags
  • at the call site (pass parameters to thread_rng or call a different function)

Feature flags allow configuration on a per-application basis, e.g.

  • prefer low-memory-usage / fast initialisation over generation performance
  • disable entirely (i.e. panic on usage)
  • require forward secrecy
  • remove security requirements (??)

The last two options sound very risky to me — should we ask distributors and end-users to reason about the security of whole applications? It is quite possible that the people building applications — even developers — will not know about all uses of thread_rng requiring secure randomness.

This brings me to ask, is having only a single user-facing function ideal? What if instead:

  • strong_rng replaces thread_rng as a source of cryptographically secure randomness
  • weak_rng is added as a fast source of randomness; depending on feature flags this could just wrap strong_rng or could be independent

An advantage of the above is that feature-flags could allow replacing the current implementation (HC-128; 4176 bytes) with two smaller back ends (e.g. ChaCha + PCG; 136 + 16 bytes), while only compromising the speed of the secure generator.

Another advantage is that we could add forward-secrecy to strong_rng with less concern for performance implications.

But first, why bother when generators like Randen and RDRAND claim to satisfy all requirements anyway? This is a good question to which I only have vague answers: Randen is still new and unproven and may have portability issues; RDRAND is not fully trusted; and may not be the fastest option.

Second, what about users like HashMap where weaknesses are often not exploitable (depending on application design and usage) and in the worst case only allow DOS attacks (slow algorithms)? Another good question. One possible answer is that these use-cases should use weak_rng but by default this would be secure anyway; we provide feature flags to change that but discourage usage on servers. It might seem tempting to add a third function, but, frankly, this kind of thing is probably the main use case for weak_rng anyway.

Another, very different, option is that we keep thread_rng looking like it is but remove CryptoRng support and recommend it not be used for crypto keys. Then we can add a feature flag changing its implementation to an insecure generator with less concern. This may be a good option, but goes against our recent changes (switching to HC-128 and implementing CryptoRng).


BTW, lets not bikeshed thread_rng vs ThreadRng::new or other syntax here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    D-changesDo: changes requested

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions