From 3032e11b784022b17b4f5111ab271c647d989eb7 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 17 Aug 2023 23:15:19 -0500 Subject: [PATCH] keyfork-mnemonic-generate: the math ain't mathin --- Cargo.lock | 42 +++++++++++++++++++++++++++ keyfork-mnemonic-generate/Cargo.toml | 1 + keyfork-mnemonic-generate/src/main.rs | 41 +++++++++++++++++++++++--- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53b71e4..2ec4b6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,23 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bip39" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +dependencies = [ + "bitcoin_hashes", + "serde", + "unicode-normalization", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + [[package]] name = "block-buffer" version = "0.10.4" @@ -72,6 +89,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" name = "keyfork-mnemonic-generate" version = "0.1.0" dependencies = [ + "bip39", "hex", "serde_json", "sha2", @@ -117,12 +135,36 @@ dependencies = [ "digest", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "typenum" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/keyfork-mnemonic-generate/Cargo.toml b/keyfork-mnemonic-generate/Cargo.toml index 4652cd1..6e78648 100644 --- a/keyfork-mnemonic-generate/Cargo.toml +++ b/keyfork-mnemonic-generate/Cargo.toml @@ -9,5 +9,6 @@ edition = "2021" sha2 = "0.10.7" [dev-dependencies] +bip39 = "2.0.0" hex = "0.4.3" serde_json = "1.0.105" diff --git a/keyfork-mnemonic-generate/src/main.rs b/keyfork-mnemonic-generate/src/main.rs index de974ad..7f3b702 100644 --- a/keyfork-mnemonic-generate/src/main.rs +++ b/keyfork-mnemonic-generate/src/main.rs @@ -93,6 +93,8 @@ fn ensure_offline() { // TODO: Can a Mnemonic be formatted using a wordlist, without allocating or without storing the // entire word list? +// +// NOTE: Yes, use a Language and pass a reference to this. struct Mnemonic { pub words: Vec, wordlist: Vec, @@ -233,19 +235,50 @@ mod tests { Ok(()) } + #[test] + fn matches_bip39_crate() { + let mut random_handle = File::open("/dev/random").unwrap(); + let entropy = &mut [0u8; 256 / 8]; + random_handle.read_exact(&mut entropy[..]).unwrap(); + let my_mnemonic = super::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap(); + let their_mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap(); + /* + let my_words = my_mnemonic.words.clone(); + let their_words = their_mnemonic.word_iter().collect::>(); + */ + assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string()); + } + #[test] fn count_to_get_duplicate_words() { let mut count = 0.; - let mut random_handle = File::open("/dev/urandom").unwrap(); + let mut smallest = 2048; + let mut largest = 0; + let mut random_handle = File::open("/dev/random").unwrap(); let entropy = &mut [0u8; 256 / 8]; + let mut set = std::collections::HashMap::<&str, u32>::new(); for _ in 0..100_000 { random_handle.read_exact(&mut entropy[..]).unwrap(); - let mut mnemonic = Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap(); + // let bits = generate_slice_hash(entropy); + let mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap(); + /* mnemonic.words.dedup(); - if mnemonic.words.len() != 24 { + */ + // NOTE: This pulls everything BUT the last word, just for testing. + // Change to ..24 to include the last word. + for (word, _) in mnemonic.word_iter().zip(0..23) { + *set.entry(word).or_insert(0) += 1; + } + let mut words = mnemonic.word_iter().collect::>(); + words.dedup(); + if words.len() != 24 { count += 1.; } } - panic!("counts: {count} {}", count / 100_000.) + for entry in &set { + smallest = std::cmp::min(smallest, *entry.1); + largest = std::cmp::max(largest, *entry.1); + } + panic!("{count} len:{} smallest:{smallest} largest:{largest}", set.len()) } }