Module Mirage_crypto_rng

Randomness

Secure random number generation.

There are several parts of this module:

Usage notes

TL;DR Don't forget to seed; don't maintain your own g.

The RNGs here are merely the deterministic part of a full random number generation suite. For proper operation, they need to be seeded with a high-quality entropy source.

Suitable entropy feeding of generators are provided by other libraries mirage-crypto-rng-lwt (for Lwt), mirage-crypto-rng-async (for Async), mirage-crypto-rng-mirage (for MirageOS), mirage-crypto-rng.unix, mirage-crypto-rng-eio (for Eio), and mirage-crypto-miou-unix (for Miou_unix).

The intention is that "initialize" in the respective sub-library is called once, which sets the default generator and registers entropy harvesting asynchronous tasks. The semantics is that the entropy is always fed to the default generator, which is not necessarily the one set by "initialize". The reasoning behind this is that the default generator should be used in most setting, and that should be fed a constant stream of entropy.

mirage-crypto-rng-eio package differs slightly from other rng packages. Instead of the initialize function a run function is provided with similar behaviour, i.e. RNG setup, entropy collection and periodic reseeding.

Although this module exposes a more fine-grained interface, e.g. allowing manual seeding of generators, this is intended either for implementing entropy-harvesting modules, or very specialized purposes. Users of this library should almost certainly use one of the above entropy libraries, and avoid manually managing the generator seeding.

Similarly, although it is possible to swap the default generator and gain control over the random stream, this is also intended for specialized applications such as testing or similar scenarios where the RNG needs to be fully deterministic (RFC 6979, deterministic usage of DSA), or as a component of deterministic algorithms which internally rely on pseudorandom streams.

In the general case, users should not maintain their local instances of g. All of the generators in a process have to compete for entropy, and it is likely that the overall result will have lower effective unpredictability.

The recommended way to use these functions is either to accept an optional generator and pass it down, or to ignore the generator altogether, as illustrated in the examples.

Interface

type g

A generator (PRNG) with its state.

exception Unseeded_generator

Thrown when using an uninitialized generator.

exception No_default_generator

Thrown when set_default_generator has not been called.

module Entropy : sig ... end

Entropy sources and collection

module type Generator = sig ... end

A single PRNG algorithm.

type 'a generator = (module Generator with type g = 'a)

Ready-to-use RNG algorithms.

Fortuna, a CSPRNG proposed by Schneier.

module Hmac_drbg (H : Digestif.S) : Generator

HMAC_DRBG: A NIST-specified RNG based on HMAC construction over the provided hash.

val create : ?g:'a -> ?seed:string -> ?strict:bool -> ?time:(unit -> int64) -> 'a generator -> g

create ~g ~seed ~strict ~time module uses a module conforming to the Generator signature to instantiate the generic generator g.

g is the state to use, otherwise a fresh one is created.

seed can be provided to immediately reseed the generator with.

strict puts the generator into a more standards-conformant, but slighty slower mode. Useful if the outputs need to match published test-vectors.

time is used to limit the amount of reseedings. Fortuna uses at most once every second.

val default_generator : unit -> g

default_generator () is the default generator. Functions in this module use this generator when not explicitly supplied one.

val set_default_generator : g -> unit

set_default_generator g sets the default generator to g. This function must be called once.

val generate_into : ?g:g -> bytes -> ?off:int -> int -> unit

generate_into ~g buf ~off len invokes generate_into on g or default generator. The random data is put into buf starting at off (defaults to 0) with len bytes.

val generate : ?g:g -> int -> string

Invoke generate_into on g or default generator and a freshly allocated string.

val block : g option -> int

Block size of g or default generator.

Examples

Generating a random 13-byte string:

let cs = Rng.generate 13

Generating a list of string, passing down an optional generator:

let rec f1 ?g ~n i =
if i < 1 then [] else Rng.generate ?g n :: f1 ?g ~n (i - 1)

Generating a Z.t smaller than 10:

let f2 ?g () = Mirage_crypto_pk.Z_extra.gen ?g Z.(~$10)

Creating a local Fortuna instance and using it as a key-derivation function:

let f3 secret =
let g = Rng.(create ~seed:secret (module Generators.Fortuna)) in
Rng.generate ~g 32