notedeck

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

pubkey.rs (3253B)


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