notedeck

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

pubkey.rs (3241B)


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