1-- Entropy whose bytes a test gives, the fake of `io.entropy`.
2
3import core/io
4import core/mem
5
6--- Caller-owned state of scripted entropy: how many of its bytes it has
7--- given and how often it was asked. Declare it `zeroed` and give it to
8--- `entropy_over`; it must outlive the handle, and may be read while the
9--- handle is in use.
10public entropy_space: type = struct
11 used: usize
12 requests: usize
13end entropy_space
14
15scripted_entropy_value: type = struct
16 state: ptr mut entropy_space
17 bytes: []u8
18end scripted_entropy_value
19
20--- Entropy whose bytes are the caller's, given in order, so a program
21--- that seeds itself from entropy runs the same way in every test: a
22--- provider of `entropy`. A request for more than what is left of them
23--- fails `io_failed` and gives nothing, so a test can make the source run
24--- dry. Copies share the state.
25public entropy: type = scripted_entropy_value
26
27--- Fill `state` for scripted entropy over `bytes`, which the handle lends;
28--- keep them alive while it is used.
29public entropy_over: (inout state: entropy_space, bytes: []u8)
30 -> (host: entropy from state, bytes) =
31 state = (used: 0, requests: 0)
32 host = (state: addr state, bytes: bytes)
33end entropy_over
34
35scripted_fill: (self: entropy, into: []mut u8) -> none ! io.io_failed =
36 state: ptr mut entropy_space = self.state
37 inc state.val.requests
38 used: usize = state.val.used
39 given: []u8 = self.bytes
40 fail io.io_failed when used > lenof given or lenof into > lenof given - used
41 mem.copy(into, given[used..<used + lenof into]) else (problem)
42 _ = problem
43 fail io.io_failed
44 end
45 state.val.used = used + lenof into
46end scripted_fill
47
48entropy is io.entropy (fill_random: scripted_fill)