/rust/registry/src/index.crates.io-1949cf8c6b5b557f/vmm-sys-util-0.15.0/src/rand.rs
Line | Count | Source |
1 | | // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
2 | | // SPDX-License-Identifier: BSD-3-Clause |
3 | | |
4 | | //! Miscellaneous functions related to getting (pseudo) random numbers and |
5 | | //! strings. |
6 | | //! |
7 | | //! NOTE! This should not be used when you do need __real__ random numbers such |
8 | | //! as for encryption but will probably be suitable when you want locally |
9 | | //! unique ID's that will not be shared over the network. |
10 | | |
11 | | use std::ffi::OsString; |
12 | | use std::str; |
13 | | |
14 | | /// Gets an ever increasing u64 (at least for this process). |
15 | | /// |
16 | | /// The number retrieved will be based upon the time of the last reboot (x86_64) |
17 | | /// and something undefined for other architectures. |
18 | 0 | pub fn timestamp_cycles() -> u64 { |
19 | | #[cfg(target_arch = "x86_64")] |
20 | | // SAFETY: Safe because there's nothing that can go wrong with this call. |
21 | | unsafe { |
22 | 0 | std::arch::x86_64::_rdtsc() |
23 | | } |
24 | | |
25 | | #[cfg(not(target_arch = "x86_64"))] |
26 | | { |
27 | | const MONOTONIC_CLOCK_MULTPIPLIER: u64 = 1_000_000_000; |
28 | | |
29 | | let mut ts = libc::timespec { |
30 | | tv_sec: 0, |
31 | | tv_nsec: 0, |
32 | | }; |
33 | | // SAFETY: We initialized the parameters correctly and we trust the function. |
34 | | unsafe { |
35 | | libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts); |
36 | | } |
37 | | (ts.tv_sec as u64) * MONOTONIC_CLOCK_MULTPIPLIER + (ts.tv_nsec as u64) |
38 | | } |
39 | 0 | } |
40 | | |
41 | | /// Generate pseudo random u32 numbers based on the current timestamp. |
42 | 0 | pub fn xor_pseudo_rng_u32() -> u32 { |
43 | 0 | let mut t: u32 = timestamp_cycles() as u32; |
44 | | // Taken from https://en.wikipedia.org/wiki/Xorshift |
45 | 0 | t ^= t << 13; |
46 | 0 | t ^= t >> 17; |
47 | 0 | t ^ (t << 5) |
48 | 0 | } |
49 | | |
50 | | // This will get an array of numbers that can safely be converted to strings |
51 | | // because they will be in the range [a-zA-Z0-9]. The return vector could be any |
52 | | // size between 0 and 4. |
53 | 0 | fn xor_pseudo_rng_u8_alphanumerics(rand_fn: &dyn Fn() -> u32) -> Vec<u8> { |
54 | 0 | rand_fn() |
55 | 0 | .to_ne_bytes() |
56 | 0 | .to_vec() |
57 | 0 | .drain(..) |
58 | 0 | .filter(|val| { |
59 | 0 | (48..=57).contains(val) || (65..=90).contains(val) || (97..=122).contains(val) |
60 | 0 | }) |
61 | 0 | .collect() |
62 | 0 | } |
63 | | |
64 | 0 | fn xor_pseudo_rng_u8_bytes(rand_fn: &dyn Fn() -> u32) -> Vec<u8> { |
65 | 0 | rand_fn().to_ne_bytes().to_vec() |
66 | 0 | } |
67 | | |
68 | 0 | fn rand_alphanumerics_impl(rand_fn: &dyn Fn() -> u32, len: usize) -> OsString { |
69 | 0 | let mut buf = OsString::new(); |
70 | 0 | let mut done = 0; |
71 | | loop { |
72 | 0 | for n in xor_pseudo_rng_u8_alphanumerics(rand_fn) { |
73 | 0 | done += 1; |
74 | 0 | buf.push(str::from_utf8(&[n]).unwrap_or("_")); |
75 | 0 | if done >= len { |
76 | 0 | return buf; |
77 | 0 | } |
78 | | } |
79 | | } |
80 | 0 | } |
81 | | |
82 | 0 | fn rand_bytes_impl(rand_fn: &dyn Fn() -> u32, len: usize) -> Vec<u8> { |
83 | 0 | let mut buf: Vec<Vec<u8>> = Vec::new(); |
84 | 0 | let mut num = if len % 4 == 0 { len / 4 } else { len / 4 + 1 }; |
85 | 0 | while num > 0 { |
86 | 0 | buf.push(xor_pseudo_rng_u8_bytes(rand_fn)); |
87 | 0 | num -= 1; |
88 | 0 | } |
89 | 0 | buf.into_iter().flatten().take(len).collect() |
90 | 0 | } |
91 | | |
92 | | /// Gets a pseudo random OsString of length `len` with characters in the |
93 | | /// range [a-zA-Z0-9]. |
94 | 0 | pub fn rand_alphanumerics(len: usize) -> OsString { |
95 | 0 | rand_alphanumerics_impl(&xor_pseudo_rng_u32, len) |
96 | 0 | } |
97 | | |
98 | | /// Get a pseudo random vector of `len` bytes. |
99 | 0 | pub fn rand_bytes(len: usize) -> Vec<u8> { |
100 | 0 | rand_bytes_impl(&xor_pseudo_rng_u32, len) |
101 | 0 | } |
102 | | |
103 | | #[cfg(test)] |
104 | | mod tests { |
105 | | use super::*; |
106 | | |
107 | | #[test] |
108 | | fn test_timestamp_cycles() { |
109 | | for _ in 0..1000 { |
110 | | assert!(timestamp_cycles() < timestamp_cycles()); |
111 | | } |
112 | | } |
113 | | |
114 | | #[test] |
115 | | fn test_xor_pseudo_rng_u32() { |
116 | | for _ in 0..1000 { |
117 | | assert_ne!(xor_pseudo_rng_u32(), xor_pseudo_rng_u32()); |
118 | | } |
119 | | } |
120 | | |
121 | | #[test] |
122 | | fn test_xor_pseudo_rng_u8_alphas() { |
123 | | let i = 3612982; // 55 (shifted 16 places), 33 (shifted 8 places), 54... |
124 | | // The 33 will be discarded as it is not a valid letter |
125 | | // (upper or lower) or number. |
126 | | let s = xor_pseudo_rng_u8_alphanumerics(&|| i); |
127 | | if cfg!(target_endian = "big") { |
128 | | assert_eq!(vec![55, 54], s); |
129 | | } else { |
130 | | assert_eq!(vec![54, 55], s); |
131 | | } |
132 | | } |
133 | | |
134 | | #[test] |
135 | | fn test_rand_alphanumerics_impl() { |
136 | | let s = rand_alphanumerics_impl(&|| 14134, 5); |
137 | | if cfg!(target_endian = "big") { |
138 | | assert_eq!("76767", s); |
139 | | } else { |
140 | | assert_eq!("67676", s); |
141 | | } |
142 | | } |
143 | | |
144 | | #[test] |
145 | | fn test_rand_alphanumerics() { |
146 | | let s = rand_alphanumerics(5); |
147 | | assert_eq!(5, s.len()); |
148 | | } |
149 | | |
150 | | #[test] |
151 | | fn test_xor_pseudo_rng_u8_bytes() { |
152 | | let i = 3612982; // 55 (shifted 16 places), 33 (shifted 8 places), 54... |
153 | | // The 33 will be discarded as it is not a valid letter |
154 | | // (upper or lower) or number. |
155 | | let s = xor_pseudo_rng_u8_bytes(&|| i); |
156 | | if cfg!(target_endian = "big") { |
157 | | assert_eq!(vec![0, 55, 33, 54], s); |
158 | | } else { |
159 | | assert_eq!(vec![54, 33, 55, 0], s); |
160 | | } |
161 | | } |
162 | | |
163 | | #[test] |
164 | | fn test_rand_bytes_impl() { |
165 | | let s = rand_bytes_impl(&|| 1234567, 4); |
166 | | if cfg!(target_endian = "big") { |
167 | | assert_eq!(vec![0, 18, 214, 135], s); |
168 | | } else { |
169 | | assert_eq!(vec![135, 214, 18, 0], s); |
170 | | } |
171 | | } |
172 | | |
173 | | #[test] |
174 | | fn test_rand_bytes() { |
175 | | for i in 0..8 { |
176 | | assert_eq!(i, rand_bytes(i).len()); |
177 | | } |
178 | | } |
179 | | } |