use sha2::{Digest, Sha256};
pub fn rand_bytes<const N: usize>() -> [u8; N] {
let mut buf = [0u8; N];
getrandom::fill(&mut buf).expect("OS entropy source (getrandom) unavailable");
buf
}
pub fn new_secret_hex() -> String {
let bytes: [u8; 32] = rand_bytes::<32>();
bytes.iter().map(|b| format!("{b:02x}")).collect()
}
pub fn new_uuid() -> String {
let bytes: [u8; 16] = rand_bytes::<16>();
let hex: String = bytes.iter().map(|b| format!("{b:02x}")).collect();
format!(
"{}-{}-{}-{}-{}",
&hex[0..8],
&hex[8..12],
&hex[12..16],
&hex[16..20],
&hex[20..32]
)
}
pub fn sha256_hex(input: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(input.as_bytes());
let digest = hasher.finalize();
digest.iter().map(|b| format!("{b:02x}")).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_uuid_has_expected_shape() {
let id = new_uuid();
let parts: Vec<&str> = id.split('-').collect();
assert_eq!(parts.len(), 5);
assert_eq!(parts[0].len(), 8);
assert_eq!(parts[1].len(), 4);
assert_eq!(parts[2].len(), 4);
assert_eq!(parts[3].len(), 4);
assert_eq!(parts[4].len(), 12);
assert!(id.chars().all(|c| c.is_ascii_hexdigit() || c == '-'));
}
#[test]
fn new_uuid_is_unique() {
assert_ne!(new_uuid(), new_uuid());
}
#[test]
fn new_secret_hex_is_64_chars() {
let s = new_secret_hex();
assert_eq!(s.len(), 64);
assert!(s.chars().all(|c| c.is_ascii_hexdigit()));
}
#[test]
fn sha256_hex_is_deterministic() {
assert_eq!(sha256_hex("abc"), sha256_hex("abc"));
assert_ne!(sha256_hex("abc"), sha256_hex("abd"));
assert_eq!(sha256_hex("").len(), 64);
}
#[test]
fn rand_bytes_are_distinct_across_many_calls() {
use std::collections::HashSet;
let mut seen = HashSet::new();
for _ in 0..2_000 {
assert!(
seen.insert(rand_bytes::<32>()),
"rand_bytes produced a duplicate 32-byte value"
);
}
}
#[test]
fn rand_bytes_cover_every_bit_position() {
let mut ever_set = [0u8; 32];
let mut ever_clear = [0xffu8; 32];
for _ in 0..256 {
let b = rand_bytes::<32>();
for i in 0..32 {
ever_set[i] |= b[i];
ever_clear[i] &= b[i];
}
}
assert_eq!(ever_set, [0xffu8; 32], "a bit position was never set");
assert_eq!(ever_clear, [0u8; 32], "a bit position was never cleared");
}
}