use secp256k1::{Parity, PublicKey, Secp256k1, XOnlyPublicKey};
use std::fmt;
use super::encoding::{decode_npub, encode_npub};
use super::{FipsAddress, IdentityError, NodeAddr, sha256};
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct PeerIdentity {
pubkey: XOnlyPublicKey,
pubkey_full: Option<PublicKey>,
node_addr: NodeAddr,
address: FipsAddress,
}
impl PeerIdentity {
pub fn from_pubkey(pubkey: XOnlyPublicKey) -> Self {
let node_addr = NodeAddr::from_pubkey(&pubkey);
let address = FipsAddress::from_node_addr(&node_addr);
let pubkey_full = pubkey.public_key(Parity::Even);
Self {
pubkey,
pubkey_full: Some(pubkey_full),
node_addr,
address,
}
}
pub fn from_pubkey_full(pubkey: PublicKey) -> Self {
let (x_only, _parity) = pubkey.x_only_public_key();
let node_addr = NodeAddr::from_pubkey(&x_only);
let address = FipsAddress::from_node_addr(&node_addr);
Self {
pubkey: x_only,
pubkey_full: Some(pubkey),
node_addr,
address,
}
}
pub fn from_npub(npub: &str) -> Result<Self, IdentityError> {
let pubkey = decode_npub(npub)?;
Ok(Self::from_pubkey(pubkey))
}
pub fn pubkey(&self) -> XOnlyPublicKey {
self.pubkey
}
pub fn pubkey_full(&self) -> PublicKey {
self.pubkey_full.unwrap_or_else(|| {
self.pubkey.public_key(Parity::Even)
})
}
pub fn npub(&self) -> String {
encode_npub(&self.pubkey)
}
pub fn short_npub(&self) -> String {
let full = self.npub();
let data = &full[5..]; format!("npub1{}...{}", &data[..4], &data[data.len() - 4..])
}
pub fn node_addr(&self) -> &NodeAddr {
&self.node_addr
}
pub fn address(&self) -> &FipsAddress {
&self.address
}
pub fn verify(&self, data: &[u8], signature: &secp256k1::schnorr::Signature) -> bool {
let secp = Secp256k1::new();
let digest = sha256(data);
secp.verify_schnorr(signature, &digest, &self.pubkey)
.is_ok()
}
}
impl fmt::Debug for PeerIdentity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PeerIdentity")
.field("node_addr", &self.node_addr)
.field("address", &self.address)
.finish()
}
}
impl fmt::Display for PeerIdentity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.npub())
}
}