Source file mirage_crypto_rng_mkernel.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
let src = Logs.Src.create "mirage-crypto-rng.miou-solo5"
module Log = (val Logs.src_log src : Logs.LOG)
open Mirage_crypto_rng
module Pfortuna = Pfortuna
let periodic fn delta =
let rec one () =
let () = fn () in
let () = Mkernel.sleep delta in
one () in
Miou.async one
let rdrand delta =
match Entropy.cpu_rng with
| Error `Not_supported -> None
| Ok cpu_rng ->
Some (periodic (cpu_rng None) delta)
let running = Atomic.make false
let default_generator_already_set =
"Mirage_crypto_rng.default_generator has already \
been set (but not via Mirage_crypto_rng_mkernel). Please check \
that this is intentional"
let miou_generator_already_launched =
"Mirage_crypto_rng_mkernel.initialize has already been launched \
and a task is already seeding the RNG."
type rng = Mkernel.Hook.t * unit Miou.t option
let rec compare_and_set ?(backoff= Miou_backoff.default) t a b =
if Atomic.compare_and_set t a b = false
then compare_and_set ~backoff:(Miou_backoff.once backoff) t a b
let[@inline] now () = Int64.of_int (Mkernel.clock_monotonic ())
let _1s = 1_000_000_000
let initialize (type a) ?g ?(sleep= _1s) (rng : a generator) =
if Atomic.compare_and_set running false true
then begin
entropy_test ();
let seed =
let init = Entropy.[ bootstrap; bootstrap; whirlwind_bootstrap; bootstrap; ] in
List.mapi (fun i fn -> fn i) init |> String.concat "" in
let () =
try let _ = default_generator () in
Logs.warn (fun m -> m "%s" default_generator_already_set)
with No_default_generator -> () in
let rng = create ?g ~seed ~time:now rng in
set_default_generator rng;
let seed =
Array.init 4 (fun _ ->
let r = Mirage_crypto_rng.generate 8 in
Int64.to_int (String.get_int64_be r 0))
in
Random.full_init seed;
let hook = Mkernel.Hook.add (Entropy.timer_accumulator None) in
(hook, rdrand sleep)
end else invalid_arg miou_generator_already_launched
let kill (hook, prm) =
Mkernel.Hook.remove hook;
Option.iter Miou.cancel prm;
compare_and_set running true false;
unset_default_generator ()