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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Interfaces for accessing an entropy source.
//!
//! An entropy source produces random bits that are computationally
//! intractable to guess, even if the complete history of generated
//! bits and state of the device can be observed. Entropy sources must
//! generate bits from an underlying physical random process, such as
//! thermal noise, radiation, avalanche noise, or circuit
//! instability. These bits of entropy can be used to seed
//! cryptographically strong random number generators. Because high-quality
//! entropy is critical for security and these APIs provide entropy,
//! it is important to understand all of these requirements before
//! implementing these traits. Otherwise you may subvert the security
//! of the operating system.
//!
//! _Entropy_: Entropy bits generated by this trait MUST have very high
//! entropy, i.e. 1 bit of entropy per generated bit. If the underlying
//! source generates <1 bit of entropy per bit, these low-entropy bits
//! SHOULD be mixed and combined with a cryptographic hash function.
//! A good, short reference on the difference between entropy and
//! randomness as well as guidelines for high-entropy sources is
//! Recommendations for Randomness in the Operating System: How to
//! Keep Evil Children Out of Your Pool and Other Random Facts,
//! Corrigan-Gibbs et al., HotOS 2015.
//!
//! The interface is designed to work well with entropy generators
//! that may not have values ready immediately. This is important when
//! generating numbers from a low-bandwidth hardware entropy source
//! generator or when virtualized among many consumers.
//!
//! Entropy is yielded to a Client as an `Iterator` which only
//! terminates when no more entropy is currently available. Clients
//! can request more entropy if needed and will be called again when
//! more is available.
//!
//! # Example
//!
//! The following example is a simple capsule that prints out entropy
//! once a second using the `Alarm` and `Entropy` traits.
//!
//! ```
//! use kernel::hil;
//! use kernel::hil::entropy::Entropy32;
//! use kernel::hil::entropy::Client32;
//! use kernel::hil::time::Alarm;
//! use kernel::hil::time::ConvertTicks;
//! use kernel::hil::time::Frequency;
//! use kernel::hil::time::AlarmClient;
//! use kernel::ErrorCode;
//!
//! struct EntropyTest<'a, A: 'a + Alarm<'a>> {
//!     entropy: &'a dyn Entropy32 <'a>,
//!     alarm: &'a A
//! }
//!
//! impl<'a, A: Alarm<'a>> EntropyTest<'a, A> {
//!     pub fn initialize(&self) {
//!         let now = self.alarm.now();
//!         let dt = self.alarm.ticks_from_seconds(1);
//!         self.alarm.set_alarm(now, dt);
//!     }
//! }
//!
//! impl<'a, A: Alarm<'a>> AlarmClient for EntropyTest<'a, A> {
//!     fn alarm(&self) {
//!         self.entropy.get();
//!     }
//! }
//!
//! impl<'a, A: Alarm<'a>> Client32 for EntropyTest<'a, A> {
//!     fn entropy_available(&self,
//!                          entropy: &mut dyn Iterator<Item = u32>,
//!                          error: Result<(), ErrorCode>) -> hil::entropy::Continue {
//!         match entropy.next() {
//!             Some(val) => {
//!                 println!("Entropy {}", val);
//!                 let now = self.alarm.now();
//!                 let dt = self.alarm.ticks_from_seconds(1);
//!                 self.alarm.set_alarm(now, dt);
//!                 hil::entropy::Continue::Done
//!             },
//!             None => hil::entropy::Continue::More
//!         }
//!     }
//! }
//! ```

use crate::ErrorCode;

/// Denotes whether the [Client](trait.Client.html) wants to be notified when
/// `More` randomness is available or if they are `Done`
#[derive(Debug, Eq, PartialEq)]
pub enum Continue {
    /// More randomness is required.
    More,
    /// No more randomness required.
    Done,
}

/// Generic interface for a 32-bit entropy source.
///
/// Implementors should assume the client implements the
/// [Client](trait.Client32.html) trait.
pub trait Entropy32<'a> {
    /// Initiate the acquisition of entropy.
    ///
    /// There are three valid return values:
    ///   - Ok(()): a `entropy_available` callback will be called in
    ///     the future when entropy is available.
    ///   - FAIL: a `entropy_available` callback will not be called in
    ///     the future, because entropy cannot be generated. This
    ///     is a general failure condition.
    ///   - OFF: a `entropy_available` callback will not be called in
    ///     the future, because the random number generator is off/not
    ///     powered.
    fn get(&self) -> Result<(), ErrorCode>;

    /// Cancel acquisition of entropy.
    ///
    /// There are three valid return values:
    ///   - Ok(()): an outstanding request from `get` has been cancelled,
    ///     or there was no outstanding request. No `entropy_available`
    ///     callback will be issued.
    ///   - FAIL: There will be a `entropy_available` callback, which
    ///     may or may not return an error code.
    fn cancel(&self) -> Result<(), ErrorCode>;

    /// Set the client to receive `entropy_available` callbacks.
    fn set_client(&'a self, _: &'a dyn Client32);
}

/// An [Entropy32](trait.Entropy32.html) client
///
/// Clients of an [Entropy32](trait.Entropy32.html) must implement this trait.
pub trait Client32 {
    /// Called by the (Entropy)[trait.Entropy32.html] when there is entropy
    /// available.
    ///
    /// `entropy` in an `Iterator` of available entropy. The amount of
    /// entropy available may increase if `entropy` is not consumed
    /// quickly so clients should not rely on iterator termination to
    /// finish consuming entropy.
    ///
    /// The client returns either `Continue::More` if the iterator did
    /// not have enough entropy (indicating another
    /// `entropy_available` callback is requested) and the client
    /// would like to be called again when more is available, or
    /// `Continue::Done`, which indicates `entropy_available` should
    /// not be called again until `get()` is called.
    ///
    /// If `entropy_available` is triggered after a call to `cancel()`
    /// then error MUST be CANCEL and `entropy` MAY contain bits of
    /// entropy.
    fn entropy_available(
        &self,
        entropy: &mut dyn Iterator<Item = u32>,
        error: Result<(), ErrorCode>,
    ) -> Continue;
}

/// An 8-bit entropy generator.
///
/// Implementors should assume the client implements the
/// [Client8](trait.Client8.html) trait.
pub trait Entropy8<'a> {
    /// Initiate the acquisition of new entropy.
    ///
    /// There are three valid return values:
    ///   - Ok(()): a `entropy_available` callback will be called in
    ///     the future when entropy is available.
    ///   - FAIL: a `entropy_available` callback will not be called in
    ///     the future, because entropy cannot be generated. This
    ///     is a general failure condition.
    ///   - OFF: a `entropy_available` callback will not be called in
    ///     the future, because the entropy generator is off/not
    ///     powered.
    fn get(&self) -> Result<(), ErrorCode>;

    /// Cancel acquisition of entropy.
    ///
    /// There are three valid return values:
    ///   - Ok(()): an outstanding request from `get` has been cancelled,
    ///     or there was no outstanding request. No `entropy_available`
    ///     callback will be issued.
    ///   - FAIL:: There will be a `entropy_available` callback, which
    ///     may or may not return an error code.
    fn cancel(&self) -> Result<(), ErrorCode>;

    /// Set the client to receive `entropy_available` callbacks.
    fn set_client(&'a self, _: &'a dyn Client8);
}

/// An [Entropy8](trait.Entropy8.html) client
///
/// Clients of an [Entropy8](trait.Entropy8.html) must implement this trait.
pub trait Client8 {
    /// Called by the (Entropy)[trait.Entropy8.html] when there are
    /// one or more bytes of entropy available.
    ///
    /// `entropy` in an `Iterator` of available entropy. The amount of
    /// entropy available may increase if `entropy` is not consumed
    /// quickly so clients should not rely on iterator termination to
    /// finish consuming entropy.
    ///
    /// The client returns either `Continue::More` if the iterator did
    /// not have enough entropy (indicating another
    /// `entropy_available` callback is requested) and the client
    /// would like to be called again when more is available, or
    /// `Continue::Done`, which indicates `entropy_available` should
    /// not be called again until `get()` is called.
    ///
    /// If `entropy_available` is triggered after a call to `cancel()`
    /// then error MUST be CANCEL and `entropy` MAY contain bits of
    /// entropy.
    fn entropy_available(
        &self,
        entropy: &mut dyn Iterator<Item = u8>,
        error: Result<(), ErrorCode>,
    ) -> Continue;
}