Skip to main content

fips_identity/
address.rs

1//! 128-bit FIPS address with IPv6-compatible format.
2
3use std::fmt;
4use std::net::Ipv6Addr;
5
6use super::{FIPS_ADDRESS_PREFIX, IdentityError, NodeAddr};
7
8/// 128-bit FIPS address with IPv6-compatible format.
9///
10/// The address uses the IPv6 Unique Local Address (ULA) prefix `fd00::/8`,
11/// providing 120 bits for the node_addr hash. This format allows applications
12/// designed for IP transports to bind to FIPS addresses via a TUN interface.
13#[derive(Clone, Copy, PartialEq, Eq, Hash)]
14pub struct FipsAddress([u8; 16]);
15
16impl FipsAddress {
17    /// Create a FipsAddress from a 16-byte array.
18    pub fn from_bytes(bytes: [u8; 16]) -> Result<Self, IdentityError> {
19        if bytes[0] != FIPS_ADDRESS_PREFIX {
20            return Err(IdentityError::InvalidAddressPrefix(bytes[0]));
21        }
22        Ok(Self(bytes))
23    }
24
25    /// Create a FipsAddress from a slice.
26    pub fn from_slice(slice: &[u8]) -> Result<Self, IdentityError> {
27        if slice.len() != 16 {
28            return Err(IdentityError::InvalidAddressLength(slice.len()));
29        }
30        let mut bytes = [0u8; 16];
31        bytes.copy_from_slice(slice);
32        Self::from_bytes(bytes)
33    }
34
35    /// Derive a FipsAddress from a NodeAddr.
36    ///
37    /// Takes the first 15 bytes of the node_addr and prepends the 0xfd prefix.
38    pub fn from_node_addr(node_addr: &NodeAddr) -> Self {
39        let mut bytes = [0u8; 16];
40        bytes[0] = FIPS_ADDRESS_PREFIX;
41        bytes[1..16].copy_from_slice(&node_addr.as_bytes()[0..15]);
42        Self(bytes)
43    }
44
45    /// Return the raw bytes.
46    pub fn as_bytes(&self) -> &[u8; 16] {
47        &self.0
48    }
49
50    /// Convert to std::net::Ipv6Addr.
51    pub fn to_ipv6(&self) -> Ipv6Addr {
52        Ipv6Addr::from(self.0)
53    }
54}
55
56impl From<FipsAddress> for Ipv6Addr {
57    fn from(addr: FipsAddress) -> Self {
58        Ipv6Addr::from(addr.0)
59    }
60}
61
62impl fmt::Debug for FipsAddress {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(f, "FipsAddress({})", self.to_ipv6())
65    }
66}
67
68impl fmt::Display for FipsAddress {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "{}", self.to_ipv6())
71    }
72}