1use crate::PeerId;
21use crate::quantum_crypto::ant_quic_integration::{
22 MlDsaPublicKey, MlDsaSecretKey, MlDsaSignature, ml_dsa_sign, ml_dsa_verify,
23};
24use anyhow::{Result, anyhow};
25use serde::{Deserialize, Serialize};
26use sha2::{Digest, Sha256};
27use std::collections::HashMap;
28use std::net::Ipv6Addr;
29use std::time::{Duration, SystemTime, UNIX_EPOCH};
30
31use std::sync::Arc;
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct IPv6NodeID {
36 pub node_id: Vec<u8>,
38 pub ipv6_addr: Ipv6Addr,
40 pub public_key: Vec<u8>,
42 pub signature: Vec<u8>,
44 pub timestamp_secs: u64,
46 pub salt: Vec<u8>,
48}
49
50#[derive(Debug, Clone)]
52pub struct IPDiversityConfig {
53 pub max_nodes_per_64: usize,
55 pub max_nodes_per_48: usize,
57 pub max_nodes_per_32: usize,
59 pub max_nodes_per_asn: usize,
61 pub enable_geolocation_check: bool,
63 pub min_geographic_diversity: usize,
65}
66
67#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
69pub struct IPAnalysis {
70 pub subnet_64: Ipv6Addr,
72 pub subnet_48: Ipv6Addr,
74 pub subnet_32: Ipv6Addr,
76 pub asn: Option<u32>,
78 pub country: Option<String>,
80 pub is_hosting_provider: bool,
82 pub is_vpn_provider: bool,
84 pub reputation_score: f64,
86}
87
88#[derive(Debug, Clone)]
90pub struct NodeReputation {
91 pub peer_id: PeerId,
93 pub response_rate: f64,
95 pub response_time: Duration,
97 pub consistency_score: f64,
99 pub uptime_estimate: Duration,
101 pub routing_accuracy: f64,
103 pub last_seen: SystemTime,
105 pub interaction_count: u64,
107}
108
109impl Default for IPDiversityConfig {
110 fn default() -> Self {
111 Self {
112 max_nodes_per_64: 1,
113 max_nodes_per_48: 3,
114 max_nodes_per_32: 10,
115 max_nodes_per_asn: 20,
116 enable_geolocation_check: true,
117 min_geographic_diversity: 3,
118 }
119 }
120}
121
122impl IPv6NodeID {
123 pub fn generate(
125 ipv6_addr: Ipv6Addr,
126 secret: &MlDsaSecretKey,
127 public: &MlDsaPublicKey,
128 ) -> Result<Self> {
129 let mut rng = rand::thread_rng();
130 let mut salt = vec![0u8; 16];
131 rand::RngCore::fill_bytes(&mut rng, &mut salt);
132
133 let timestamp = SystemTime::now();
134 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
135 let public_key = public.as_bytes().to_vec();
136
137 let mut hasher = Sha256::new();
139 hasher.update(ipv6_addr.octets());
140 hasher.update(&public_key);
141 hasher.update(&salt);
142 hasher.update(timestamp_secs.to_le_bytes());
143 let node_id = hasher.finalize().to_vec();
144
145 let mut message_to_sign = Vec::new();
147 message_to_sign.extend_from_slice(&ipv6_addr.octets());
148 message_to_sign.extend_from_slice(&public_key);
149 message_to_sign.extend_from_slice(&salt);
150 message_to_sign.extend_from_slice(×tamp_secs.to_le_bytes());
151
152 let sig = ml_dsa_sign(secret, &message_to_sign)
153 .map_err(|e| anyhow!("ML-DSA sign failed: {:?}", e))?;
154 let signature = sig.0.to_vec();
155
156 Ok(IPv6NodeID {
157 node_id,
158 ipv6_addr,
159 public_key,
160 signature,
161 timestamp_secs,
162 salt,
163 })
164 }
165
166 pub fn verify(&self) -> Result<bool> {
168 let mut hasher = Sha256::new();
170 hasher.update(self.ipv6_addr.octets());
171 hasher.update(&self.public_key);
172 hasher.update(&self.salt);
173 hasher.update(self.timestamp_secs.to_le_bytes());
174 let expected_node_id = hasher.finalize();
175
176 if expected_node_id.as_slice() != self.node_id {
178 return Ok(false);
179 }
180
181 let public_key = MlDsaPublicKey::from_bytes(&self.public_key)
182 .map_err(|e| anyhow!("Invalid ML-DSA public key: {:?}", e))?;
183
184 if self.signature.len() != 3309 {
186 return Ok(false); }
188 let mut sig_bytes = [0u8; 3309];
189 sig_bytes.copy_from_slice(&self.signature);
190 let signature = MlDsaSignature(Box::new(sig_bytes));
191
192 let mut message_to_verify = Vec::new();
193 message_to_verify.extend_from_slice(&self.ipv6_addr.octets());
194 message_to_verify.extend_from_slice(&self.public_key);
195 message_to_verify.extend_from_slice(&self.salt);
196 message_to_verify.extend_from_slice(&self.timestamp_secs.to_le_bytes());
197
198 let ok = ml_dsa_verify(&public_key, &message_to_verify, &signature)
199 .map_err(|e| anyhow!("ML-DSA verify error: {:?}", e))?;
200 Ok(ok)
201 }
202
203 pub fn extract_subnet_64(&self) -> Ipv6Addr {
205 let octets = self.ipv6_addr.octets();
206 let mut subnet = [0u8; 16];
207 subnet[..8].copy_from_slice(&octets[..8]); Ipv6Addr::from(subnet)
209 }
210
211 pub fn extract_subnet_48(&self) -> Ipv6Addr {
213 let octets = self.ipv6_addr.octets();
214 let mut subnet = [0u8; 16];
215 subnet[..6].copy_from_slice(&octets[..6]); Ipv6Addr::from(subnet)
217 }
218
219 pub fn extract_subnet_32(&self) -> Ipv6Addr {
221 let octets = self.ipv6_addr.octets();
222 let mut subnet = [0u8; 16];
223 subnet[..4].copy_from_slice(&octets[..4]); Ipv6Addr::from(subnet)
225 }
226}
227
228#[derive(Debug)]
230pub struct IPDiversityEnforcer {
231 config: IPDiversityConfig,
232 subnet_64_counts: HashMap<Ipv6Addr, usize>,
233 subnet_48_counts: HashMap<Ipv6Addr, usize>,
234 subnet_32_counts: HashMap<Ipv6Addr, usize>,
235 asn_counts: HashMap<u32, usize>,
236 country_counts: HashMap<String, usize>,
237 geo_provider: Option<Arc<dyn GeoProvider + Send + Sync>>,
238}
239
240impl IPDiversityEnforcer {
241 pub fn new(config: IPDiversityConfig) -> Self {
243 Self {
244 config,
245 subnet_64_counts: HashMap::new(),
246 subnet_48_counts: HashMap::new(),
247 subnet_32_counts: HashMap::new(),
248 asn_counts: HashMap::new(),
249 country_counts: HashMap::new(),
250 geo_provider: None,
251 }
252 }
253
254 pub fn with_geo_provider(
256 config: IPDiversityConfig,
257 provider: Arc<dyn GeoProvider + Send + Sync>,
258 ) -> Self {
259 let mut s = Self::new(config);
260 s.geo_provider = Some(provider);
261 s
262 }
263
264 pub fn analyze_ip(&self, ipv6_addr: Ipv6Addr) -> Result<IPAnalysis> {
266 let subnet_64 = Self::extract_subnet_prefix(ipv6_addr, 64);
267 let subnet_48 = Self::extract_subnet_prefix(ipv6_addr, 48);
268 let subnet_32 = Self::extract_subnet_prefix(ipv6_addr, 32);
269
270 let (asn, country, is_hosting_provider, is_vpn_provider) =
272 if let Some(p) = &self.geo_provider {
273 let info = p.lookup(ipv6_addr);
274 (
275 info.asn,
276 info.country,
277 info.is_hosting_provider,
278 info.is_vpn_provider,
279 )
280 } else {
281 (None, None, false, false)
282 };
283
284 let reputation_score = 0.5;
286
287 Ok(IPAnalysis {
288 subnet_64,
289 subnet_48,
290 subnet_32,
291 asn,
292 country,
293 is_hosting_provider,
294 is_vpn_provider,
295 reputation_score,
296 })
297 }
298
299 pub fn can_accept_node(&self, ip_analysis: &IPAnalysis) -> bool {
301 let (limit_64, limit_48, limit_32, limit_asn) =
303 if ip_analysis.is_hosting_provider || ip_analysis.is_vpn_provider {
304 (
306 std::cmp::max(1, self.config.max_nodes_per_64 / 2),
307 std::cmp::max(1, self.config.max_nodes_per_48 / 2),
308 std::cmp::max(1, self.config.max_nodes_per_32 / 2),
309 std::cmp::max(1, self.config.max_nodes_per_asn / 2),
310 )
311 } else {
312 (
314 self.config.max_nodes_per_64,
315 self.config.max_nodes_per_48,
316 self.config.max_nodes_per_32,
317 self.config.max_nodes_per_asn,
318 )
319 };
320
321 if let Some(&count) = self.subnet_64_counts.get(&ip_analysis.subnet_64)
323 && count >= limit_64
324 {
325 return false;
326 }
327
328 if let Some(&count) = self.subnet_48_counts.get(&ip_analysis.subnet_48)
330 && count >= limit_48
331 {
332 return false;
333 }
334
335 if let Some(&count) = self.subnet_32_counts.get(&ip_analysis.subnet_32)
337 && count >= limit_32
338 {
339 return false;
340 }
341
342 if let Some(asn) = ip_analysis.asn
344 && let Some(&count) = self.asn_counts.get(&asn)
345 && count >= limit_asn
346 {
347 return false;
348 }
349
350 true
351 }
352
353 pub fn add_node(&mut self, ip_analysis: &IPAnalysis) -> Result<()> {
355 if !self.can_accept_node(ip_analysis) {
356 return Err(anyhow!("IP diversity limits exceeded"));
357 }
358
359 *self
361 .subnet_64_counts
362 .entry(ip_analysis.subnet_64)
363 .or_insert(0) += 1;
364 *self
365 .subnet_48_counts
366 .entry(ip_analysis.subnet_48)
367 .or_insert(0) += 1;
368 *self
369 .subnet_32_counts
370 .entry(ip_analysis.subnet_32)
371 .or_insert(0) += 1;
372
373 if let Some(asn) = ip_analysis.asn {
374 *self.asn_counts.entry(asn).or_insert(0) += 1;
375 }
376
377 if let Some(ref country) = ip_analysis.country {
378 *self.country_counts.entry(country.clone()).or_insert(0) += 1;
379 }
380
381 Ok(())
382 }
383
384 pub fn remove_node(&mut self, ip_analysis: &IPAnalysis) {
386 if let Some(count) = self.subnet_64_counts.get_mut(&ip_analysis.subnet_64) {
387 *count = count.saturating_sub(1);
388 if *count == 0 {
389 self.subnet_64_counts.remove(&ip_analysis.subnet_64);
390 }
391 }
392
393 if let Some(count) = self.subnet_48_counts.get_mut(&ip_analysis.subnet_48) {
394 *count = count.saturating_sub(1);
395 if *count == 0 {
396 self.subnet_48_counts.remove(&ip_analysis.subnet_48);
397 }
398 }
399
400 if let Some(count) = self.subnet_32_counts.get_mut(&ip_analysis.subnet_32) {
401 *count = count.saturating_sub(1);
402 if *count == 0 {
403 self.subnet_32_counts.remove(&ip_analysis.subnet_32);
404 }
405 }
406
407 if let Some(asn) = ip_analysis.asn
408 && let Some(count) = self.asn_counts.get_mut(&asn)
409 {
410 *count = count.saturating_sub(1);
411 if *count == 0 {
412 self.asn_counts.remove(&asn);
413 }
414 }
415
416 if let Some(ref country) = ip_analysis.country
417 && let Some(count) = self.country_counts.get_mut(country)
418 {
419 *count = count.saturating_sub(1);
420 if *count == 0 {
421 self.country_counts.remove(country);
422 }
423 }
424 }
425
426 pub fn extract_subnet_prefix(addr: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
428 let octets = addr.octets();
429 let mut subnet = [0u8; 16];
430
431 let bytes_to_copy = (prefix_len / 8) as usize;
432 let remaining_bits = prefix_len % 8;
433
434 if bytes_to_copy < 16 {
436 subnet[..bytes_to_copy].copy_from_slice(&octets[..bytes_to_copy]);
437 } else {
438 subnet.copy_from_slice(&octets);
439 }
440
441 if remaining_bits > 0 && bytes_to_copy < 16 {
443 let mask = 0xFF << (8 - remaining_bits);
444 subnet[bytes_to_copy] = octets[bytes_to_copy] & mask;
445 }
446
447 Ipv6Addr::from(subnet)
448 }
449
450 pub fn get_diversity_stats(&self) -> DiversityStats {
452 DiversityStats {
453 total_64_subnets: self.subnet_64_counts.len(),
454 total_48_subnets: self.subnet_48_counts.len(),
455 total_32_subnets: self.subnet_32_counts.len(),
456 total_asns: self.asn_counts.len(),
457 total_countries: self.country_counts.len(),
458 max_nodes_per_64: self.subnet_64_counts.values().max().copied().unwrap_or(0),
459 max_nodes_per_48: self.subnet_48_counts.values().max().copied().unwrap_or(0),
460 max_nodes_per_32: self.subnet_32_counts.values().max().copied().unwrap_or(0),
461 }
462 }
463}
464
465pub trait GeoProvider: std::fmt::Debug {
467 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo;
468}
469
470#[derive(Debug, Clone)]
472pub struct GeoInfo {
473 pub asn: Option<u32>,
474 pub country: Option<String>,
475 pub is_hosting_provider: bool,
476 pub is_vpn_provider: bool,
477}
478
479#[derive(Debug)]
481pub struct CachedGeoProvider<P: GeoProvider> {
482 inner: P,
483 cache: parking_lot::RwLock<HashMap<Ipv6Addr, GeoInfo>>,
484}
485
486impl<P: GeoProvider> CachedGeoProvider<P> {
487 pub fn new(inner: P) -> Self {
488 Self {
489 inner,
490 cache: parking_lot::RwLock::new(HashMap::new()),
491 }
492 }
493}
494
495impl<P: GeoProvider> GeoProvider for CachedGeoProvider<P> {
496 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo {
497 if let Some(info) = self.cache.read().get(&ip).cloned() {
498 return info;
499 }
500 let info = self.inner.lookup(ip);
501 self.cache.write().insert(ip, info.clone());
502 info
503 }
504}
505
506#[derive(Debug)]
508pub struct StubGeoProvider;
509impl GeoProvider for StubGeoProvider {
510 fn lookup(&self, _ip: Ipv6Addr) -> GeoInfo {
511 GeoInfo {
512 asn: None,
513 country: None,
514 is_hosting_provider: false,
515 is_vpn_provider: false,
516 }
517 }
518}
519
520#[derive(Debug, Clone, Serialize, Deserialize)]
522pub struct DiversityStats {
523 pub total_64_subnets: usize,
525 pub total_48_subnets: usize,
527 pub total_32_subnets: usize,
529 pub total_asns: usize,
531 pub total_countries: usize,
533 pub max_nodes_per_64: usize,
535 pub max_nodes_per_48: usize,
537 pub max_nodes_per_32: usize,
539}
540
541#[derive(Debug)]
543pub struct ReputationManager {
544 reputations: HashMap<PeerId, NodeReputation>,
545 reputation_decay: f64,
546 min_reputation: f64,
547}
548
549impl ReputationManager {
550 pub fn new(reputation_decay: f64, min_reputation: f64) -> Self {
552 Self {
553 reputations: HashMap::new(),
554 reputation_decay,
555 min_reputation,
556 }
557 }
558
559 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<&NodeReputation> {
561 self.reputations.get(peer_id)
562 }
563
564 pub fn update_reputation(&mut self, peer_id: &PeerId, success: bool, response_time: Duration) {
566 let reputation =
567 self.reputations
568 .entry(peer_id.clone())
569 .or_insert_with(|| NodeReputation {
570 peer_id: peer_id.clone(),
571 response_rate: 0.5,
572 response_time: Duration::from_millis(500),
573 consistency_score: 0.5,
574 uptime_estimate: Duration::from_secs(0),
575 routing_accuracy: 0.5,
576 last_seen: SystemTime::now(),
577 interaction_count: 0,
578 });
579
580 let alpha = 0.3; if success {
584 reputation.response_rate = reputation.response_rate * (1.0 - alpha) + alpha;
585 } else {
586 reputation.response_rate *= 1.0 - alpha;
587 }
588
589 let response_time_ms = response_time.as_millis() as f64;
591 let current_response_ms = reputation.response_time.as_millis() as f64;
592 let new_response_ms = current_response_ms * (1.0 - alpha) + response_time_ms * alpha;
593 reputation.response_time = Duration::from_millis(new_response_ms as u64);
594
595 reputation.last_seen = SystemTime::now();
596 reputation.interaction_count += 1;
597 }
598
599 pub fn apply_decay(&mut self) {
601 let now = SystemTime::now();
602
603 self.reputations.retain(|_, reputation| {
604 if let Ok(elapsed) = now.duration_since(reputation.last_seen) {
605 let decay_factor = (-elapsed.as_secs_f64() / 3600.0 * self.reputation_decay).exp();
607 reputation.response_rate *= decay_factor;
608 reputation.consistency_score *= decay_factor;
609 reputation.routing_accuracy *= decay_factor;
610
611 reputation.response_rate > self.min_reputation / 10.0
613 } else {
614 true
615 }
616 });
617 }
618}
619
620#[cfg(test)]
623mod tests {
624 use super::*;
625 use crate::quantum_crypto::generate_ml_dsa_keypair;
626
627 fn create_test_keypair() -> (MlDsaPublicKey, MlDsaSecretKey) {
628 generate_ml_dsa_keypair().expect("Failed to generate test keypair")
629 }
630
631 fn create_test_ipv6() -> Ipv6Addr {
632 Ipv6Addr::new(
633 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334,
634 )
635 }
636
637 fn create_test_diversity_config() -> IPDiversityConfig {
638 IPDiversityConfig {
639 max_nodes_per_64: 1,
640 max_nodes_per_48: 3,
641 max_nodes_per_32: 10,
642 max_nodes_per_asn: 20,
643 enable_geolocation_check: true,
644 min_geographic_diversity: 3,
645 }
646 }
647
648 #[test]
649 fn test_ipv6_node_id_generation() -> Result<()> {
650 let (public_key, secret_key) = create_test_keypair();
651 let ipv6_addr = create_test_ipv6();
652
653 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
654
655 assert_eq!(node_id.ipv6_addr, ipv6_addr);
656 assert_eq!(node_id.public_key.len(), 1952); assert_eq!(node_id.signature.len(), 3309); assert_eq!(node_id.node_id.len(), 32); assert_eq!(node_id.salt.len(), 16);
660 assert!(node_id.timestamp_secs > 0);
661
662 Ok(())
663 }
664
665 #[test]
666 fn test_ipv6_node_id_verification() -> Result<()> {
667 let (public_key, secret_key) = create_test_keypair();
668 let ipv6_addr = create_test_ipv6();
669
670 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
671 let is_valid = node_id.verify()?;
672
673 assert!(is_valid);
674
675 Ok(())
676 }
677
678 #[test]
679 fn test_ipv6_node_id_verification_fails_with_wrong_data() -> Result<()> {
680 let (public_key, secret_key) = create_test_keypair();
681 let ipv6_addr = create_test_ipv6();
682
683 let mut node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
684
685 node_id.node_id[0] ^= 0xFF;
687 let is_valid = node_id.verify()?;
688 assert!(!is_valid);
689
690 let mut node_id2 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
692 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
694 assert!(!is_valid2);
695
696 let mut node_id3 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
698 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
700 assert!(!is_valid3);
701
702 Ok(())
703 }
704
705 #[test]
706 fn test_ipv6_subnet_extraction() -> Result<()> {
707 let (public_key, secret_key) = create_test_keypair();
708 let ipv6_addr = Ipv6Addr::new(
709 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
710 );
711
712 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
713
714 let subnet_64 = node_id.extract_subnet_64();
716 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
717 assert_eq!(subnet_64, expected_64);
718
719 let subnet_48 = node_id.extract_subnet_48();
721 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
722 assert_eq!(subnet_48, expected_48);
723
724 let subnet_32 = node_id.extract_subnet_32();
726 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
727 assert_eq!(subnet_32, expected_32);
728
729 Ok(())
730 }
731
732 #[test]
733 fn test_ip_diversity_config_default() {
734 let config = IPDiversityConfig::default();
735
736 assert_eq!(config.max_nodes_per_64, 1);
737 assert_eq!(config.max_nodes_per_48, 3);
738 assert_eq!(config.max_nodes_per_32, 10);
739 assert_eq!(config.max_nodes_per_asn, 20);
740 assert!(config.enable_geolocation_check);
741 assert_eq!(config.min_geographic_diversity, 3);
742 }
743
744 #[test]
745 fn test_ip_diversity_enforcer_creation() {
746 let config = create_test_diversity_config();
747 let enforcer = IPDiversityEnforcer::new(config.clone());
748
749 assert_eq!(enforcer.config.max_nodes_per_64, config.max_nodes_per_64);
750 assert_eq!(enforcer.subnet_64_counts.len(), 0);
751 assert_eq!(enforcer.subnet_48_counts.len(), 0);
752 assert_eq!(enforcer.subnet_32_counts.len(), 0);
753 }
754
755 #[test]
756 fn test_ip_analysis() -> Result<()> {
757 let config = create_test_diversity_config();
758 let enforcer = IPDiversityEnforcer::new(config);
759
760 let ipv6_addr = create_test_ipv6();
761 let analysis = enforcer.analyze_ip(ipv6_addr)?;
762
763 assert_eq!(
764 analysis.subnet_64,
765 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 64)
766 );
767 assert_eq!(
768 analysis.subnet_48,
769 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 48)
770 );
771 assert_eq!(
772 analysis.subnet_32,
773 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 32)
774 );
775 assert!(analysis.asn.is_none()); assert!(analysis.country.is_none()); assert!(!analysis.is_hosting_provider);
778 assert!(!analysis.is_vpn_provider);
779 assert_eq!(analysis.reputation_score, 0.5);
780
781 Ok(())
782 }
783
784 #[test]
785 fn test_can_accept_node_basic() -> Result<()> {
786 let config = create_test_diversity_config();
787 let enforcer = IPDiversityEnforcer::new(config);
788
789 let ipv6_addr = create_test_ipv6();
790 let analysis = enforcer.analyze_ip(ipv6_addr)?;
791
792 assert!(enforcer.can_accept_node(&analysis));
794
795 Ok(())
796 }
797
798 #[test]
799 fn test_add_and_remove_node() -> Result<()> {
800 let config = create_test_diversity_config();
801 let mut enforcer = IPDiversityEnforcer::new(config);
802
803 let ipv6_addr = create_test_ipv6();
804 let analysis = enforcer.analyze_ip(ipv6_addr)?;
805
806 enforcer.add_node(&analysis)?;
808 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), Some(&1));
809 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), Some(&1));
810 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), Some(&1));
811
812 enforcer.remove_node(&analysis);
814 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), None);
815 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), None);
816 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), None);
817
818 Ok(())
819 }
820
821 #[test]
822 fn test_diversity_limits_enforcement() -> Result<()> {
823 let config = create_test_diversity_config();
824 let mut enforcer = IPDiversityEnforcer::new(config);
825
826 let ipv6_addr1 = Ipv6Addr::new(
827 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
828 );
829 let ipv6_addr2 = Ipv6Addr::new(
830 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7335,
831 ); let analysis1 = enforcer.analyze_ip(ipv6_addr1)?;
834 let analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
835
836 assert!(enforcer.can_accept_node(&analysis1));
838 enforcer.add_node(&analysis1)?;
839
840 assert!(!enforcer.can_accept_node(&analysis2));
842
843 let result = enforcer.add_node(&analysis2);
845 assert!(result.is_err());
846 assert!(
847 result
848 .unwrap_err()
849 .to_string()
850 .contains("IP diversity limits exceeded")
851 );
852
853 Ok(())
854 }
855
856 #[test]
857 fn test_hosting_provider_stricter_limits() -> Result<()> {
858 let config = IPDiversityConfig {
859 max_nodes_per_64: 4, max_nodes_per_48: 8,
861 ..create_test_diversity_config()
862 };
863 let mut enforcer = IPDiversityEnforcer::new(config);
864
865 let ipv6_addr = create_test_ipv6();
866 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
867 analysis.is_hosting_provider = true;
868
869 assert!(enforcer.can_accept_node(&analysis));
871 enforcer.add_node(&analysis)?;
872
873 let ipv6_addr2 = Ipv6Addr::new(
875 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7335,
876 );
877 let mut analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
878 analysis2.is_hosting_provider = true;
879 analysis2.subnet_64 = analysis.subnet_64; assert!(enforcer.can_accept_node(&analysis2));
882 enforcer.add_node(&analysis2)?;
883
884 let ipv6_addr3 = Ipv6Addr::new(
886 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7336,
887 );
888 let mut analysis3 = enforcer.analyze_ip(ipv6_addr3)?;
889 analysis3.is_hosting_provider = true;
890 analysis3.subnet_64 = analysis.subnet_64; assert!(!enforcer.can_accept_node(&analysis3));
893
894 Ok(())
895 }
896
897 #[test]
898 fn test_diversity_stats() -> Result<()> {
899 let config = create_test_diversity_config();
900 let mut enforcer = IPDiversityEnforcer::new(config);
901
902 let addresses = [
904 Ipv6Addr::new(
905 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
906 ),
907 Ipv6Addr::new(
908 0x2001, 0xdb8, 0x85a4, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
909 ), Ipv6Addr::new(
911 0x2002, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
912 ), ];
914
915 for addr in addresses {
916 let analysis = enforcer.analyze_ip(addr)?;
917 enforcer.add_node(&analysis)?;
918 }
919
920 let stats = enforcer.get_diversity_stats();
921 assert_eq!(stats.total_64_subnets, 3);
922 assert_eq!(stats.total_48_subnets, 3);
923 assert_eq!(stats.total_32_subnets, 2); assert_eq!(stats.max_nodes_per_64, 1);
925 assert_eq!(stats.max_nodes_per_48, 1);
926 assert_eq!(stats.max_nodes_per_32, 2); Ok(())
929 }
930
931 #[test]
932 fn test_extract_subnet_prefix() {
933 let addr = Ipv6Addr::new(
934 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
935 );
936
937 let prefix_64 = IPDiversityEnforcer::extract_subnet_prefix(addr, 64);
939 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
940 assert_eq!(prefix_64, expected_64);
941
942 let prefix_48 = IPDiversityEnforcer::extract_subnet_prefix(addr, 48);
944 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
945 assert_eq!(prefix_48, expected_48);
946
947 let prefix_32 = IPDiversityEnforcer::extract_subnet_prefix(addr, 32);
949 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
950 assert_eq!(prefix_32, expected_32);
951
952 let prefix_56 = IPDiversityEnforcer::extract_subnet_prefix(addr, 56);
954 let expected_56 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1200, 0, 0, 0, 0);
955 assert_eq!(prefix_56, expected_56);
956
957 let prefix_128 = IPDiversityEnforcer::extract_subnet_prefix(addr, 128);
959 assert_eq!(prefix_128, addr);
960 }
961
962 #[test]
963 fn test_reputation_manager_creation() {
964 let manager = ReputationManager::new(0.1, 0.1);
965 assert_eq!(manager.reputation_decay, 0.1);
966 assert_eq!(manager.min_reputation, 0.1);
967 assert_eq!(manager.reputations.len(), 0);
968 }
969
970 #[test]
971 fn test_reputation_get_nonexistent() {
972 let manager = ReputationManager::new(0.1, 0.1);
973 let peer_id = "test_peer".to_string();
974
975 let reputation = manager.get_reputation(&peer_id);
976 assert!(reputation.is_none());
977 }
978
979 #[test]
980 fn test_reputation_update_creates_entry() {
981 let mut manager = ReputationManager::new(0.1, 0.1);
982 let peer_id = "test_peer".to_string();
983
984 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
985
986 let reputation = manager.get_reputation(&peer_id);
987 assert!(reputation.is_some());
988
989 let rep = reputation.unwrap();
990 assert_eq!(rep.peer_id, peer_id);
991 assert!(rep.response_rate > 0.5); assert_eq!(rep.interaction_count, 1);
993 }
994
995 #[test]
996 fn test_reputation_update_success_improves_rate() {
997 let mut manager = ReputationManager::new(0.1, 0.1);
998 let peer_id = "test_peer".to_string();
999
1000 for _ in 0..15 {
1002 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1003 }
1004
1005 let reputation = manager.get_reputation(&peer_id).unwrap();
1006 assert!(reputation.response_rate > 0.85); assert_eq!(reputation.interaction_count, 15);
1008 }
1009
1010 #[test]
1011 fn test_reputation_update_failure_decreases_rate() {
1012 let mut manager = ReputationManager::new(0.1, 0.1);
1013 let peer_id = "test_peer".to_string();
1014
1015 for _ in 0..15 {
1017 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1018 }
1019
1020 let reputation = manager.get_reputation(&peer_id).unwrap();
1021 assert!(reputation.response_rate < 0.15); assert_eq!(reputation.interaction_count, 15);
1023 }
1024
1025 #[test]
1026 fn test_reputation_response_time_tracking() {
1027 let mut manager = ReputationManager::new(0.1, 0.1);
1028 let peer_id = "test_peer".to_string();
1029
1030 manager.update_reputation(&peer_id, true, Duration::from_millis(200));
1032
1033 let reputation = manager.get_reputation(&peer_id).unwrap();
1034 assert!(reputation.response_time.as_millis() > 200);
1036 assert!(reputation.response_time.as_millis() < 500);
1037 }
1038
1039 #[test]
1040 fn test_reputation_decay() {
1041 let mut manager = ReputationManager::new(1.0, 0.01); let peer_id = "test_peer".to_string();
1043
1044 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1046
1047 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1049 reputation.last_seen = SystemTime::now() - Duration::from_secs(7200); }
1051
1052 let original_rate = manager.get_reputation(&peer_id).unwrap().response_rate;
1053
1054 manager.apply_decay();
1056
1057 let reputation = manager.get_reputation(&peer_id);
1058 if let Some(rep) = reputation {
1059 assert!(rep.response_rate < original_rate);
1061 } }
1063
1064 #[test]
1065 fn test_reputation_decay_removes_low_reputation() {
1066 let mut manager = ReputationManager::new(0.1, 0.5); let peer_id = "test_peer".to_string();
1068
1069 for _ in 0..10 {
1071 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1072 }
1073
1074 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1076 reputation.last_seen = SystemTime::now() - Duration::from_secs(3600); reputation.response_rate = 0.01; }
1079
1080 manager.apply_decay();
1082
1083 assert!(manager.get_reputation(&peer_id).is_none());
1085 }
1086
1087 #[test]
1088 fn test_security_types_keypair() {
1089 let (public_key, secret_key) =
1090 generate_ml_dsa_keypair().expect("Failed to generate keypair");
1091
1092 let public_key_bytes = public_key.as_bytes();
1093 assert_eq!(public_key_bytes.len(), 1952); let message = b"test message";
1096 let signature = ml_dsa_sign(&secret_key, message).expect("Failed to sign message");
1097 assert_eq!(signature.as_bytes().len(), 3309); assert!(ml_dsa_verify(&public_key, message, &signature).is_ok());
1101 }
1102
1103 #[test]
1104 fn test_node_reputation_structure() {
1105 let peer_id = "test_peer".to_string();
1106 let reputation = NodeReputation {
1107 peer_id: peer_id.clone(),
1108 response_rate: 0.85,
1109 response_time: Duration::from_millis(150),
1110 consistency_score: 0.9,
1111 uptime_estimate: Duration::from_secs(86400),
1112 routing_accuracy: 0.8,
1113 last_seen: SystemTime::now(),
1114 interaction_count: 42,
1115 };
1116
1117 assert_eq!(reputation.peer_id, peer_id);
1118 assert_eq!(reputation.response_rate, 0.85);
1119 assert_eq!(reputation.response_time, Duration::from_millis(150));
1120 assert_eq!(reputation.consistency_score, 0.9);
1121 assert_eq!(reputation.uptime_estimate, Duration::from_secs(86400));
1122 assert_eq!(reputation.routing_accuracy, 0.8);
1123 assert_eq!(reputation.interaction_count, 42);
1124 }
1125
1126 #[test]
1127 fn test_ip_analysis_structure() {
1128 let analysis = IPAnalysis {
1129 subnet_64: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0),
1130 subnet_48: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0),
1131 subnet_32: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1132 asn: Some(64512),
1133 country: Some("US".to_string()),
1134 is_hosting_provider: true,
1135 is_vpn_provider: false,
1136 reputation_score: 0.75,
1137 };
1138
1139 assert_eq!(analysis.asn, Some(64512));
1140 assert_eq!(analysis.country, Some("US".to_string()));
1141 assert!(analysis.is_hosting_provider);
1142 assert!(!analysis.is_vpn_provider);
1143 assert_eq!(analysis.reputation_score, 0.75);
1144 }
1145
1146 #[test]
1147 fn test_diversity_stats_structure() {
1148 let stats = DiversityStats {
1149 total_64_subnets: 100,
1150 total_48_subnets: 50,
1151 total_32_subnets: 25,
1152 total_asns: 15,
1153 total_countries: 8,
1154 max_nodes_per_64: 1,
1155 max_nodes_per_48: 3,
1156 max_nodes_per_32: 10,
1157 };
1158
1159 assert_eq!(stats.total_64_subnets, 100);
1160 assert_eq!(stats.total_48_subnets, 50);
1161 assert_eq!(stats.total_32_subnets, 25);
1162 assert_eq!(stats.total_asns, 15);
1163 assert_eq!(stats.total_countries, 8);
1164 assert_eq!(stats.max_nodes_per_64, 1);
1165 assert_eq!(stats.max_nodes_per_48, 3);
1166 assert_eq!(stats.max_nodes_per_32, 10);
1167 }
1168
1169 #[test]
1170 fn test_multiple_same_subnet_nodes() -> Result<()> {
1171 let config = IPDiversityConfig {
1172 max_nodes_per_64: 3, max_nodes_per_48: 5,
1174 max_nodes_per_32: 10,
1175 ..create_test_diversity_config()
1176 };
1177 let mut enforcer = IPDiversityEnforcer::new(config);
1178
1179 let _base_addr = Ipv6Addr::new(
1180 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x0000,
1181 );
1182
1183 for i in 1..=3 {
1185 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, i);
1186 let analysis = enforcer.analyze_ip(addr)?;
1187 assert!(enforcer.can_accept_node(&analysis));
1188 enforcer.add_node(&analysis)?;
1189 }
1190
1191 let addr4 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 4);
1193 let analysis4 = enforcer.analyze_ip(addr4)?;
1194 assert!(!enforcer.can_accept_node(&analysis4));
1195
1196 let stats = enforcer.get_diversity_stats();
1197 assert_eq!(stats.total_64_subnets, 1);
1198 assert_eq!(stats.max_nodes_per_64, 3);
1199
1200 Ok(())
1201 }
1202
1203 #[test]
1204 fn test_asn_and_country_tracking() -> Result<()> {
1205 let config = create_test_diversity_config();
1206 let mut enforcer = IPDiversityEnforcer::new(config);
1207
1208 let ipv6_addr = create_test_ipv6();
1210 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1211 analysis.asn = Some(64512);
1212 analysis.country = Some("US".to_string());
1213
1214 enforcer.add_node(&analysis)?;
1215
1216 assert_eq!(enforcer.asn_counts.get(&64512), Some(&1));
1217 assert_eq!(enforcer.country_counts.get("US"), Some(&1));
1218
1219 enforcer.remove_node(&analysis);
1221 assert!(!enforcer.asn_counts.contains_key(&64512));
1222 assert!(!enforcer.country_counts.contains_key("US"));
1223
1224 Ok(())
1225 }
1226
1227 #[test]
1228 fn test_reputation_mixed_interactions() {
1229 let mut manager = ReputationManager::new(0.1, 0.1);
1230 let peer_id = "test_peer".to_string();
1231
1232 for i in 0..15 {
1234 let success = i % 3 != 0; manager.update_reputation(&peer_id, success, Duration::from_millis(100 + i * 10));
1236 }
1237
1238 let reputation = manager.get_reputation(&peer_id).unwrap();
1239 assert!(reputation.response_rate > 0.55);
1242 assert!(reputation.response_rate < 0.85);
1243 assert_eq!(reputation.interaction_count, 15);
1244 }
1245}