Skip to main content

fips_identity/
node_addr.rs

1//! 16-byte node identifier derived from truncated SHA-256(pubkey).
2
3use secp256k1::XOnlyPublicKey;
4use sha2::{Digest, Sha256};
5use std::fmt;
6
7use super::{IdentityError, hex_encode};
8
9/// 16-byte node identifier derived from truncated SHA-256(pubkey).
10///
11/// The node_addr is the first 16 bytes of SHA-256(pubkey), providing 128 bits
12/// of collision resistance. Hashing the public key prevents grinding attacks
13/// that exploit secp256k1's algebraic structure.
14#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct NodeAddr([u8; 16]);
16
17impl NodeAddr {
18    /// Create a NodeAddr from a 16-byte array.
19    pub fn from_bytes(bytes: [u8; 16]) -> Self {
20        Self(bytes)
21    }
22
23    /// Create a NodeAddr from a slice.
24    pub fn from_slice(slice: &[u8]) -> Result<Self, IdentityError> {
25        if slice.len() != 16 {
26            return Err(IdentityError::InvalidNodeAddrLength(slice.len()));
27        }
28        let mut bytes = [0u8; 16];
29        bytes.copy_from_slice(slice);
30        Ok(Self(bytes))
31    }
32
33    /// Derive a NodeAddr from an x-only public key (npub).
34    ///
35    /// Computes SHA-256(pubkey) and takes the first 16 bytes.
36    pub fn from_pubkey(pubkey: &XOnlyPublicKey) -> Self {
37        let mut hasher = Sha256::new();
38        hasher.update(pubkey.serialize());
39        let hash = hasher.finalize();
40        let mut bytes = [0u8; 16];
41        bytes.copy_from_slice(&hash[..16]);
42        Self(bytes)
43    }
44
45    /// Return the raw bytes.
46    pub fn as_bytes(&self) -> &[u8; 16] {
47        &self.0
48    }
49
50    /// Return the bytes as a slice.
51    pub fn as_slice(&self) -> &[u8] {
52        &self.0
53    }
54
55    /// Return a short hex representation: first 4 bytes + "...".
56    pub fn short_hex(&self) -> String {
57        format!("{}...", hex_encode(&self.0[..4]))
58    }
59}
60
61impl fmt::Debug for NodeAddr {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        write!(f, "NodeAddr({})", hex_encode(&self.0[..8]))
64    }
65}
66
67impl fmt::Display for NodeAddr {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(f, "{}", hex_encode(&self.0))
70    }
71}
72
73impl AsRef<[u8]> for NodeAddr {
74    fn as_ref(&self) -> &[u8] {
75        &self.0
76    }
77}