notedeck

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

keypair.rs (8149B)


      1 use nostr::nips::nip19::FromBech32;
      2 use nostr::nips::nip19::ToBech32;
      3 use nostr::nips::nip49::EncryptedSecretKey;
      4 use serde::Deserialize;
      5 use serde::Serialize;
      6 use tokenator::ParseError;
      7 use tokenator::TokenParser;
      8 use tokenator::TokenSerializable;
      9 
     10 use crate::Pubkey;
     11 use crate::SecretKey;
     12 
     13 #[derive(Debug, Eq, PartialEq, Clone)]
     14 pub struct Keypair {
     15     pub pubkey: Pubkey,
     16     pub secret_key: Option<SecretKey>,
     17 }
     18 
     19 pub struct KeypairUnowned<'a> {
     20     pub pubkey: &'a Pubkey,
     21     pub secret_key: Option<&'a SecretKey>,
     22 }
     23 
     24 impl<'a> From<&'a Keypair> for KeypairUnowned<'a> {
     25     fn from(value: &'a Keypair) -> Self {
     26         Self {
     27             pubkey: &value.pubkey,
     28             secret_key: value.secret_key.as_ref(),
     29         }
     30     }
     31 }
     32 
     33 impl Keypair {
     34     pub fn from_secret(secret_key: SecretKey) -> Self {
     35         let cloned_secret_key = secret_key.clone();
     36         let nostr_keys = nostr::Keys::new(secret_key);
     37         Keypair {
     38             pubkey: Pubkey::new(nostr_keys.public_key().to_bytes()),
     39             secret_key: Some(cloned_secret_key),
     40         }
     41     }
     42 
     43     pub fn new(pubkey: Pubkey, secret_key: Option<SecretKey>) -> Self {
     44         Keypair { pubkey, secret_key }
     45     }
     46 
     47     pub fn only_pubkey(pubkey: Pubkey) -> Self {
     48         Keypair {
     49             pubkey,
     50             secret_key: None,
     51         }
     52     }
     53 
     54     pub fn to_full(&self) -> Option<FilledKeypair<'_>> {
     55         self.secret_key.as_ref().map(|secret_key| FilledKeypair {
     56             pubkey: &self.pubkey,
     57             secret_key,
     58         })
     59     }
     60 }
     61 
     62 #[derive(Debug, Eq, PartialEq, Clone)]
     63 pub struct FullKeypair {
     64     pub pubkey: Pubkey,
     65     pub secret_key: SecretKey,
     66 }
     67 
     68 #[derive(Debug, Eq, PartialEq, Clone, Copy)]
     69 pub struct FilledKeypair<'a> {
     70     pub pubkey: &'a Pubkey,
     71     pub secret_key: &'a SecretKey,
     72 }
     73 
     74 impl<'a> FilledKeypair<'a> {
     75     pub fn new(pubkey: &'a Pubkey, secret_key: &'a SecretKey) -> Self {
     76         FilledKeypair { pubkey, secret_key }
     77     }
     78 
     79     pub fn to_full(&self) -> FullKeypair {
     80         FullKeypair {
     81             pubkey: self.pubkey.to_owned(),
     82             secret_key: self.secret_key.to_owned(),
     83         }
     84     }
     85 }
     86 
     87 impl<'a> From<&'a FilledKeypair<'a>> for KeypairUnowned<'a> {
     88     fn from(value: &'a FilledKeypair<'a>) -> Self {
     89         Self {
     90             pubkey: value.pubkey,
     91             secret_key: Some(value.secret_key),
     92         }
     93     }
     94 }
     95 
     96 impl FullKeypair {
     97     pub fn new(pubkey: Pubkey, secret_key: SecretKey) -> Self {
     98         FullKeypair { pubkey, secret_key }
     99     }
    100 
    101     pub fn to_filled(&self) -> FilledKeypair<'_> {
    102         FilledKeypair::new(&self.pubkey, &self.secret_key)
    103     }
    104 
    105     pub fn generate() -> Self {
    106         let mut rng = nostr::secp256k1::rand::rngs::OsRng;
    107         let (secret_key, _) = &nostr::SECP256K1.generate_keypair(&mut rng);
    108         let (xopk, _) = secret_key.x_only_public_key(&nostr::SECP256K1);
    109         let secret_key = nostr::SecretKey::from(*secret_key);
    110         FullKeypair {
    111             pubkey: Pubkey::new(xopk.serialize()),
    112             secret_key,
    113         }
    114     }
    115 
    116     pub fn to_keypair(self) -> Keypair {
    117         Keypair {
    118             pubkey: self.pubkey,
    119             secret_key: Some(self.secret_key),
    120         }
    121     }
    122 }
    123 
    124 impl std::fmt::Display for Keypair {
    125     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    126         write!(
    127             f,
    128             "Keypair:\n\tpublic: {}\n\tsecret: {}",
    129             self.pubkey,
    130             match self.secret_key {
    131                 Some(_) => "Some(<hidden>)",
    132                 None => "None",
    133             }
    134         )
    135     }
    136 }
    137 
    138 impl std::fmt::Display for FullKeypair {
    139     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    140         write!(f, "Keypair:\n\tpublic: {}\n\tsecret: <hidden>", self.pubkey)
    141     }
    142 }
    143 
    144 #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
    145 pub struct SerializableKeypair {
    146     pub pubkey: Pubkey,
    147     pub encrypted_secret_key: Option<EncryptedSecretKey>,
    148 }
    149 
    150 impl SerializableKeypair {
    151     pub fn from_keypair(kp: &Keypair, pass: &str, log_n: u8) -> Self {
    152         Self {
    153             pubkey: kp.pubkey,
    154             encrypted_secret_key: kp.secret_key.clone().and_then(|s| {
    155                 EncryptedSecretKey::new(&s, pass, log_n, nostr::nips::nip49::KeySecurity::Weak).ok()
    156             }),
    157         }
    158     }
    159 
    160     pub fn to_keypair(&self, pass: &str) -> Keypair {
    161         Keypair::new(
    162             self.pubkey,
    163             self.encrypted_secret_key
    164                 .and_then(|e| e.to_secret_key(pass).ok()),
    165         )
    166     }
    167 }
    168 
    169 impl TokenSerializable for Pubkey {
    170     fn parse_from_tokens<'a>(parser: &mut TokenParser<'a>) -> Result<Self, ParseError<'a>> {
    171         parser.parse_token(PUBKEY_TOKEN)?;
    172         let raw = parser.pull_token()?;
    173         let pubkey =
    174             Pubkey::try_from_bech32_string(raw, true).map_err(|_| ParseError::DecodeFailed)?;
    175         Ok(pubkey)
    176     }
    177 
    178     fn serialize_tokens(&self, writer: &mut tokenator::TokenWriter) {
    179         writer.write_token(PUBKEY_TOKEN);
    180 
    181         let Some(bech) = self.npub() else {
    182             tracing::error!("Could not convert pubkey to bech: {}", self.hex());
    183             return;
    184         };
    185 
    186         writer.write_token(&bech);
    187     }
    188 }
    189 
    190 impl TokenSerializable for Keypair {
    191     fn parse_from_tokens<'a>(parser: &mut TokenParser<'a>) -> Result<Self, ParseError<'a>> {
    192         TokenParser::alt(
    193             parser,
    194             &[
    195                 |p| Ok(Keypair::only_pubkey(Pubkey::parse_from_tokens(p)?)),
    196                 |p| Ok(Keypair::from_secret(parse_seckey(p)?)),
    197             ],
    198         )
    199     }
    200 
    201     fn serialize_tokens(&self, writer: &mut tokenator::TokenWriter) {
    202         if let Some(seckey) = &self.secret_key {
    203             writer.write_token(ESECKEY_TOKEN);
    204             let maybe_eseckey = EncryptedSecretKey::new(
    205                 seckey,
    206                 ESECKEY_PASS,
    207                 7,
    208                 nostr::nips::nip49::KeySecurity::Unknown,
    209             );
    210 
    211             let Ok(eseckey) = maybe_eseckey else {
    212                 tracing::error!("Could not convert seckey to EncryptedSecretKey");
    213                 return;
    214             };
    215             let Ok(serialized) = eseckey.to_bech32() else {
    216                 tracing::error!("Could not serialize ncryptsec");
    217                 return;
    218             };
    219 
    220             writer.write_token(&serialized);
    221         } else {
    222             self.pubkey.serialize_tokens(writer);
    223         }
    224     }
    225 }
    226 
    227 const ESECKEY_TOKEN: &str = "eseckey";
    228 const ESECKEY_PASS: &str = "notedeck";
    229 const PUBKEY_TOKEN: &str = "pubkey";
    230 
    231 fn parse_seckey<'a>(parser: &mut TokenParser<'a>) -> Result<SecretKey, ParseError<'a>> {
    232     parser.parse_token(ESECKEY_TOKEN)?;
    233 
    234     let raw = parser.pull_token()?;
    235 
    236     let eseckey = EncryptedSecretKey::from_bech32(raw).map_err(|_| ParseError::DecodeFailed)?;
    237 
    238     let seckey = eseckey
    239         .to_secret_key(ESECKEY_PASS)
    240         .map_err(|_| ParseError::DecodeFailed)?;
    241 
    242     Ok(seckey)
    243 }
    244 
    245 #[cfg(test)]
    246 mod tests {
    247 
    248     use tokenator::{TokenParser, TokenSerializable, TokenWriter};
    249 
    250     use super::{FullKeypair, Keypair};
    251 
    252     #[test]
    253     fn test_token_eseckey_serialize_deserialize() {
    254         let kp = FullKeypair::generate();
    255 
    256         let mut writer = TokenWriter::new("\t");
    257         kp.clone().to_keypair().serialize_tokens(&mut writer);
    258 
    259         let serialized = writer.str();
    260 
    261         let data = &serialized.split("\t").collect::<Vec<&str>>();
    262 
    263         let mut parser = TokenParser::new(data);
    264         let m_new_kp = Keypair::parse_from_tokens(&mut parser);
    265         assert!(m_new_kp.is_ok());
    266 
    267         let new_kp = m_new_kp.unwrap();
    268 
    269         assert_eq!(kp, new_kp.to_full().unwrap().to_full());
    270     }
    271 
    272     #[test]
    273     fn test_token_pubkey_serialize_deserialize() {
    274         let kp = Keypair::only_pubkey(FullKeypair::generate().pubkey);
    275 
    276         let mut writer = TokenWriter::new("\t");
    277         kp.clone().serialize_tokens(&mut writer);
    278 
    279         let serialized = writer.str();
    280 
    281         let data = &serialized.split("\t").collect::<Vec<&str>>();
    282 
    283         let mut parser = TokenParser::new(data);
    284         let m_new_kp = Keypair::parse_from_tokens(&mut parser);
    285         assert!(m_new_kp.is_ok());
    286 
    287         let new_kp = m_new_kp.unwrap();
    288 
    289         assert_eq!(kp, new_kp);
    290     }
    291 }