keyfork-mnemonic-generate: the math ain't mathin

This commit is contained in:
Ryan Heywood 2023-08-17 23:15:19 -05:00
parent 2c06b96953
commit 3032e11b78
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
3 changed files with 80 additions and 4 deletions

42
Cargo.lock generated
View File

@ -2,6 +2,23 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 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]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@ -72,6 +89,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
name = "keyfork-mnemonic-generate" name = "keyfork-mnemonic-generate"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bip39",
"hex", "hex",
"serde_json", "serde_json",
"sha2", "sha2",
@ -117,12 +135,36 @@ dependencies = [
"digest", "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]] [[package]]
name = "typenum" name = "typenum"
version = "1.16.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 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]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"

View File

@ -9,5 +9,6 @@ edition = "2021"
sha2 = "0.10.7" sha2 = "0.10.7"
[dev-dependencies] [dev-dependencies]
bip39 = "2.0.0"
hex = "0.4.3" hex = "0.4.3"
serde_json = "1.0.105" serde_json = "1.0.105"

View File

@ -93,6 +93,8 @@ fn ensure_offline() {
// TODO: Can a Mnemonic be formatted using a wordlist, without allocating or without storing the // TODO: Can a Mnemonic be formatted using a wordlist, without allocating or without storing the
// entire word list? // entire word list?
//
// NOTE: Yes, use a Language and pass a reference to this.
struct Mnemonic { struct Mnemonic {
pub words: Vec<usize>, pub words: Vec<usize>,
wordlist: Vec<String>, wordlist: Vec<String>,
@ -233,19 +235,50 @@ mod tests {
Ok(()) 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::<Vec<_>>();
*/
assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string());
}
#[test] #[test]
fn count_to_get_duplicate_words() { fn count_to_get_duplicate_words() {
let mut count = 0.; 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 entropy = &mut [0u8; 256 / 8];
let mut set = std::collections::HashMap::<&str, u32>::new();
for _ in 0..100_000 { for _ in 0..100_000 {
random_handle.read_exact(&mut entropy[..]).unwrap(); 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(); 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::<Vec<_>>();
words.dedup();
if words.len() != 24 {
count += 1.; 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())
} }
} }