Skip to main content

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}