rand_ish: Generate random string from SimpleRng

Devices may not have access to /dev/urandom so refactor the random
string generation code so that it can also be used by SimpleRng.  Also
implement Iterator for SimpleRng to make the string generator
implementation easier.

BUG=b:152806644,b:159285544
TEST=unit tests

Change-Id: I245c90dc44cfa53a7e12343925b1e04a5df55255
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2260252
Auto-Submit: Chirantan Ekbote <chirantan@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
This commit is contained in:
Chirantan Ekbote 2020-06-23 16:27:43 +09:00 committed by Commit Bot
parent 708e3a63b9
commit da69086e9f

View file

@ -25,27 +25,37 @@ impl SimpleRng {
self.seed = a.wrapping_mul(self.seed).wrapping_add(c);
self.seed
}
/// Generate a random alphanumeric string.
pub fn str(&mut self, len: usize) -> String {
self.filter_map(|v| uniform_sample_ascii_alphanumeric(v as u8))
.take(len)
.collect()
}
}
impl Iterator for SimpleRng {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
Some(self.rng())
}
}
// Uniformly samples the ASCII alphanumeric characters given a random variable. If an `Err` is
// passed in, the error is returned as `Some(Err(...))`. If the the random variable can not be used
// to uniformly sample, `None` is returned.
fn uniform_sample_ascii_alphanumeric(
b: Result<u8, std::io::Error>,
) -> Option<Result<char, std::io::Error>> {
fn uniform_sample_ascii_alphanumeric(b: u8) -> Option<char> {
const ASCII_CHARS: &[u8] = b"\
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789";
let char_index = match b {
Ok(c) => c as usize,
Err(e) => return Some(Err(e)),
};
let char_index = b as usize;
// Throw away numbers that would cause sampling bias.
if char_index >= ASCII_CHARS.len() * 4 {
None
} else {
Some(Ok(ASCII_CHARS[char_index % ASCII_CHARS.len()] as char))
Some(ASCII_CHARS[char_index % ASCII_CHARS.len()] as char)
}
}
@ -53,7 +63,7 @@ fn uniform_sample_ascii_alphanumeric(
pub fn urandom_str(len: usize) -> io::Result<String> {
File::open("/dev/urandom")?
.bytes()
.filter_map(uniform_sample_ascii_alphanumeric)
.filter_map(|b| b.map(uniform_sample_ascii_alphanumeric).transpose())
.take(len)
.collect::<io::Result<String>>()
}