Skip to content

Commit 29f6478

Browse files
Pass Automated Testing Suitezoj613
Pass Automated Testing Suite
authored andcommitted
Simplify SeeqSequence module implementation.
This is done by always calling `assembled_entropy` inside of `mix` and adding labelled arguments to avoid confusing inputs of the same type. code for `generate_32bit_state` is cleaned up to make better use of Seq.
1 parent fcc219d commit 29f6478

File tree

1 file changed

+39
-43
lines changed

1 file changed

+39
-43
lines changed

lib/seed.ml

+39-43
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ let mixhashmix x y const =
2222
const', Uint32.(logxor (shift_right res xshift) res)
2323

2424

25-
let mask32 = Uint128.of_int 0xffffffff
25+
let mask32 = Uint32.max_int |> Uint128.of_uint32
2626
(* Convert a list of unsigned 128bit integers into an array of unsigned 32 bit integers
2727
by splitting each 128bit integer into a sequence of 32bit ints and concatenating the result.*)
2828
let to_u32_array l =
29-
let f n = Some Uint128.(logand n mask32 |> to_uint32, shift_right n 32) in
30-
let split n = Seq.unfold f n |> Seq.take_while (fun x -> Uint32.(x > zero))
31-
|> (fun s -> if Seq.is_empty s then Seq.(return Uint32.zero) else s)
32-
in List.to_seq l |> Seq.concat_map split |> Array.of_seq
29+
let open Uint128 in
30+
Seq.concat_map (fun n -> if n = zero then Seq.return Uint32.zero else
31+
Seq.unfold (function
32+
| n when n > zero -> Some (logand n mask32 |> to_uint32, shift_right n 32)
33+
| _ -> None) n) (List.to_seq l) |> Array.of_seq
3334

3435

3536
(* Return an integer with 128 random bits by combining 2 integers with 64 random bits. *)
@@ -91,24 +92,30 @@ module SeedSequence : sig
9192
the bit stream of [t]. *)
9293
end = struct
9394

94-
type t = {
95-
entropy : uint128 list;
96-
spawn_key : uint128 list;
97-
children_spawned : int;
98-
pool : uint32 array;
99-
}
95+
type t = {entropy : uint128 list; spawn_key : uint128 list;
96+
children_spawned : int; pool : uint32 array}
10097

10198
let entropy t = t.entropy
10299

100+
103101
let children_spawned t = t.children_spawned
104102

105103

106-
let mix_entropy pool_size entropy =
104+
let assembled_entropy ~entropy ~spawn_key pool_size =
105+
let run, spawn = to_u32_array entropy, to_u32_array spawn_key in
106+
if Array.(length spawn > 0 && length run < pool_size) then
107+
Array.concat [run; Array.make (pool_size - Array.length run) Uint32.zero; spawn]
108+
else Array.concat [run; spawn]
109+
110+
111+
let mix ~entropy ~spawn_key pool_size =
112+
let entropy' = assembled_entropy ~entropy ~spawn_key pool_size in
113+
107114
(* Add in entropy up to the pool size. *)
108-
let values, leftover = match Array.length entropy, pool_size with
109-
| le, lp when le > lp -> entropy, le - lp
110-
| le, lp -> Array.append entropy (Array.init (lp - le) (fun _ -> Uint32.zero)), 0 in
111-
let hash, pool = Array.fold_left_map hashmix (Uint32.of_int 0x43b0d7e5) values in
115+
let values, leftover = match Array.length entropy', pool_size with
116+
| le, lp when le > lp -> entropy', le - lp
117+
| le, lp -> Array.append entropy' (Array.init (lp - le) (fun _ -> Uint32.zero)), 0 in
118+
let hash, pool = Array.fold_left_map hashmix (Uint32.of_int32 0x43b0d7e5l) values in
112119

113120
(* mix all bits together so later bits can affect earlier bits *)
114121
let indices = Array.init pool_size (fun x -> x) in
@@ -120,47 +127,36 @@ end = struct
120127
if leftover > 0 then
121128
let leftover_indices = (Array.init leftover (fun i -> pool_size + i)) in
122129
let f (acc0, acc1) j = Array.fold_left_map
123-
(fun c i -> mixhashmix entropy.(j) acc1.(i) c) acc0 indices in
130+
(fun c i -> mixhashmix entropy'.(j) acc1.(i) c) acc0 indices in
124131
Array.fold_left f (hash', pool') leftover_indices |> snd
125132
else pool'
126133

127134

128-
let assembled_entropy entropy spawn_key pool_size =
129-
let run_entropy = to_u32_array entropy
130-
and spawn_entropy = to_u32_array spawn_key in
131-
let l = match Array.(length spawn_entropy > 0 && length run_entropy < pool_size) with
132-
| true -> Array.init (pool_size - Array.length run_entropy) (fun _ -> Uint32.zero)
133-
| false -> [||]
134-
in Array.concat [run_entropy; l; spawn_entropy]
135-
136-
137135
let initialize ?(spawn_key=[]) ?(pool_size=4) entropy =
138136
(* 128 bits of system entropy are used when entropy is not provided *)
139-
let entropy' = if List.compare_length_with entropy 0 = 0 then [randbits128 ()] else entropy in
140-
let assembled = assembled_entropy entropy' spawn_key pool_size in
141-
{spawn_key; entropy = entropy'; children_spawned = 0; pool = mix_entropy pool_size assembled}
137+
let entropy = if List.compare_length_with entropy 0 = 0 then [randbits128 ()] else entropy in
138+
{spawn_key; entropy; children_spawned = 0; pool = mix pool_size ~entropy ~spawn_key}
142139

143140

144141
let spawn n t =
145-
let f i =
146-
let psize = Array.length t.pool
147-
and spawn_key = t.spawn_key @ [i] in
148-
let pool = assembled_entropy t.entropy spawn_key psize |> mix_entropy psize in
149-
Some ({t with pool; spawn_key; children_spawned = 0}, Uint128.(i + one))
150-
in Seq.unfold f Uint128.(of_int n) |> Seq.take n |> List.of_seq,
142+
List.init n (fun x -> Uint128.of_int x)
143+
|> List.map (fun i -> match t.spawn_key @ [i] with
144+
| spawn_key -> {t with spawn_key; children_spawned = 0;
145+
pool = Array.length t.pool |> mix ~entropy:t.entropy ~spawn_key}),
151146
{t with children_spawned = t.children_spawned + n}
152147

153148

154-
let init_b, mult_b = Uint32.(of_int 0x8b51f9dd, of_int 0x58f38ded)
149+
let init_b, mult_b = Uint32.(of_int 0x8b51f9dd, of_int32 0x58f38dedl)
150+
155151

156152
let generate_32bit_state n_words t =
157-
let f acc a =
158-
let a' = Uint32.(logxor a acc)
159-
and acc' = Uint32.(acc * mult_b) in
160-
let a'' = Uint32.(a' * acc') in
161-
acc', Uint32.(shift_right a'' xshift |> logxor a'')
162-
in Array.to_seq t.pool |> Seq.cycle |> Seq.take n_words
163-
|> Array.of_seq |> Array.fold_left_map f init_b |> snd
153+
Seq.unfold (fun (seq, acc) -> match Seq.uncons seq, Uint32.(acc * mult_b) with
154+
| Some (a, seq'), acc' ->
155+
let a' = Uint32.(logxor a acc |> mul acc') in
156+
Some Uint32.(shift_right a' xshift |> logxor a', (seq', acc'))
157+
| None, _ -> None) (Array.to_seq t.pool |> Seq.cycle |> Seq.take n_words, init_b)
158+
|> Array.of_seq
159+
164160

165161
(* 64 bit state array is obtained by combining elements i and (i + 1) of the [o] array
166162
to create a 64 bit integer using the formula o.(k + 1) << 32 | o.(k), where k = i * 2

0 commit comments

Comments
 (0)