• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fs::File;
6 use std::io::{self, Read};
7 
8 /// A simple prng based on a Linear congruential generator
9 /// https://en.wikipedia.org/wiki/Linear_congruential_generator
10 pub struct SimpleRng {
11     seed: u64,
12 }
13 
14 impl SimpleRng {
15     /// Create a new SimpleRng
new(seed: u64) -> SimpleRng16     pub fn new(seed: u64) -> SimpleRng {
17         SimpleRng { seed }
18     }
19 
20     /// Generate random u64
rng(&mut self) -> u6421     pub fn rng(&mut self) -> u64 {
22         // a simple Linear congruential generator
23         let a: u64 = 6364136223846793005;
24         let c: u64 = 1442695040888963407;
25         self.seed = a.wrapping_mul(self.seed).wrapping_add(c);
26         self.seed
27     }
28 }
29 
30 // Uniformly samples the ASCII alphanumeric characters given a random variable. If an `Err` is
31 // passed in, the error is returned as `Some(Err(...))`. If the the random variable can not be used
32 // to uniformly sample, `None` is returned.
uniform_sample_ascii_alphanumeric( b: Result<u8, std::io::Error>, ) -> Option<Result<char, std::io::Error>>33 fn uniform_sample_ascii_alphanumeric(
34     b: Result<u8, std::io::Error>,
35 ) -> Option<Result<char, std::io::Error>> {
36     const ASCII_CHARS: &[u8] = b"\
37           ABCDEFGHIJKLMNOPQRSTUVWXYZ\
38           abcdefghijklmnopqrstuvwxyz\
39           0123456789";
40     let char_index = match b {
41         Ok(c) => c as usize,
42         Err(e) => return Some(Err(e)),
43     };
44     // Throw away numbers that would cause sampling bias.
45     if char_index >= ASCII_CHARS.len() * 4 {
46         None
47     } else {
48         Some(Ok(ASCII_CHARS[char_index % ASCII_CHARS.len()] as char))
49     }
50 }
51 
52 /// Samples `/dev/urandom` and generates a random ASCII string of length `len`
urandom_str(len: usize) -> io::Result<String>53 pub fn urandom_str(len: usize) -> io::Result<String> {
54     File::open("/dev/urandom")?
55         .bytes()
56         .filter_map(uniform_sample_ascii_alphanumeric)
57         .take(len)
58         .collect::<io::Result<String>>()
59 }
60 
61 #[cfg(test)]
62 mod tests {
63     use super::*;
64 
65     #[test]
check_100()66     fn check_100() {
67         for i in 0..100 {
68             let s = urandom_str(i).unwrap();
69             assert_eq!(s.len(), i);
70             assert!(s.is_ascii());
71             assert!(!s.contains(' '));
72             assert!(!s.contains(|c: char| !c.is_ascii_alphanumeric()));
73         }
74     }
75 }
76