commit e6484a6cfaf93eb79fb47f34097ed1537987cd6a Author: mcneb10 Date: Sat Jul 27 02:47:01 2024 -0500 begin the thing diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e74220e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,58 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + +[[package]] +name = "garnet-key-extractor" +version = "0.1.0" +dependencies = [ + "anyhow", + "bech32", + "num-bigint", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3889a13 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "garnet-key-extractor" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.86" +bech32 = "0.11.0" +num-bigint = "0.4.6" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ee2396b --- /dev/null +++ b/src/main.rs @@ -0,0 +1,49 @@ +use anyhow::{bail, Context, Result}; +use num_bigint::BigInt; +use std::str::FromStr; + +fn derive_hex_seed_from_nostr_key(key: Vec) -> Vec { + let key_num = BigInt::from_bytes_be(num_bigint::Sign::Plus, &key); + let reduction_constant = BigInt::from_str( + "7237005577332262213973186563042994240857116359379907606001950938285454250989", + ) + .unwrap(); + let hex_seed = key_num % reduction_constant; + + let mut hex_seed_bytes = hex_seed.to_bytes_be().1; + hex_seed_bytes.resize(32, 0); // Pad with zeros to ensure the array is 32 bytes + + hex_seed_bytes +} + +fn extract_nostr_key_from_nsec(nsec: String) -> Result> { + let (hrp, data) = bech32::decode(&nsec).with_context(|| "bech32 decode failed")?; + + if hrp.as_str() != "nsec" { + bail!("human readable part is {} when it should be nsec", hrp) + } else if data.len() != 32 { + bail!("private key has length {} when it should be 32", data.len()) + } else { + Ok(data) + } +} + +fn main() { + println!("Please enter a nostr nsec private key below and hit enter:"); + + let mut nsec = String::new(); + std::io::stdin() + .read_line(&mut nsec) + .with_context(|| "Failed to read nostr private key") + .unwrap(); + nsec = nsec.trim_end().to_string(); + + let nostr_key = extract_nostr_key_from_nsec(nsec) + .with_context(|| "Failed to parse nostr private key") + .unwrap(); + let hex_seed = derive_hex_seed_from_nostr_key(nostr_key); + + hex_seed.iter().for_each(|b| print!("{b:02x}")); + + println!(); +}