1-- Entropy: the system's source of random bytes, a concept beside the
2-- others and outside `world`, and a scripted one whose bytes a test
3-- gives. A deterministic generator seeded from it is core/random's.
4
5import core/mem
6
7--- The system's source of unpredictable bytes, fit for seeding a
8--- generator or making a key. `fill_random` fills all of `into` or fails
9--- `io_failed`, and after a failure what `into` holds is not to be used.
10--- It is a concept of its own, outside `world`, so a provider without a
11--- source, and a firmware image that never asks for one, carries none.
12public entropy: type = concept (provider: type)
13 --- Fill all of `into` with random bytes, or fail.
14 fill_random: (self: provider, into: []mut u8) -> none ! io_failed
15end entropy
16
17--- Fill all of `into` with random bytes from the provider, through
18--- `entropy` evidence. On a hosted system they are the system's own,
19--- `getrandom` on Linux and `arc4random_buf` on Darwin and FreeBSD.
20public fill_random: (provider: type is entropy, host: provider,
21 into: []mut u8) -> none ! io_failed =
22 try provider.fill_random(host, into)
23end fill_random
24
25--- Caller-owned state of scripted entropy: how many of its bytes it has
26--- given and how often it was asked. Declare it `zeroed` and give it to
27--- `entropy_over`; it must outlive the handle, and may be read while the
28--- handle is in use.
29public entropy_space: type = struct
30 used: usize
31 requests: usize
32end entropy_space
33
34scripted_entropy_value: type = struct
35 state: ptr mut entropy_space
36 bytes: []u8
37end scripted_entropy_value
38
39--- Entropy whose bytes are the caller's, given in order, so a program
40--- that seeds itself from entropy runs the same way in every test: a
41--- provider of `entropy`. A request for more than what is left of them
42--- fails `io_failed` and gives nothing, so a test can make the source run
43--- dry. Copies share the state.
44public scripted_entropy: type = scripted_entropy_value
45
46--- Fill `state` for scripted entropy over `bytes`, which the handle lends;
47--- keep them alive while it is used.
48public entropy_over: (inout state: entropy_space, bytes: []u8)
49 -> (host: scripted_entropy from state, bytes) =
50 state = (used: 0, requests: 0)
51 host = (state: addr state, bytes: bytes)
52end entropy_over
53
54scripted_fill: (self: scripted_entropy, into: []mut u8) -> none ! io_failed =
55 state: ptr mut entropy_space = self.state
56 inc state.val.requests
57 used: usize = state.val.used
58 given: []u8 = self.bytes
59 fail io_failed when used > lenof given or lenof into > lenof given - used
60 mem.copy(into, given[used..<used + lenof into]) else (problem)
61 _ = problem
62 fail io_failed
63 end
64 state.val.used = used + lenof into
65end scripted_fill
66
67scripted_entropy is entropy (fill_random: scripted_fill)