use bech32::FromBase32;
use secp256k1::{KeyPair, Secp256k1, XOnlyPublicKey};
use vanikey::NostrKeyGenerator;
#[test]
fn test_prefix_to_base32_values() {
let values = NostrKeyGenerator::prefix_to_base32_values("qpzr").unwrap();
assert_eq!(values, vec![0, 1, 2, 3]);
let values = NostrKeyGenerator::prefix_to_base32_values("a").unwrap();
assert_eq!(values, vec![29]);
let values = NostrKeyGenerator::prefix_to_base32_values("test").unwrap();
assert_eq!(values, vec![11, 25, 16, 11]);
}
#[test]
fn test_prefix_to_base32_values_invalid_char() {
let result = NostrKeyGenerator::prefix_to_base32_values("b");
assert!(result.is_err());
let result = NostrKeyGenerator::prefix_to_base32_values("hello!");
assert!(result.is_err());
}
#[test]
fn test_matches_prefix_known_patterns() {
let secp = Secp256k1::new();
let mut rng = rand::thread_rng();
for _ in 0..100 {
let keypair = NostrKeyGenerator::generate_key(&secp, &mut rng);
let (pubkey, _) = keypair.x_only_public_key();
let npub = NostrKeyGenerator::to_npub(&pubkey).unwrap();
let pubkey_bytes = pubkey.serialize();
let data_str = &npub[5..];
for len in 1..=8 {
let prefix = &data_str[..len];
let values = NostrKeyGenerator::prefix_to_base32_values(prefix).unwrap();
assert!(
NostrKeyGenerator::matches_prefix(&pubkey_bytes, &values),
"matches_prefix should match for prefix '{}' of npub '{}'",
prefix,
npub
);
}
let first_char = data_str.as_bytes()[0];
let wrong_char = if first_char == b'q' { b'p' } else { b'q' };
let wrong_prefix = String::from(wrong_char as char);
let wrong_values = NostrKeyGenerator::prefix_to_base32_values(&wrong_prefix).unwrap();
let _ = NostrKeyGenerator::matches_prefix(&pubkey_bytes, &wrong_values);
}
}
#[test]
fn test_matches_prefix_agrees_with_bech32() {
let secp = Secp256k1::new();
let mut rng = rand::thread_rng();
let prefix = "test";
let prefix_values = NostrKeyGenerator::prefix_to_base32_values(prefix).unwrap();
for _ in 0..10_000 {
let keypair = NostrKeyGenerator::generate_key(&secp, &mut rng);
let (pubkey, _) = keypair.x_only_public_key();
let pubkey_bytes = pubkey.serialize();
let npub = NostrKeyGenerator::to_npub(&pubkey).unwrap();
let bech32_match = npub.starts_with(&format!("npub1{}", prefix));
let byte_match = NostrKeyGenerator::matches_prefix(&pubkey_bytes, &prefix_values);
assert_eq!(
bech32_match, byte_match,
"matches_prefix disagrees with bech32 for npub '{}'",
npub
);
}
}
#[test]
fn test_matches_prefix_empty() {
let secp = Secp256k1::new();
let mut rng = rand::thread_rng();
let keypair = NostrKeyGenerator::generate_key(&secp, &mut rng);
let (pubkey, _) = keypair.x_only_public_key();
let pubkey_bytes = pubkey.serialize();
let empty_values = NostrKeyGenerator::prefix_to_base32_values("").unwrap();
assert!(
NostrKeyGenerator::matches_prefix(&pubkey_bytes, &empty_values),
"Empty prefix should match any key"
);
}
#[test]
fn test_generator_creation() {
let generator = NostrKeyGenerator::new(4);
assert_eq!(generator.thread_count(), 4);
}
#[test]
fn test_key_generation() {
let secp = Secp256k1::new();
let mut rng = rand::thread_rng();
let keypair = NostrKeyGenerator::generate_key(&secp, &mut rng);
let (pubkey, _) = XOnlyPublicKey::from_keypair(&keypair);
assert!(!pubkey.serialize().is_empty());
}
#[test]
fn test_npub_conversion() {
let secp = Secp256k1::new();
let mut rng = rand::thread_rng();
let keypair = NostrKeyGenerator::generate_key(&secp, &mut rng);
let (pubkey, _) = XOnlyPublicKey::from_keypair(&keypair);
let npub = NostrKeyGenerator::to_npub(&pubkey).unwrap();
assert!(npub.starts_with("npub1"));
assert_eq!(npub.len(), 63);
}
#[test]
fn test_vanity_generation() {
let generator = NostrKeyGenerator::new(4);
let prefix = "test";
let result = generator.find_vanity_key(prefix, None).unwrap();
assert!(result.npub.starts_with(&format!("npub1{}", prefix)));
}
#[test]
fn test_multiple_threads() {
let generator = NostrKeyGenerator::new(8);
let prefix = "a";
let result = generator.find_vanity_key(prefix, None).unwrap();
assert!(result.npub.starts_with(&format!("npub1{}", prefix)));
}
#[test]
fn test_generated_key_format() {
let generator = NostrKeyGenerator::new(1);
let result = generator.find_vanity_key("a", None).unwrap();
let (_, nsec_data, _) = bech32::decode(&result.nsec).unwrap();
let secret_bytes = Vec::<u8>::from_base32(&nsec_data).unwrap();
let secret_key = secp256k1::SecretKey::from_slice(&secret_bytes).unwrap();
let secp = Secp256k1::new();
let keypair = KeyPair::from_secret_key(&secp, &secret_key);
let (derived_pubkey, _) = keypair.x_only_public_key();
let derived_npub = NostrKeyGenerator::to_npub(&derived_pubkey).unwrap();
assert_eq!(result.npub, derived_npub);
}
#[test]
fn test_with_additional_prefixes() {
let generator = NostrKeyGenerator::new(4);
let primary_prefix = "test";
let additional_prefixes = vec!["ace".to_string(), "key".to_string()];
let result = generator
.find_vanity_key(primary_prefix, Some(&additional_prefixes))
.unwrap();
assert!(result.npub.starts_with(&format!("npub1{}", primary_prefix)));
}
#[test]
fn test_nsec_roundtrip() {
let secp = Secp256k1::new();
let mut rng = rand::thread_rng();
let keypair = NostrKeyGenerator::generate_key(&secp, &mut rng);
let nsec = NostrKeyGenerator::to_nsec(&keypair).unwrap();
assert!(nsec.starts_with("nsec1"));
let (_, nsec_data, _) = bech32::decode(&nsec).unwrap();
let secret_bytes = Vec::<u8>::from_base32(&nsec_data).unwrap();
let secret_key = secp256k1::SecretKey::from_slice(&secret_bytes).unwrap();
let recovered = KeyPair::from_secret_key(&secp, &secret_key);
let (original_pub, _) = keypair.x_only_public_key();
let (recovered_pub, _) = recovered.x_only_public_key();
assert_eq!(original_pub, recovered_pub);
}