Skip to main content

shadow_core/
peer.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::hash::{Hash, Hasher};
4
5/// Unique identifier for a peer in the network
6#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
7pub struct PeerId([u8; 32]);
8
9impl PeerId {
10    /// Create a new random PeerId
11    pub fn random() -> Self {
12        use bytes::Bytes;
13        let mut id = [0u8; 32];
14        // In production, use a cryptographically secure RNG
15        for byte in &mut id {
16            *byte = rand::random();
17        }
18        Self(id)
19    }
20
21    /// Create PeerId from bytes
22    pub fn from_bytes(bytes: [u8; 32]) -> Self {
23        Self(bytes)
24    }
25
26    /// Get the underlying bytes
27    pub fn as_bytes(&self) -> &[u8; 32] {
28        &self.0
29    }
30
31    /// Calculate XOR distance to another PeerId (for Kademlia)
32    pub fn xor_distance(&self, other: &PeerId) -> [u8; 32] {
33        let mut result = [0u8; 32];
34        for i in 0..32 {
35            result[i] = self.0[i] ^ other.0[i];
36        }
37        result
38    }
39
40    /// Count leading zeros in the XOR distance (for Kademlia bucket calculation)
41    pub fn leading_zeros_to(&self, other: &PeerId) -> usize {
42        let distance = self.xor_distance(other);
43        let mut zeros = 0;
44        for byte in distance.iter() {
45            if *byte == 0 {
46                zeros += 8;
47            } else {
48                zeros += byte.leading_zeros() as usize;
49                break;
50            }
51        }
52        zeros
53    }
54}
55
56impl Hash for PeerId {
57    fn hash<H: Hasher>(&self, state: &mut H) {
58        self.0.hash(state);
59    }
60}
61
62impl fmt::Debug for PeerId {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(f, "PeerId({}...)", hex::encode(&self.0[..4]))
65    }
66}
67
68impl fmt::Display for PeerId {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "{}", hex::encode(&self.0))
71    }
72}
73
74/// Information about a peer in the network
75#[derive(Clone, Debug, Serialize, Deserialize)]
76pub struct PeerInfo {
77    /// Unique identifier for this peer
78    pub id: PeerId,
79    
80    /// Network addresses where this peer can be reached
81    pub addresses: Vec<String>,
82    
83    /// Public key for encryption (X25519)
84    pub public_key: [u8; 32],
85    
86    /// Signature verification key (Ed25519)
87    pub verify_key: [u8; 32],
88    
89    /// Last seen timestamp (Unix epoch)
90    pub last_seen: u64,
91    
92    /// Reputation score (for Sybil resistance)
93    pub reputation: f64,
94    
95    /// Geographic location hint (for routing optimization)
96    pub location: Option<GeoLocation>,
97    
98    /// Supported cover protocols
99    pub supported_protocols: Vec<String>,
100}
101
102impl PeerInfo {
103    /// Create new peer info
104    pub fn new(
105        id: PeerId,
106        addresses: Vec<String>,
107        public_key: [u8; 32],
108        verify_key: [u8; 32],
109    ) -> Self {
110        Self {
111            id,
112            addresses,
113            public_key,
114            verify_key,
115            last_seen: current_timestamp(),
116            reputation: 0.5, // Neutral starting reputation
117            location: None,
118            supported_protocols: vec![],
119        }
120    }
121
122    /// Update last seen timestamp
123    pub fn touch(&mut self) {
124        self.last_seen = current_timestamp();
125    }
126
127    /// Check if peer info is stale
128    pub fn is_stale(&self, max_age_secs: u64) -> bool {
129        let now = current_timestamp();
130        now - self.last_seen > max_age_secs
131    }
132}
133
134/// Geographic location for routing optimization
135#[derive(Clone, Debug, Serialize, Deserialize)]
136pub struct GeoLocation {
137    pub latitude: f64,
138    pub longitude: f64,
139    pub city: Option<String>,
140    pub country: Option<String>,
141}
142
143impl GeoLocation {
144    /// Calculate approximate distance to another location (in kilometers)
145    pub fn distance_to(&self, other: &GeoLocation) -> f64 {
146        // Haversine formula
147        const EARTH_RADIUS_KM: f64 = 6371.0;
148        
149        let lat1 = self.latitude.to_radians();
150        let lat2 = other.latitude.to_radians();
151        let delta_lat = (other.latitude - self.latitude).to_radians();
152        let delta_lon = (other.longitude - self.longitude).to_radians();
153        
154        let a = (delta_lat / 2.0).sin().powi(2)
155            + lat1.cos() * lat2.cos() * (delta_lon / 2.0).sin().powi(2);
156        let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
157        
158        EARTH_RADIUS_KM * c
159    }
160}
161
162/// Get current Unix timestamp
163fn current_timestamp() -> u64 {
164    use std::time::{SystemTime, UNIX_EPOCH};
165    SystemTime::now()
166        .duration_since(UNIX_EPOCH)
167        .unwrap()
168        .as_secs()
169}
170
171// We need the hex crate for display
172mod hex {
173    pub fn encode(data: &[u8]) -> String {
174        data.iter().map(|b| format!("{:02x}", b)).collect()
175    }
176}
177
178// Mock rand for now
179mod rand {
180    pub fn random<T>() -> T
181    where
182        Standard: Distribution<T>,
183    {
184        Standard.sample(&mut thread_rng())
185    }
186    
187    use std::sync::Mutex;
188    use std::collections::hash_map::RandomState;
189    use std::hash::{BuildHasher, Hash, Hasher};
190    
191    static RNG_STATE: Mutex<u64> = Mutex::new(12345);
192    
193    fn thread_rng() -> impl Iterator<Item = u8> {
194        std::iter::repeat_with(|| {
195            let mut state = RNG_STATE.lock().unwrap();
196            *state = state.wrapping_mul(6364136223846793005).wrapping_add(1);
197            (*state >> 32) as u8
198        })
199    }
200    
201    pub struct Standard;
202    
203    pub trait Distribution<T> {
204        fn sample<R>(&self, rng: &mut R) -> T
205        where
206            R: Iterator<Item = u8>;
207    }
208    
209    impl Distribution<u8> for Standard {
210        fn sample<R>(&self, rng: &mut R) -> u8
211        where
212            R: Iterator<Item = u8>,
213        {
214            rng.next().unwrap()
215        }
216    }
217}