use std::fmt;
use sha2::{Digest, Sha256};
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct PeerId([u8; 32]);
impl PeerId {
pub const fn from_bytes(bytes: [u8; 32]) -> Self {
PeerId(bytes)
}
pub const fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub fn to_hex(&self) -> String {
let mut s = String::with_capacity(64);
for b in self.0 {
s.push(char::from_digit((b >> 4) as u32, 16).unwrap());
s.push(char::from_digit((b & 0x0f) as u32, 16).unwrap());
}
s
}
pub fn from_hex(hex: &str) -> Option<Self> {
if hex.len() != 64 {
return None;
}
let mut out = [0u8; 32];
let bytes = hex.as_bytes();
for (i, chunk) in bytes.chunks(2).enumerate() {
let hi = (chunk[0] as char).to_digit(16)?;
let lo = (chunk[1] as char).to_digit(16)?;
out[i] = ((hi << 4) | lo) as u8;
}
Some(PeerId(out))
}
}
impl fmt::Debug for PeerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PeerId({})", self.to_hex())
}
}
impl fmt::Display for PeerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_hex())
}
}
pub fn peer_id_from_tls_spki_der(spki_der: &[u8]) -> PeerId {
let digest = Sha256::digest(spki_der);
let bytes: [u8; 32] = digest.into();
PeerId(bytes)
}
pub fn peer_id_from_leaf_cert_der(cert_der: &[u8]) -> Option<PeerId> {
let (_, x509) = x509_parser::parse_x509_certificate(cert_der).ok()?;
let spki_der = x509.tbs_certificate.subject_pki.raw;
Some(peer_id_from_tls_spki_der(spki_der))
}