diff --git a/Cargo.lock b/Cargo.lock index 3a21c24..356a5c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,6 +280,12 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bitcoin_hashes" version = "0.10.0" @@ -1531,6 +1537,7 @@ dependencies = [ "anyhow", "async-std", "async-trait", + "bech32", "bitcoin_hashes", "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index b67aa2e..35ef257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ sqlx = { version ="0.6.2", features=["runtime-tokio-rustls", "postgres", "chrono chrono = "0.4.23" prometheus = "0.13.3" indicatif = "0.17.3" +bech32 = "0.9.1" [dev-dependencies] anyhow = "1" diff --git a/src/hexrange.rs b/src/hexrange.rs index b0566ff..3020faa 100644 --- a/src/hexrange.rs +++ b/src/hexrange.rs @@ -1,5 +1,5 @@ //! Utilities for searching hexadecimal -use crate::utils::is_hex; +use crate::utils::{is_hex}; use hex; /// Types of hexadecimal queries. @@ -20,15 +20,14 @@ fn is_all_fs(s: &str) -> bool { /// Find the next hex sequence greater than the argument. #[must_use] pub fn hex_range(s: &str) -> Option { - // handle special cases - if !is_hex(s) || s.len() > 64 { + let mut hash_base = s.to_owned(); + if !is_hex(&hash_base) || hash_base.len() > 64 { return None; } - if s.len() == 64 { - return Some(HexSearch::Exact(hex::decode(s).ok()?)); + if hash_base.len() == 64 { + return Some(HexSearch::Exact(hex::decode(&hash_base).ok()?)); } // if s is odd, add a zero - let mut hash_base = s.to_owned(); let mut odd = hash_base.len() % 2 != 0; if odd { // extend the string to make it even diff --git a/src/utils.rs b/src/utils.rs index 6eff34d..92ca8d0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,5 @@ //! Common utility functions +use bech32::FromBase32; use std::time::SystemTime; /// Seconds since 1970. @@ -14,6 +15,17 @@ use std::time::SystemTime; s.chars().all(|x| char::is_ascii_hexdigit(&x)) } +/// Check if string is a nip19 string +pub fn is_nip19(s: &str) -> bool { + s.starts_with("npub") || s.starts_with("note") +} + +pub fn nip19_to_hex(s: &str) -> Result { + let (_hrp, data, _checksum) = bech32::decode(s)?; + let data = Vec::::from_base32(&data)?; + Ok(hex::encode(data)) +} + /// Check if a string contains only lower-case hex chars. #[must_use] pub fn is_lower_hex(s: &str) -> bool { s.chars().all(|x| { @@ -30,4 +42,21 @@ mod tests { let hexstr = "abcd0123"; assert_eq!(is_lower_hex(hexstr), true); } + + #[test] + fn nip19() { + let hexkey = "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"; + let nip19key = "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6"; + assert_eq!(is_nip19(hexkey), false); + assert_eq!(is_nip19(nip19key), true); + } + + #[test] + fn nip19_hex() { + let nip19key = "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6"; + let expected = "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"; + let got = nip19_to_hex(nip19key).unwrap(); + + assert_eq!(expected, got); + } }