keechain_core/command/
vanity.rs1use std::time::Instant;
5
6use bitcoin::secp256k1::Secp256k1;
7use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
8use bitcoin::{Address, Network, PublicKey};
9
10use crate::error::{Error, Result};
11use crate::types::{Seed, MAX_INDEX};
12use crate::util::bip::bip32::{self, Bip32RootKey};
13
14const BECH32_CHARS: &str = "023456789acdefghjklmnpqrstuvwxyz";
15
16pub fn search_address(
17 seed: Seed,
18 prefixes: impl Into<Vec<String>>,
19 network: Network,
20) -> Result<(DerivationPath, Address)> {
21 let now = Instant::now();
22 let secp = Secp256k1::new();
23 let root = seed.to_bip32_root_key(network)?;
24 let prefixes = prefixes.into();
25
26 for prefix in prefixes.iter() {
27 for c in prefix.chars() {
28 if !BECH32_CHARS.contains(c) {
29 return Err(Error::Generic(format!("Unsupported char: {}", c)));
30 }
31 }
32 }
33
34 for account in 0..MAX_INDEX {
35 let path = bip32::account_extended_path(84, network, Some(account))?;
36 let derived_private_key: ExtendedPrivKey = root.derive_priv(&secp, &path)?;
37 let derived_public_key: ExtendedPubKey =
38 ExtendedPubKey::from_priv(&secp, &derived_private_key);
39
40 for index in 0..MAX_INDEX {
41 let derived_public_key: ExtendedPubKey =
42 derived_public_key.ckd_pub(&secp, ChildNumber::from_normal_idx(index)?)?;
43
44 for change in 0..=1 {
45 let derived_public_key: ExtendedPubKey =
46 derived_public_key.ckd_pub(&secp, ChildNumber::from_normal_idx(change)?)?;
47 let pubkey = PublicKey::new(derived_public_key.public_key);
48 let address = Address::p2wpkh(&pubkey, network).unwrap();
49 let addr_str = address.to_string();
50 if prefixes.iter().any(|prefix| addr_str.contains(prefix)) {
51 println!("{} ms", now.elapsed().as_millis());
52 let path =
53 bip32::get_path(84, network, Some(account), Some(index), change == 1)?;
54 return Ok((path, address));
55 }
56 }
57 }
58 }
59
60 Err(Error::Generic(
61 "Failed to derive xpub at found path".to_string(),
62 ))
63}