capsules_core/test/
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//! Test entropy and random number generators.
6//!
7//! Usually, to test the full library, these generators should be
8//! through two layers of translation for entropy then converted to
9//! randomness. For example, if your platform provides an Entropy32,
10//! then test Entropy32 -> Entropy32to8 -> Entropy8to32 ->
11//! Entropy32ToRandom. Then simply ask for ELEMENTS random numbers and
12//! print them in hex to console.
13
14use core::cell::Cell;
15
16use kernel::debug;
17use kernel::hil::entropy;
18use kernel::hil::rng;
19use kernel::ErrorCode;
20
21const ELEMENTS: usize = 8;
22
23pub struct TestRandom<'a> {
24    random: &'a dyn rng::Random<'a>,
25}
26
27impl<'a> TestRandom<'a> {
28    pub fn new(random: &'a dyn rng::Random<'a>) -> TestRandom<'a> {
29        TestRandom { random }
30    }
31
32    pub fn run(&self) {
33        self.random.initialize();
34        for _i in 0..ELEMENTS {
35            let val = self.random.random();
36            debug!("TestRandom: generated synchronous random number: {}", val);
37        }
38    }
39}
40
41// Use this test to test an Rng
42pub struct TestRng<'a> {
43    rng: &'a dyn rng::Rng<'a>,
44    pool: Cell<[u32; ELEMENTS]>,
45    count: Cell<usize>,
46}
47
48impl<'a> TestRng<'a> {
49    pub fn new(rng: &'a dyn rng::Rng<'a>) -> TestRng<'a> {
50        TestRng {
51            rng,
52            pool: Cell::new([0xeeeeeeee; ELEMENTS]),
53            count: Cell::new(0),
54        }
55    }
56
57    pub fn run(&self) {
58        match self.rng.get() {
59            Ok(()) => debug!("RNG test: first get Ok(())"),
60            _ => panic!("RNG test: unable to get random numbers"),
61        }
62    }
63}
64
65impl rng::Client for TestRng<'_> {
66    fn randomness_available(
67        &self,
68        randomness: &mut dyn Iterator<Item = u32>,
69        error: Result<(), ErrorCode>,
70    ) -> rng::Continue {
71        let mut val = randomness.next();
72        if error != Ok(()) {
73            panic!(
74                "RNG test: randomness_available called with error {:?}",
75                error
76            );
77        }
78        while val.is_some() {
79            //debug!("RNG test: iterator returned Some.");
80            let data = val.unwrap();
81
82            let mut pool = self.pool.get();
83            let mut count = self.count.get();
84            pool[count] = data;
85            count += 1;
86            self.pool.set(pool);
87            self.count.set(count);
88
89            if count >= ELEMENTS {
90                debug!("RNG test: obtained all {} values. They are:", count);
91                for (i, c) in pool.iter().enumerate() {
92                    debug!("[{:02x}]: {:08x}", i, c);
93                }
94                return rng::Continue::Done;
95            } else {
96                val = randomness.next();
97            }
98        }
99        // val must be None: out of randomness, ask for more
100        rng::Continue::More
101    }
102}
103
104// Use this test to test a 32 bit Entropy source
105pub struct TestEntropy32<'a> {
106    egen: &'a dyn entropy::Entropy32<'a>,
107    pool: Cell<[u32; ELEMENTS]>,
108    count: Cell<usize>,
109}
110
111impl<'a> TestEntropy32<'a> {
112    pub fn new(egen: &'a dyn entropy::Entropy32<'a>) -> TestEntropy32<'a> {
113        TestEntropy32 {
114            egen,
115            pool: Cell::new([0xeeeeeeee; ELEMENTS]),
116            count: Cell::new(0),
117        }
118    }
119
120    pub fn run(&self) {
121        match self.egen.get() {
122            Ok(()) => debug!("Entropy32 test: first get Ok(())"),
123            _ => panic!("Entropy32 test: unable to get entropy"),
124        }
125    }
126}
127
128impl entropy::Client32 for TestEntropy32<'_> {
129    fn entropy_available(
130        &self,
131        entropy: &mut dyn Iterator<Item = u32>,
132        error: Result<(), ErrorCode>,
133    ) -> entropy::Continue {
134        let mut val = entropy.next();
135        if error != Ok(()) {
136            panic!(
137                "RNG test: randomness_available called with error {:?}",
138                error
139            );
140        }
141        while val.is_some() {
142            //debug!("RNG test: iterator returned Some.");
143            let data = val.unwrap();
144
145            let mut pool = self.pool.get();
146            let mut count = self.count.get();
147            pool[count] = data;
148            count += 1;
149            self.pool.set(pool);
150            self.count.set(count);
151
152            if count >= ELEMENTS {
153                debug!("Entropy test: obtained all {} values. They are:", count);
154                for i in 0..pool.len() {
155                    debug!("[{:02x}]: {:08x}", i, pool[i]);
156                }
157                return entropy::Continue::Done;
158            } else {
159                val = entropy.next();
160            }
161        }
162        // val must be None: out of randomness, ask for more
163        entropy::Continue::More
164    }
165}
166
167// Use this test if the underlying Entropy source is an Entropy8
168pub struct TestEntropy8<'a> {
169    egen: &'a dyn entropy::Entropy8<'a>,
170    pool: Cell<[u8; ELEMENTS]>,
171    count: Cell<usize>,
172}
173
174impl<'a> TestEntropy8<'a> {
175    pub fn new(egen: &'a dyn entropy::Entropy8<'a>) -> TestEntropy8<'a> {
176        TestEntropy8 {
177            egen,
178            pool: Cell::new([0xee; ELEMENTS]),
179            count: Cell::new(0),
180        }
181    }
182
183    pub fn run(&self) {
184        match self.egen.get() {
185            Ok(()) => debug!("Entropy8 test: first get Ok(())"),
186            _ => panic!("RNG test: unable to get random numbers"),
187        }
188    }
189}
190
191impl entropy::Client8 for TestEntropy8<'_> {
192    fn entropy_available(
193        &self,
194        entropy: &mut dyn Iterator<Item = u8>,
195        error: Result<(), ErrorCode>,
196    ) -> entropy::Continue {
197        let mut val = entropy.next();
198        if error != Ok(()) {
199            panic!(
200                "Entropy8 test: entropy_available called with error {:?}",
201                error
202            );
203        }
204        while val.is_some() {
205            debug!("Entropy8 test: entropy_available iterator returned Some, adding.");
206            let data = val.unwrap();
207
208            let mut pool = self.pool.get();
209            let mut count = self.count.get();
210            pool[count] = data;
211            count += 1;
212            self.pool.set(pool);
213            self.count.set(count);
214
215            if count >= ELEMENTS {
216                debug!("RNG test: obtained {} values. They are:", count);
217                for i in 0..pool.len() {
218                    debug!("[{:02x}]: {:02x}", i, pool[i]);
219                }
220                return entropy::Continue::Done;
221            } else {
222                val = entropy.next();
223            }
224        }
225        debug!("Entropy8 test: entropy_available iterator returned None, requesting more.");
226        // val must be None: out of entropy, ask for more
227        entropy::Continue::More
228    }
229}