kernel/hil/rng.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Interfaces for accessing a random number generator.
6//!
7//! A random number generator produces a stream of random numbers,
8//! either from hardware or based on an initial seed. The
9//! [RNG](trait.RNG.html) trait provides a simple, implementation
10//! agnostic interface for getting new random values.
11//!
12//! _Randomness_: Random numbers generated by this trait MUST pass
13//! standard randomness tests, such as A. Rukhin, J. Soto,
14//! J. Nechvatal, M. Smid, E. Barker, S. Leigh, M. Levenson,
15//! M. Vangel, D. Banks, A. Heckert, J. Dray, and S. Vo. A statistical
16//! test suite for random and pseudorandom number generators for
17//! cryptographic applications. Technical report, NIST, 2010. It is
18//! acceptable for implementations to rely on prior verification of
19//! the algorithm being used. For example, if the implementation
20//! chooses to use a Fishman and Moore Linear Congruence Generator
21//! (LCG) with the parameters specified in the NIST report above, it
22//! does not need to re-run the tests.
23//!
24//! Entropy: This trait does not promise high-entropy random numbers,
25//! although it MAY generate them. Implementations of this interface
26//! MAY generate random numbers using techniques other than true
27//! random number generation (through entropy) or cryptographically
28//! secure pseudorandom number generation. Other traits, described
29//! elsewhere, provide random numbers with entropy guarantees. This
30//! trait MUST NOT be used for randomness needed for security or
31//! cryptography. If high-entropy randomness is needed, the `Entropy`
32//! trait should be used instead.
33//!
34//! The Rng trait is designed to work well with random number
35//! generators that may not have values ready immediately. This is
36//! important when generating numbers from a low-bandwidth hardware
37//! random number generator or when the RNG is virtualized among many
38//! consumers. Random numbers are yielded to the
39//! [Client](trait.Client.html) as an `Iterator` which only terminates
40//! when no more numbers are currently available. Clients can request
41//! more randomness if needed and will be called again when more is
42//! available.
43//!
44//! The Random trait is synchronous, so designed to work
45//! with arithmetically simple random number generators that can
46//! return a result quickly.
47//!
48//!
49//! # Example
50//!
51//! The following example is a simple capsule that prints out a random number
52//! once a second using the `Alarm` and `RNG` traits.
53//!
54//! ```
55//! use kernel::hil;
56//! use kernel::hil::time::ConvertTicks;
57//! use kernel::hil::time::Frequency;
58//! use kernel::hil::time::Time;
59//! use kernel::ErrorCode;
60//!
61//! struct RngTest<'a, A: 'a + hil::time::Alarm<'a>> {
62//! rng: &'a dyn hil::rng::Rng<'a>,
63//! alarm: &'a A
64//! }
65//!
66//! impl<'a, A: hil::time::Alarm<'a>> RngTest<'a, A> {
67//! pub fn initialize(&self) {
68//! let now = self.alarm.now();
69//! let dt = self.alarm.ticks_from_seconds(1);
70//! self.alarm.set_alarm(now, dt);
71//! }
72//! }
73//!
74//! impl<'a, A: hil::time::Alarm<'a>> hil::time::AlarmClient for RngTest<'a, A> {
75//! fn alarm(&self) {
76//! self.rng.get();
77//! }
78//! }
79//!
80//! impl<'a, A: hil::time::Alarm<'a>> hil::rng::Client for RngTest<'a, A> {
81//! fn randomness_available(&self,
82//! randomness: &mut dyn Iterator<Item = u32>,
83//! error: Result<(), ErrorCode>) -> hil::rng::Continue {
84//! match randomness.next() {
85//! Some(random) => {
86//! println!("Rand {}", random);
87//! let now = self.alarm.now();
88//! let dt = self.alarm.ticks_from_seconds(1);
89//!
90//! self.alarm.set_alarm(now, dt);
91//! hil::rng::Continue::Done
92//! },
93//! None => hil::rng::Continue::More
94//! }
95//! }
96//! }
97//! ```
98
99use crate::ErrorCode;
100
101/// Denotes whether the [Client](trait.Client.html) wants to be notified when
102/// `More` randomness is available or if they are `Done`
103#[derive(Debug, Eq, PartialEq)]
104pub enum Continue {
105 /// More randomness is required.
106 More,
107 /// No more randomness required.
108 Done,
109}
110
111/// Generic interface for a 32-bit random number generator.
112///
113/// Implementors should assume the client implements the
114/// [Client](trait.Client.html) trait.
115pub trait Rng<'a> {
116 /// Initiate the aquisition of new random number generation.
117 ///
118 /// There are three valid return values:
119 /// - Ok(()): a `randomness_available` callback will be called in
120 /// the future when randomness is available.
121 /// - FAIL: a `randomness_available` callback will not be called in
122 /// the future, because random numbers cannot be generated. This
123 /// is a general failure condition.
124 /// - OFF: a `randomness_available` callback will not be called in
125 /// the future, because the random number generator is off/not
126 /// powered.
127 fn get(&self) -> Result<(), ErrorCode>;
128
129 /// Cancel acquisition of random numbers.
130 ///
131 /// There are two valid return values:
132 /// - Ok(()): an outstanding request from `get` has been cancelled,
133 /// or there was no oustanding request. No `randomness_available`
134 /// callback will be issued.
135 /// - FAIL: There will be a randomness_available callback, which
136 /// may or may not return an error code.
137 fn cancel(&self) -> Result<(), ErrorCode>;
138 fn set_client(&'a self, _: &'a dyn Client);
139}
140
141/// An [Rng](trait.Rng.html) client
142///
143/// Clients of an [Rng](trait.Rng.html) must implement this trait.
144pub trait Client {
145 /// Called by the (RNG)[trait.RNG.html] when there are one or more random
146 /// numbers available
147 ///
148 /// `randomness` in an `Iterator` of available random numbers. The amount of
149 /// randomness available may increase if `randomness` is not consumed
150 /// quickly so clients should not rely on iterator termination to finish
151 /// consuming random numbers.
152 ///
153 /// The client returns either `Continue::More` if the iterator did not have
154 /// enough random values and the client would like to be called again when
155 /// more is available, or `Continue::Done`.
156 ///
157 /// If randoness_available is triggered after a call to cancel()
158 /// then error MUST be CANCEL and randomness MAY contain
159 /// random bits.
160 fn randomness_available(
161 &self,
162 randomness: &mut dyn Iterator<Item = u32>,
163 error: Result<(), ErrorCode>,
164 ) -> Continue;
165}
166
167/// Generic interface for a synchronous 32-bit random number
168/// generator.
169
170pub trait Random<'a> {
171 /// Initialize/reseed the random number generator from an
172 /// internal source. This initialization MAY be deterministic
173 /// (e.g., based on an EUI-64) or MAY be random (e.g., based on an
174 /// underlying hardware entropy source); an implementation SHOULD
175 /// make reseeding random.
176 fn initialize(&'a self);
177
178 /// Reseed the random number generator with a specific
179 /// seed. Useful for deterministic tests.
180 fn reseed(&self, seed: u32);
181
182 /// Generate a 32-bit random number.
183 fn random(&self) -> u32;
184}