notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

pubkey.rs (2853B)


      1 use serde::{Deserialize, Deserializer, Serialize, Serializer};
      2 
      3 use crate::Error;
      4 use nostr::bech32::Hrp;
      5 use std::fmt;
      6 use tracing::debug;
      7 
      8 #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
      9 pub struct Pubkey([u8; 32]);
     10 
     11 static HRP_NPUB: Hrp = Hrp::parse_unchecked("npub");
     12 
     13 impl Pubkey {
     14     pub fn new(data: [u8; 32]) -> Self {
     15         Self(data)
     16     }
     17 
     18     pub fn hex(&self) -> String {
     19         hex::encode(self.bytes())
     20     }
     21 
     22     pub fn bytes(&self) -> &[u8; 32] {
     23         &self.0
     24     }
     25 
     26     pub fn parse(s: &str) -> Result<Self, Error> {
     27         match Pubkey::from_hex(s) {
     28             Ok(pk) => Ok(pk),
     29             Err(_) => Pubkey::try_from_bech32_string(s, false),
     30         }
     31     }
     32 
     33     pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
     34         Ok(Pubkey(hex::decode(hex_str)?.as_slice().try_into()?))
     35     }
     36 
     37     pub fn try_from_hex_str_with_verify(hex_str: &str) -> Result<Self, Error> {
     38         let vec: Vec<u8> = hex::decode(hex_str)?;
     39         if vec.len() != 32 {
     40             Err(Error::HexDecodeFailed)
     41         } else {
     42             let _ = match nostr::secp256k1::XOnlyPublicKey::from_slice(&vec) {
     43                 Ok(r) => Ok(r),
     44                 Err(_) => Err(Error::InvalidPublicKey),
     45             }?;
     46 
     47             Ok(Pubkey(vec.try_into().unwrap()))
     48         }
     49     }
     50 
     51     pub fn try_from_bech32_string(s: &str, verify: bool) -> Result<Self, Error> {
     52         let data = match nostr::bech32::decode(s) {
     53             Ok(res) => Ok(res),
     54             Err(_) => Err(Error::InvalidBech32),
     55         }?;
     56 
     57         if data.0 != HRP_NPUB {
     58             Err(Error::InvalidBech32)
     59         } else if data.1.len() != 32 {
     60             Err(Error::InvalidByteSize)
     61         } else {
     62             if verify {
     63                 let _ = match nostr::secp256k1::XOnlyPublicKey::from_slice(&data.1) {
     64                     Ok(r) => Ok(r),
     65                     Err(_) => Err(Error::InvalidPublicKey),
     66                 }?;
     67             }
     68             Ok(Pubkey(data.1.try_into().unwrap()))
     69         }
     70     }
     71 }
     72 
     73 impl fmt::Display for Pubkey {
     74     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     75         write!(f, "{}", self.hex())
     76     }
     77 }
     78 
     79 impl From<Pubkey> for String {
     80     fn from(pk: Pubkey) -> Self {
     81         pk.hex()
     82     }
     83 }
     84 
     85 // Custom serialize function for Pubkey
     86 impl Serialize for Pubkey {
     87     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     88     where
     89         S: Serializer,
     90     {
     91         serializer.serialize_str(&self.hex())
     92     }
     93 }
     94 
     95 // Custom deserialize function for Pubkey
     96 impl<'de> Deserialize<'de> for Pubkey {
     97     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     98     where
     99         D: Deserializer<'de>,
    100     {
    101         debug!("decoding pubkey start");
    102         let s = String::deserialize(deserializer)?;
    103         debug!("decoding pubkey {}", &s);
    104         Pubkey::from_hex(&s).map_err(serde::de::Error::custom)
    105     }
    106 }