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] 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//! # Example
45//!
46//! The following example is a simple capsule that prints out a random number
47//! once a second using the `Alarm` and `Rng` traits.
48//!
49//! ```
50//! use kernel::hil;
51//! use kernel::hil::time::ConvertTicks;
52//! use kernel::hil::time::Frequency;
53//! use kernel::hil::time::Time;
54//! use kernel::ErrorCode;
55//!
56//! struct RngTest<'a, A: 'a + hil::time::Alarm<'a>> {
57//! rng: &'a dyn hil::rng::Rng<'a>,
58//! alarm: &'a A
59//! }
60//!
61//! impl<'a, A: hil::time::Alarm<'a>> RngTest<'a, A> {
62//! pub fn initialize(&self) {
63//! let now = self.alarm.now();
64//! let dt = self.alarm.ticks_from_seconds(1);
65//! self.alarm.set_alarm(now, dt);
66//! }
67//! }
68//!
69//! impl<'a, A: hil::time::Alarm<'a>> hil::time::AlarmClient for RngTest<'a, A> {
70//! fn alarm(&self) {
71//! self.rng.get();
72//! }
73//! }
74//!
75//! impl<'a, A: hil::time::Alarm<'a>> hil::rng::Client for RngTest<'a, A> {
76//! fn randomness_available(&self,
77//! randomness: &mut dyn Iterator<Item = u32>,
78//! error: Result<(), ErrorCode>) -> hil::rng::Continue {
79//! match randomness.next() {
80//! Some(random) => {
81//! println!("Rand {}", random);
82//! let now = self.alarm.now();
83//! let dt = self.alarm.ticks_from_seconds(1);
84//!
85//! self.alarm.set_alarm(now, dt);
86//! hil::rng::Continue::Done
87//! },
88//! None => hil::rng::Continue::More
89//! }
90//! }
91//! }
92//! ```
93
94use crate::ErrorCode;
95
96/// Denotes whether the [Client] wants to be notified when
97/// `More` randomness is available or if they are `Done`
98#[derive(Debug, Eq, PartialEq)]
99pub enum Continue {
100 /// More randomness is required.
101 More,
102 /// No more randomness required.
103 Done,
104}
105
106/// Generic interface for a 32-bit random number generator.
107///
108/// Implementors should assume the client implements the
109/// [Client] trait.
110pub trait Rng<'a> {
111 /// Initiate the aquisition of new random number generation.
112 ///
113 /// There are three valid return values:
114 /// - Ok(()): a `randomness_available` callback will be called in
115 /// the future when randomness is available.
116 /// - FAIL: a `randomness_available` callback will not be called in
117 /// the future, because random numbers cannot be generated. This
118 /// is a general failure condition.
119 /// - OFF: a `randomness_available` callback will not be called in
120 /// the future, because the random number generator is off/not
121 /// powered.
122 fn get(&self) -> Result<(), ErrorCode>;
123
124 /// Cancel acquisition of random numbers.
125 ///
126 /// There are two valid return values:
127 /// - Ok(()): an outstanding request from `get` has been cancelled,
128 /// or there was no oustanding request. No `randomness_available`
129 /// callback will be issued.
130 /// - FAIL: There will be a randomness_available callback, which
131 /// may or may not return an error code.
132 fn cancel(&self) -> Result<(), ErrorCode>;
133 fn set_client(&'a self, _: &'a dyn Client);
134}
135
136/// An [Rng] client
137///
138/// Clients of an [Rng] must implement this trait.
139pub trait Client {
140 /// Called by the (RNG)[trait.RNG.html] when there are one or more random
141 /// numbers available
142 ///
143 /// `randomness` in an `Iterator` of available random numbers. The amount of
144 /// randomness available may increase if `randomness` is not consumed
145 /// quickly so clients should not rely on iterator termination to finish
146 /// consuming random numbers.
147 ///
148 /// The client returns either `Continue::More` if the iterator did not have
149 /// enough random values and the client would like to be called again when
150 /// more is available, or `Continue::Done`.
151 ///
152 /// If randoness_available is triggered after a call to cancel()
153 /// then error MUST be CANCEL and randomness MAY contain
154 /// random bits.
155 fn randomness_available(
156 &self,
157 randomness: &mut dyn Iterator<Item = u32>,
158 error: Result<(), ErrorCode>,
159 ) -> Continue;
160}