keyfork-mnemonic-generate: begin work on tests

This commit is contained in:
Ryan Heywood 2023-08-16 07:42:13 -05:00
parent 0d768a6eef
commit 7467a30c40
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
4 changed files with 1566 additions and 13 deletions

37
Cargo.lock generated
View File

@ -56,10 +56,24 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]] [[package]]
name = "keyfork-mnemonic-generate" name = "keyfork-mnemonic-generate"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"hex",
"serde_json",
"sha2", "sha2",
] ]
@ -69,6 +83,29 @@ version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "serde"
version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
[[package]]
name = "serde_json"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.10.7" version = "0.10.7"

View File

@ -7,3 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
sha2 = "0.10.7" sha2 = "0.10.7"
[dev-dependencies]
hex = "0.4.3"
serde_json = "1.0.105"

View File

@ -61,6 +61,12 @@ fn ensure_offline() {
} }
} }
fn generate_slice_hash(data: &[u8]) -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().to_vec()
}
fn build_wordlist() -> Vec<String> { fn build_wordlist() -> Vec<String> {
let wordlist_file = include_str!("wordlist.txt"); let wordlist_file = include_str!("wordlist.txt");
wordlist_file wordlist_file
@ -85,17 +91,17 @@ fn u8_to_bitslice(byte: &u8) -> [bool; 8] {
} }
fn bitslice_to_usize(bitslice: [bool; 11]) -> usize { fn bitslice_to_usize(bitslice: [bool; 11]) -> usize {
usize::from(bitslice[0]) usize::from(bitslice[10])
+ (usize::from(bitslice[1]) << 1) + (usize::from(bitslice[9]) << 1)
+ (usize::from(bitslice[2]) << 2) + (usize::from(bitslice[8]) << 2)
+ (usize::from(bitslice[3]) << 3) + (usize::from(bitslice[7]) << 3)
+ (usize::from(bitslice[4]) << 4) + (usize::from(bitslice[6]) << 4)
+ (usize::from(bitslice[5]) << 5) + (usize::from(bitslice[5]) << 5)
+ (usize::from(bitslice[6]) << 6) + (usize::from(bitslice[4]) << 6)
+ (usize::from(bitslice[7]) << 7) + (usize::from(bitslice[3]) << 7)
+ (usize::from(bitslice[8]) << 8) + (usize::from(bitslice[2]) << 8)
+ (usize::from(bitslice[9]) << 9) + (usize::from(bitslice[1]) << 9)
+ (usize::from(bitslice[10]) << 10) + (usize::from(bitslice[0]) << 10)
} }
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
@ -127,9 +133,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let entropy = &mut [0u8; 256 / 8]; let entropy = &mut [0u8; 256 / 8];
random_handle.read_exact(&mut entropy[..])?; random_handle.read_exact(&mut entropy[..])?;
let mut hasher = Sha256::new(); let hash = generate_slice_hash(entropy);
hasher.update(&entropy);
let hash = hasher.finalize();
let checksum = u8_to_bitslice(&hash[1]); let checksum = u8_to_bitslice(&hash[1]);
let mut seed_bits = entropy[..bit_size / 8] let mut seed_bits = entropy[..bit_size / 8]
@ -149,3 +153,49 @@ fn main() -> Result<(), Box<dyn Error>> {
Ok(()) Ok(())
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn has_good_wordlist() {
let wordlist = build_wordlist();
assert_eq!(
wordlist.len(),
2usize.pow(11),
"Wordlist did not include correct word count"
);
}
#[test]
fn loads_mnemonics() -> Result<(), Box<dyn super::Error>> {
let content = include_str!("test/vectors.json");
let jsonobj: serde_json::Value = serde_json::from_str(content)?;
let wordlist = build_wordlist();
for test in jsonobj["english"].as_array().unwrap() {
let [ref hex_, ref seed, ..] = test.as_array().unwrap()[..] else {
panic!("bad test: {test}");
};
let hex = hex::decode(hex_.as_str().unwrap()).unwrap();
let hash = generate_slice_hash(&hex);
let checksum = u8_to_bitslice(&hash.iter().next().unwrap());
let mut seed_bits = hex.iter().flat_map(u8_to_bitslice).collect::<Vec<_>>();
seed_bits.extend(if hex.len() == 256 / 8 {
&checksum[..8]
} else {
&checksum[..4]
});
let words = seed_bits
.chunks_exact(11)
.map(|chunk| {
wordlist[bitslice_to_usize(chunk.try_into().expect("11 bit chunks"))].clone()
})
.collect::<Vec<_>>();
panic!("{}", words.join(" "));
}
Ok(())
}
}

File diff suppressed because it is too large Load Diff