From d333f987fe0e058ae7a43d95eb81a89c0d5721bf Mon Sep 17 00:00:00 2001 From: Ed Guloien Date: Thu, 23 Apr 2026 15:59:31 -0400 Subject: [PATCH] added reproducability Rng --- src/main.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8f0914b..ec0d7bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ use rand::Rng; use rand::rngs::OsRng; +use rand::SeedableRng; +use rand::rngs::StdRng; + use std::fs; use rand::prelude::SliceRandom; use bitflags::bitflags; @@ -127,7 +130,7 @@ fn validate_passphrase(password: &str, policy: &PassphraseConfig) -> bool { (policy.capitalize || upper) && (policy.symbol || symbol) && (policy.number || number) && - (lower) + (lower) // all passwords need lower chars } impl Default for PasswordConfig { @@ -142,7 +145,7 @@ impl Default for PasswordConfig { } } -fn random_ascii(rng: &mut OsRng, char_set: &[u8]) -> u8 { +fn random_ascii(rng: &mut impl Rng, char_set: &[u8]) -> u8 { // NOT IDEAL FOR CRYPTO/password generation // let range_max = 122; // 125 - 33 // let n = rng.next_u32() % range_max; // slightly modulo biased @@ -161,7 +164,7 @@ fn random_ascii(rng: &mut OsRng, char_set: &[u8]) -> u8 { // log2(possible_symbols^len) yields bits of entropy // so say len is 20 and we use all 80 chars: // that's log2(80^20) -> 126.4 bits of entropy per password -fn generate_password(config: &PasswordConfig, rng: &mut OsRng) -> Result { +fn generate_password(config: &PasswordConfig, rng: &mut impl Rng) -> Result { if config.len < 8 { return Err(String::from("Password length not long enough")); } @@ -207,7 +210,7 @@ fn generate_password(config: &PasswordConfig, rng: &mut OsRng) -> Result 4.1 bits for separator assuming seporator is one of our SYMBOLs // total 70.5 bits of entropy fn generate_passphrase(config: &PassphraseConfig, - word_list: &[&str], rng: &mut OsRng) -> Result { + word_list: &[&str], rng: &mut impl Rng) -> Result { if config.phrases < 2 { return Err("Phrase count too low".to_string()); } @@ -235,12 +238,10 @@ fn generate_passphrase(config: &PassphraseConfig, Ok(res) } -fn random_word<'a>(word_list: &[&'a str], rng: &mut OsRng) -> &'a str { +fn random_word<'a>(word_list: &[&'a str], rng: &mut impl Rng) -> &'a str { word_list[rng.gen_range(0..word_list.len())] } -// Some questions: -// todo: “What if I need reproducibility?” fn main() { // todo: not cross-platform // todo: abstract this a bit @@ -256,7 +257,13 @@ fn main() { // doesn't require seeding because it is backed by CSPRNG, backed by OS // the OS maintains it's own entropy from mouse movement, hardware noise,etc // we pass it through the functions to avoid a potential syscall - let mut rng = OsRng; + let mut _rng = OsRng; + + // when we are looking for Reproducability we can use the same seed value + // to create our Rng. Because both StdRng and OsRng implement Rng + // we make our methods slightly more generic and this works just fine + // comment out when we need random version! + let mut rng = StdRng::seed_from_u64(42); // todo: add actual tests // password with alphnumeric