Skip to content

Commit

Permalink
rng: provide a generate_into : ?g -> bytes -> ?off:int -> int -> unit
Browse files Browse the repository at this point in the history
and reimplement the generate in terms of generate_into

this keeps the allocation at the API boundary if desired
  • Loading branch information
hannesm committed Mar 11, 2024
1 parent 4664b90 commit 72d4c48
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 38 deletions.
5 changes: 4 additions & 1 deletion bench/speed.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ let burn_period = 2.0
let sizes = [16; 64; 256; 1024; 8192]
(* let sizes = [16] *)

let big_b = Bytes.create List.(hd (rev sizes))

let burn f n =
let cs = Cstruct.of_string (Mirage_crypto_rng.generate n) in
let (t1, i1) =
Expand Down Expand Up @@ -410,7 +412,8 @@ let benchmarks = [
let open Mirage_crypto_rng.Fortuna in
let g = create () in
reseed ~g "abcd" ;
throughput name (fun cs -> generate ~g (Cstruct.length cs))) ;
throughput name (fun cs ->
generate_into ~g big_b ~off:0 (Cstruct.length cs))) ;

bm "md5" (fun name -> throughput name MD5.digest) ;
bm "sha1" (fun name -> throughput name SHA1.digest) ;
Expand Down
26 changes: 14 additions & 12 deletions rng/fortuna.ml
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,14 @@ let iter1 a f = f a

let reseed ~g cs = reseedi ~g (iter1 cs)

let generate_rekey ~g bytes =
let b = bytes // block + 2 in
let generate_rekey ~g buf ~off len =
let b = len // block + 2 in
let n = b * block in
let r = Cstruct.to_string (AES_CTR.stream ~key:g.key ~ctr:g.ctr n) in
let r1 = String.sub r 0 bytes
and r2 = String.sub r (n - 32) 32 in
Bytes.blit_string r 0 buf off len;
let r2 = String.sub r (n - 32) 32 in
set_key ~g r2 ;
g.ctr <- AES_CTR.add_ctr g.ctr (Int64.of_int b);
r1
g.ctr <- AES_CTR.add_ctr g.ctr (Int64.of_int b)

let add_pool_entropy g =
if g.pool0_size > min_pool_size then
Expand All @@ -94,14 +93,17 @@ let add_pool_entropy g =
done
end

let generate ~g bytes =
let generate_into ~g buf ~off len =
add_pool_entropy g;
if not (seeded ~g) then raise Rng.Unseeded_generator ;
let rec chunk acc = function
| i when i <= 0 -> acc
| n -> let n' = imin n 0x10000 in
chunk (generate_rekey ~g n' :: acc) (n - n') in
String.concat "" @@ chunk [] bytes
let rec chunk off = function
| i when i <= 0 -> ()
| n ->
let n' = imin n 0x10000 in
generate_rekey ~g buf ~off n';
chunk (off + n') (n - n')
in
chunk off len

let _buf = Bytes.create 2

Expand Down
23 changes: 16 additions & 7 deletions rng/hmac_drbg.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,26 @@ module Make (H : Digestif.S) = struct
let v = H.hmac_string ~key:k v |> H.to_raw_string in
g.k <- k ; g.v <- v ; g.seeded <- true

let generate ~g bytes =
let generate_into ~g buf ~off len =
if not g.seeded then raise Rng.Unseeded_generator ;
let rec go acc k v = function
| 0 -> (v, String.concat "" @@ List.rev acc)
let rec go off k v = function
| 0 -> v (* unlikely this happens *)
| 1 ->
let v = H.hmac_string ~key:k v |> H.to_raw_string in
let len =
let rem = len mod H.digest_size in
if rem = 0 then H.digest_size else rem
in
Bytes.blit_string v 0 buf off len;
v
| i ->
let v = H.hmac_string ~key:k v |> H.to_raw_string in
go (v::acc) k v (pred i) in
let (v, buf) = go [] g.k g.v Mirage_crypto.Uncommon.(bytes // H.digest_size) in
Bytes.blit_string v 0 buf off H.digest_size;
go (off + H.digest_size) k v (pred i)
in
let v = go off g.k g.v Mirage_crypto.Uncommon.(len // H.digest_size) in
g.k <- H.hmac_string ~key:g.k (v ^ bx00) |> H.to_raw_string;
g.v <- H.hmac_string ~key:g.k v |> H.to_raw_string;
String.sub buf 0 (Mirage_crypto.Uncommon.imax 0 bytes)
g.v <- H.hmac_string ~key:g.k v |> H.to_raw_string

(* XXX *)
let accumulate ~g:_ = invalid_arg "Implement Hmac_drbg.accumulate..."
Expand Down
13 changes: 10 additions & 3 deletions rng/mirage_crypto_rng.mli
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,12 @@ module type Generator = sig
val create : ?time:(unit -> int64) -> unit -> g
(** Create a new, unseeded {{!g}g}. *)

val generate : g:g -> int -> string
(** [generate ~g n] produces [n] uniformly distributed random bytes,
updating the state of [g]. *)
val generate_into : g:g -> bytes -> off:int -> int -> unit
(** [generate_into ~g buf ~off n] produces [n] uniformly distributed random
bytes into [buf] at offset [off], updating the state of [g].
@raise Invalid_argument if buffer is too small (it must be: Bytes.length buf - off >= n)
*)

val reseed : g:g -> string -> unit
(** [reseed ~g bytes] directly updates [g]. Its new state depends both on
Expand Down Expand Up @@ -231,6 +234,10 @@ val generate : ?g:g -> int -> string
(** Invoke {{!Generator.generate}generate} on [g] or
{{!generator}default generator}. *)

val generate_into : ?g:g -> bytes -> ?off:int -> int -> unit
(** Invoke {{!Generator.generate}generate} on [g] or
{{!generator}default generator}. The offset [off] defaults to 0. *)

val block : g option -> int
(** {{!Generator.block}Block} size of [g] or
{{!generator}default generator}. *)
Expand Down
23 changes: 15 additions & 8 deletions rng/rng.ml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ let () = Printexc.register_printer (function

module type Generator = sig
type g
val block : int
val create : ?time:(unit -> int64) -> unit -> g
val generate : g:g -> int -> string
val reseed : g:g -> string -> unit
val block : int
val create : ?time:(unit -> int64) -> unit -> g
val generate_into : g:g -> bytes -> off:int -> int -> unit
val reseed : g:g -> string -> unit
val accumulate : g:g -> source -> [`Acc of string -> unit]
val seeded : g:g -> bool
val pools : int
val seeded : g:g -> bool
val pools : int
end

type 'a generator = (module Generator with type g = 'a)
Expand All @@ -67,8 +67,15 @@ let default_generator () =

let get = function Some g -> g | None -> default_generator ()

let generate ?(g = default_generator ()) n =
let Generator (g, _, m) = g in let module M = (val m) in M.generate ~g n
let generate_into ?(g = default_generator ()) b ?(off = 0) n =
let Generator (g, _, m) = g in
let module M = (val m) in
M.generate_into ~g b ~off n

let generate ?g n =
let data = Bytes.create n in
generate_into ?g data ~off:0 n;
Bytes.unsafe_to_string data

let reseed ?(g = default_generator ()) cs =
let Generator (g, _, m) = g in let module M = (val m) in M.reseed ~g cs
Expand Down
2 changes: 1 addition & 1 deletion tests/test_eio_entropy_collection.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Printing_rng = struct

let block = 16
let create ?time:_ () = ()
let generate ~g:_ _n = assert false
let generate_into ~g:_ _buf ~off:_ _len = assert false
let seeded ~g:_ = true
let pools = 1

Expand Down
2 changes: 1 addition & 1 deletion tests/test_entropy_collection.ml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Printing_rng = struct

let create ?time:_ () = ()

let generate ~g:_ _n = assert false
let generate_into ~g:_ _buf ~off:_ _len = assert false

let reseed ~g:_ data =
Format.printf "reseeding: %a@.%!" Cstruct.hexdump_pp (Cstruct.of_string data)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_entropy_collection_async.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Printing_rng = struct

let create ?time:_ () = ()

let generate ~g:_ _n = assert false
let generate_into ~g:_ _buf ~off:_ _len = assert false

let reseed ~g:_ data =
Format.printf "reseeding: %a@.%!" Cstruct.hexdump_pp (Cstruct.of_string data)
Expand Down
7 changes: 3 additions & 4 deletions tests/test_rsa.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ module Null = struct

let create ?time:_ () = ref ""

let generate ~g n =
let generate_into ~g buf ~off n =
try
let (a, b) = String.sub !g 0 n, String.sub !g n (String.length !g - n) in
g := b;
a
Bytes.blit_string !g 0 buf off n;
g := String.sub !g n (String.length !g - n)
with Invalid_argument _ -> raise Mirage_crypto_rng.Unseeded_generator

let reseed ~g buf = g := !g ^ buf
Expand Down

0 comments on commit 72d4c48

Please sign in to comment.