1use std::io::Read;
7
8pub fn bytes(length: usize) -> Vec<u8> {
10 let mut buffer = vec![0u8; length];
11
12 if let Ok(mut source) = std::fs::File::open("/dev/urandom")
13 && source.read_exact(&mut buffer).is_ok() {
14 return buffer;
15 }
16
17 let now = std::time::SystemTime::now()
21 .duration_since(std::time::UNIX_EPOCH)
22 .map(|d| d.as_nanos() as u64)
23 .unwrap_or(0);
24 let mut state = now ^ (Box::into_raw(Box::new(0u8)) as u64);
25
26 for slot in buffer.iter_mut() {
27 state ^= state << 13;
28 state ^= state >> 7;
29 state ^= state << 17;
30 *slot = (state >> 24) as u8;
31 }
32 buffer
33}
34
35pub fn nonce(length: usize) -> String {
37 const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
38
39 bytes(length)
40 .into_iter()
41 .map(|byte| ALPHABET[byte as usize % ALPHABET.len()] as char)
42 .collect()
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn nonces_are_the_requested_length_and_printable() {
51 let value = nonce(24);
52
53 assert_eq!(value.len(), 24);
54 assert!(value.chars().all(|c| c.is_ascii_alphanumeric()));
55 }
56
57 #[test]
58 fn two_nonces_differ() {
59 assert_ne!(nonce(24), nonce(24));
60 }
61}