use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::Error; use log::debug; use nostr::bech32::Hrp; use std::fmt; #[derive(Debug, Eq, PartialEq, Clone, Hash)] pub struct Pubkey([u8; 32]); static HRP_NPUB: Hrp = Hrp::parse_unchecked("npub"); impl Pubkey { pub fn new(data: &[u8; 32]) -> Self { Self(*data) } pub fn hex(&self) -> String { hex::encode(self.bytes()) } pub fn bytes(&self) -> &[u8; 32] { &self.0 } pub fn from_hex(hex_str: &str) -> Result { Ok(Pubkey(hex::decode(hex_str)?.as_slice().try_into()?)) } pub fn try_from_hex_str_with_verify(hex_str: &str) -> Result { let vec: Vec = hex::decode(hex_str)?; if vec.len() != 32 { Err(Error::HexDecodeFailed) } else { let _ = match nostr::secp256k1::XOnlyPublicKey::from_slice(&vec) { Ok(r) => Ok(r), Err(_) => Err(Error::InvalidPublicKey), }?; Ok(Pubkey(vec.try_into().unwrap())) } } pub fn try_from_bech32_string(s: &str, verify: bool) -> Result { let data = match nostr::bech32::decode(s) { Ok(res) => Ok(res), Err(_) => Err(Error::InvalidBech32), }?; if data.0 != HRP_NPUB { Err(Error::InvalidBech32) } else if data.1.len() != 32 { Err(Error::InvalidByteSize) } else { if verify { let _ = match nostr::secp256k1::XOnlyPublicKey::from_slice(&data.1) { Ok(r) => Ok(r), Err(_) => Err(Error::InvalidPublicKey), }?; } Ok(Pubkey(data.1.try_into().unwrap())) } } } impl fmt::Display for Pubkey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.hex()) } } impl From for String { fn from(pk: Pubkey) -> Self { pk.hex() } } // Custom serialize function for Pubkey impl Serialize for Pubkey { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(&self.hex()) } } // Custom deserialize function for Pubkey impl<'de> Deserialize<'de> for Pubkey { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { debug!("decoding pubkey start"); let s = String::deserialize(deserializer)?; debug!("decoding pubkey {}", &s); Pubkey::from_hex(&s).map_err(serde::de::Error::custom) } }