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::{Ipv4Addr, 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,
56 pub max_nodes_per_48: usize,
58 pub max_nodes_per_32: usize,
60
61 pub max_nodes_per_ipv4_32: usize,
64 pub max_nodes_per_ipv4_24: usize,
66 pub max_nodes_per_ipv4_16: usize,
68
69 pub max_per_ip_cap: usize,
72 pub max_network_fraction: f64,
74
75 pub max_nodes_per_asn: usize,
78 pub enable_geolocation_check: bool,
80 pub min_geographic_diversity: usize,
82}
83
84#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
86pub struct IPAnalysis {
87 pub subnet_64: Ipv6Addr,
89 pub subnet_48: Ipv6Addr,
91 pub subnet_32: Ipv6Addr,
93 pub asn: Option<u32>,
95 pub country: Option<String>,
97 pub is_hosting_provider: bool,
99 pub is_vpn_provider: bool,
101 pub reputation_score: f64,
103}
104
105#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
107pub struct IPv4Analysis {
108 pub ip_addr: Ipv4Addr,
110 pub subnet_24: Ipv4Addr,
112 pub subnet_16: Ipv4Addr,
114 pub subnet_8: Ipv4Addr,
116 pub asn: Option<u32>,
118 pub country: Option<String>,
120 pub is_hosting_provider: bool,
122 pub is_vpn_provider: bool,
124 pub reputation_score: f64,
126}
127
128#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
130pub enum UnifiedIPAnalysis {
131 IPv4(IPv4Analysis),
133 IPv6(IPAnalysis),
135}
136
137#[derive(Debug, Clone)]
139pub struct NodeReputation {
140 pub peer_id: PeerId,
142 pub response_rate: f64,
144 pub response_time: Duration,
146 pub consistency_score: f64,
148 pub uptime_estimate: Duration,
150 pub routing_accuracy: f64,
152 pub last_seen: SystemTime,
154 pub interaction_count: u64,
156}
157
158impl Default for IPDiversityConfig {
159 fn default() -> Self {
160 Self {
161 max_nodes_per_64: 1,
163 max_nodes_per_48: 3,
164 max_nodes_per_32: 10,
165 max_nodes_per_ipv4_32: 1, max_nodes_per_ipv4_24: 3, max_nodes_per_ipv4_16: 10, max_per_ip_cap: 50, max_network_fraction: 0.005, max_nodes_per_asn: 20,
174 enable_geolocation_check: true,
175 min_geographic_diversity: 3,
176 }
177 }
178}
179
180impl IPDiversityConfig {
181 #[must_use]
192 pub fn testnet() -> Self {
193 Self {
194 max_nodes_per_64: 100, max_nodes_per_48: 500, max_nodes_per_32: 1000, max_nodes_per_ipv4_32: 100, max_nodes_per_ipv4_24: 500, max_nodes_per_ipv4_16: 1000, max_per_ip_cap: 100, max_network_fraction: 0.1, max_nodes_per_asn: 5000, enable_geolocation_check: false, min_geographic_diversity: 1, }
210 }
211
212 #[must_use]
217 pub fn permissive() -> Self {
218 Self {
219 max_nodes_per_64: usize::MAX,
221 max_nodes_per_48: usize::MAX,
222 max_nodes_per_32: usize::MAX,
223 max_nodes_per_ipv4_32: usize::MAX,
225 max_nodes_per_ipv4_24: usize::MAX,
226 max_nodes_per_ipv4_16: usize::MAX,
227 max_per_ip_cap: usize::MAX,
229 max_network_fraction: 1.0, max_nodes_per_asn: usize::MAX,
232 enable_geolocation_check: false,
233 min_geographic_diversity: 0,
234 }
235 }
236
237 #[must_use]
239 pub fn is_relaxed(&self) -> bool {
240 self.max_nodes_per_asn > 100 || !self.enable_geolocation_check
241 }
242}
243
244impl IPv6NodeID {
245 pub fn generate(
247 ipv6_addr: Ipv6Addr,
248 secret: &MlDsaSecretKey,
249 public: &MlDsaPublicKey,
250 ) -> Result<Self> {
251 let mut rng = rand::thread_rng();
252 let mut salt = vec![0u8; 16];
253 rand::RngCore::fill_bytes(&mut rng, &mut salt);
254
255 let timestamp = SystemTime::now();
256 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
257 let public_key = public.as_bytes().to_vec();
258
259 let mut hasher = Sha256::new();
261 hasher.update(ipv6_addr.octets());
262 hasher.update(&public_key);
263 hasher.update(&salt);
264 hasher.update(timestamp_secs.to_le_bytes());
265 let node_id = hasher.finalize().to_vec();
266
267 let mut message_to_sign = Vec::new();
269 message_to_sign.extend_from_slice(&ipv6_addr.octets());
270 message_to_sign.extend_from_slice(&public_key);
271 message_to_sign.extend_from_slice(&salt);
272 message_to_sign.extend_from_slice(×tamp_secs.to_le_bytes());
273
274 let sig = ml_dsa_sign(secret, &message_to_sign)
275 .map_err(|e| anyhow!("ML-DSA sign failed: {:?}", e))?;
276 let signature = sig.0.to_vec();
277
278 Ok(IPv6NodeID {
279 node_id,
280 ipv6_addr,
281 public_key,
282 signature,
283 timestamp_secs,
284 salt,
285 })
286 }
287
288 pub fn verify(&self) -> Result<bool> {
290 let mut hasher = Sha256::new();
292 hasher.update(self.ipv6_addr.octets());
293 hasher.update(&self.public_key);
294 hasher.update(&self.salt);
295 hasher.update(self.timestamp_secs.to_le_bytes());
296 let expected_node_id = hasher.finalize();
297
298 if expected_node_id.as_slice() != self.node_id {
300 return Ok(false);
301 }
302
303 let public_key = MlDsaPublicKey::from_bytes(&self.public_key)
304 .map_err(|e| anyhow!("Invalid ML-DSA public key: {:?}", e))?;
305
306 if self.signature.len() != 3309 {
308 return Ok(false); }
310 let mut sig_bytes = [0u8; 3309];
311 sig_bytes.copy_from_slice(&self.signature);
312 let signature = MlDsaSignature(Box::new(sig_bytes));
313
314 let mut message_to_verify = Vec::new();
315 message_to_verify.extend_from_slice(&self.ipv6_addr.octets());
316 message_to_verify.extend_from_slice(&self.public_key);
317 message_to_verify.extend_from_slice(&self.salt);
318 message_to_verify.extend_from_slice(&self.timestamp_secs.to_le_bytes());
319
320 let ok = ml_dsa_verify(&public_key, &message_to_verify, &signature)
321 .map_err(|e| anyhow!("ML-DSA verify error: {:?}", e))?;
322 Ok(ok)
323 }
324
325 pub fn extract_subnet_64(&self) -> Ipv6Addr {
327 let octets = self.ipv6_addr.octets();
328 let mut subnet = [0u8; 16];
329 subnet[..8].copy_from_slice(&octets[..8]); Ipv6Addr::from(subnet)
331 }
332
333 pub fn extract_subnet_48(&self) -> Ipv6Addr {
335 let octets = self.ipv6_addr.octets();
336 let mut subnet = [0u8; 16];
337 subnet[..6].copy_from_slice(&octets[..6]); Ipv6Addr::from(subnet)
339 }
340
341 pub fn extract_subnet_32(&self) -> Ipv6Addr {
343 let octets = self.ipv6_addr.octets();
344 let mut subnet = [0u8; 16];
345 subnet[..4].copy_from_slice(&octets[..4]); Ipv6Addr::from(subnet)
347 }
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct IPv4NodeID {
354 pub node_id: Vec<u8>,
356 pub ipv4_addr: Ipv4Addr,
358 pub public_key: Vec<u8>,
360 pub signature: Vec<u8>,
362 pub timestamp_secs: u64,
364 pub salt: Vec<u8>,
366}
367
368impl IPv4NodeID {
369 pub fn generate(
371 ipv4_addr: Ipv4Addr,
372 secret: &MlDsaSecretKey,
373 public: &MlDsaPublicKey,
374 ) -> Result<Self> {
375 let mut rng = rand::thread_rng();
376 let mut salt = vec![0u8; 16];
377 rand::RngCore::fill_bytes(&mut rng, &mut salt);
378
379 let timestamp = SystemTime::now();
380 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
381 let public_key = public.as_bytes().to_vec();
382
383 let mut hasher = Sha256::new();
385 hasher.update(ipv4_addr.octets());
386 hasher.update(&public_key);
387 hasher.update(&salt);
388 hasher.update(timestamp_secs.to_le_bytes());
389 let node_id = hasher.finalize().to_vec();
390
391 let mut message_to_sign = Vec::new();
393 message_to_sign.extend_from_slice(&ipv4_addr.octets());
394 message_to_sign.extend_from_slice(&public_key);
395 message_to_sign.extend_from_slice(&salt);
396 message_to_sign.extend_from_slice(×tamp_secs.to_le_bytes());
397
398 let sig = ml_dsa_sign(secret, &message_to_sign)
399 .map_err(|e| anyhow!("ML-DSA sign failed: {:?}", e))?;
400 let signature = sig.0.to_vec();
401
402 Ok(IPv4NodeID {
403 node_id,
404 ipv4_addr,
405 public_key,
406 signature,
407 timestamp_secs,
408 salt,
409 })
410 }
411
412 pub fn verify(&self) -> Result<bool> {
414 let mut hasher = Sha256::new();
416 hasher.update(self.ipv4_addr.octets());
417 hasher.update(&self.public_key);
418 hasher.update(&self.salt);
419 hasher.update(self.timestamp_secs.to_le_bytes());
420 let expected_node_id = hasher.finalize();
421
422 if expected_node_id.as_slice() != self.node_id {
424 return Ok(false);
425 }
426
427 let public_key = MlDsaPublicKey::from_bytes(&self.public_key)
428 .map_err(|e| anyhow!("Invalid ML-DSA public key: {:?}", e))?;
429
430 if self.signature.len() != 3309 {
432 return Ok(false); }
434 let mut sig_bytes = [0u8; 3309];
435 sig_bytes.copy_from_slice(&self.signature);
436 let signature = MlDsaSignature(Box::new(sig_bytes));
437
438 let mut message_to_verify = Vec::new();
439 message_to_verify.extend_from_slice(&self.ipv4_addr.octets());
440 message_to_verify.extend_from_slice(&self.public_key);
441 message_to_verify.extend_from_slice(&self.salt);
442 message_to_verify.extend_from_slice(&self.timestamp_secs.to_le_bytes());
443
444 let ok = ml_dsa_verify(&public_key, &message_to_verify, &signature)
445 .map_err(|e| anyhow!("ML-DSA verify error: {:?}", e))?;
446 Ok(ok)
447 }
448
449 pub fn extract_subnet_24(&self) -> Ipv4Addr {
451 let octets = self.ipv4_addr.octets();
452 Ipv4Addr::new(octets[0], octets[1], octets[2], 0)
453 }
454
455 pub fn extract_subnet_16(&self) -> Ipv4Addr {
457 let octets = self.ipv4_addr.octets();
458 Ipv4Addr::new(octets[0], octets[1], 0, 0)
459 }
460
461 pub fn extract_subnet_8(&self) -> Ipv4Addr {
463 let octets = self.ipv4_addr.octets();
464 Ipv4Addr::new(octets[0], 0, 0, 0)
465 }
466
467 pub fn age_secs(&self) -> u64 {
469 let now = SystemTime::now()
470 .duration_since(UNIX_EPOCH)
471 .map(|d| d.as_secs())
472 .unwrap_or(0);
473 now.saturating_sub(self.timestamp_secs)
474 }
475
476 pub fn is_expired(&self, max_age: Duration) -> bool {
478 self.age_secs() > max_age.as_secs()
479 }
480}
481
482#[derive(Debug)]
484pub struct IPDiversityEnforcer {
485 config: IPDiversityConfig,
486 subnet_64_counts: HashMap<Ipv6Addr, usize>,
488 subnet_48_counts: HashMap<Ipv6Addr, usize>,
489 subnet_32_counts: HashMap<Ipv6Addr, usize>,
490 ipv4_32_counts: HashMap<Ipv4Addr, usize>, ipv4_24_counts: HashMap<Ipv4Addr, usize>, ipv4_16_counts: HashMap<Ipv4Addr, usize>, asn_counts: HashMap<u32, usize>,
496 country_counts: HashMap<String, usize>,
497 geo_provider: Option<Arc<dyn GeoProvider + Send + Sync>>,
498 network_size: usize,
500}
501
502impl IPDiversityEnforcer {
503 pub fn new(config: IPDiversityConfig) -> Self {
505 Self {
506 config,
507 subnet_64_counts: HashMap::new(),
509 subnet_48_counts: HashMap::new(),
510 subnet_32_counts: HashMap::new(),
511 ipv4_32_counts: HashMap::new(),
513 ipv4_24_counts: HashMap::new(),
514 ipv4_16_counts: HashMap::new(),
515 asn_counts: HashMap::new(),
517 country_counts: HashMap::new(),
518 geo_provider: None,
519 network_size: 0,
520 }
521 }
522
523 pub fn with_geo_provider(
525 config: IPDiversityConfig,
526 provider: Arc<dyn GeoProvider + Send + Sync>,
527 ) -> Self {
528 let mut s = Self::new(config);
529 s.geo_provider = Some(provider);
530 s
531 }
532
533 pub fn analyze_ip(&self, ipv6_addr: Ipv6Addr) -> Result<IPAnalysis> {
535 let subnet_64 = Self::extract_subnet_prefix(ipv6_addr, 64);
536 let subnet_48 = Self::extract_subnet_prefix(ipv6_addr, 48);
537 let subnet_32 = Self::extract_subnet_prefix(ipv6_addr, 32);
538
539 let (asn, country, is_hosting_provider, is_vpn_provider) =
541 if let Some(p) = &self.geo_provider {
542 let info = p.lookup(ipv6_addr);
543 (
544 info.asn,
545 info.country,
546 info.is_hosting_provider,
547 info.is_vpn_provider,
548 )
549 } else {
550 (None, None, false, false)
551 };
552
553 let reputation_score = 0.5;
555
556 Ok(IPAnalysis {
557 subnet_64,
558 subnet_48,
559 subnet_32,
560 asn,
561 country,
562 is_hosting_provider,
563 is_vpn_provider,
564 reputation_score,
565 })
566 }
567
568 pub fn can_accept_node(&self, ip_analysis: &IPAnalysis) -> bool {
570 let (limit_64, limit_48, limit_32, limit_asn) =
572 if ip_analysis.is_hosting_provider || ip_analysis.is_vpn_provider {
573 (
575 std::cmp::max(1, self.config.max_nodes_per_64 / 2),
576 std::cmp::max(1, self.config.max_nodes_per_48 / 2),
577 std::cmp::max(1, self.config.max_nodes_per_32 / 2),
578 std::cmp::max(1, self.config.max_nodes_per_asn / 2),
579 )
580 } else {
581 (
583 self.config.max_nodes_per_64,
584 self.config.max_nodes_per_48,
585 self.config.max_nodes_per_32,
586 self.config.max_nodes_per_asn,
587 )
588 };
589
590 if let Some(&count) = self.subnet_64_counts.get(&ip_analysis.subnet_64)
592 && count >= limit_64
593 {
594 return false;
595 }
596
597 if let Some(&count) = self.subnet_48_counts.get(&ip_analysis.subnet_48)
599 && count >= limit_48
600 {
601 return false;
602 }
603
604 if let Some(&count) = self.subnet_32_counts.get(&ip_analysis.subnet_32)
606 && count >= limit_32
607 {
608 return false;
609 }
610
611 if let Some(asn) = ip_analysis.asn
613 && let Some(&count) = self.asn_counts.get(&asn)
614 && count >= limit_asn
615 {
616 return false;
617 }
618
619 true
620 }
621
622 pub fn add_node(&mut self, ip_analysis: &IPAnalysis) -> Result<()> {
624 if !self.can_accept_node(ip_analysis) {
625 return Err(anyhow!("IP diversity limits exceeded"));
626 }
627
628 *self
630 .subnet_64_counts
631 .entry(ip_analysis.subnet_64)
632 .or_insert(0) += 1;
633 *self
634 .subnet_48_counts
635 .entry(ip_analysis.subnet_48)
636 .or_insert(0) += 1;
637 *self
638 .subnet_32_counts
639 .entry(ip_analysis.subnet_32)
640 .or_insert(0) += 1;
641
642 if let Some(asn) = ip_analysis.asn {
643 *self.asn_counts.entry(asn).or_insert(0) += 1;
644 }
645
646 if let Some(ref country) = ip_analysis.country {
647 *self.country_counts.entry(country.clone()).or_insert(0) += 1;
648 }
649
650 Ok(())
651 }
652
653 pub fn remove_node(&mut self, ip_analysis: &IPAnalysis) {
655 if let Some(count) = self.subnet_64_counts.get_mut(&ip_analysis.subnet_64) {
656 *count = count.saturating_sub(1);
657 if *count == 0 {
658 self.subnet_64_counts.remove(&ip_analysis.subnet_64);
659 }
660 }
661
662 if let Some(count) = self.subnet_48_counts.get_mut(&ip_analysis.subnet_48) {
663 *count = count.saturating_sub(1);
664 if *count == 0 {
665 self.subnet_48_counts.remove(&ip_analysis.subnet_48);
666 }
667 }
668
669 if let Some(count) = self.subnet_32_counts.get_mut(&ip_analysis.subnet_32) {
670 *count = count.saturating_sub(1);
671 if *count == 0 {
672 self.subnet_32_counts.remove(&ip_analysis.subnet_32);
673 }
674 }
675
676 if let Some(asn) = ip_analysis.asn
677 && let Some(count) = self.asn_counts.get_mut(&asn)
678 {
679 *count = count.saturating_sub(1);
680 if *count == 0 {
681 self.asn_counts.remove(&asn);
682 }
683 }
684
685 if let Some(ref country) = ip_analysis.country
686 && let Some(count) = self.country_counts.get_mut(country)
687 {
688 *count = count.saturating_sub(1);
689 if *count == 0 {
690 self.country_counts.remove(country);
691 }
692 }
693 }
694
695 pub fn extract_subnet_prefix(addr: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
697 let octets = addr.octets();
698 let mut subnet = [0u8; 16];
699
700 let bytes_to_copy = (prefix_len / 8) as usize;
701 let remaining_bits = prefix_len % 8;
702
703 if bytes_to_copy < 16 {
705 subnet[..bytes_to_copy].copy_from_slice(&octets[..bytes_to_copy]);
706 } else {
707 subnet.copy_from_slice(&octets);
708 }
709
710 if remaining_bits > 0 && bytes_to_copy < 16 {
712 let mask = 0xFF << (8 - remaining_bits);
713 subnet[bytes_to_copy] = octets[bytes_to_copy] & mask;
714 }
715
716 Ipv6Addr::from(subnet)
717 }
718
719 pub fn get_diversity_stats(&self) -> DiversityStats {
721 DiversityStats {
722 total_64_subnets: self.subnet_64_counts.len(),
723 total_48_subnets: self.subnet_48_counts.len(),
724 total_32_subnets: self.subnet_32_counts.len(),
725 total_asns: self.asn_counts.len(),
726 total_countries: self.country_counts.len(),
727 max_nodes_per_64: self.subnet_64_counts.values().max().copied().unwrap_or(0),
728 max_nodes_per_48: self.subnet_48_counts.values().max().copied().unwrap_or(0),
729 max_nodes_per_32: self.subnet_32_counts.values().max().copied().unwrap_or(0),
730 total_ipv4_32: self.ipv4_32_counts.len(),
732 total_ipv4_24_subnets: self.ipv4_24_counts.len(),
733 total_ipv4_16_subnets: self.ipv4_16_counts.len(),
734 max_nodes_per_ipv4_32: self.ipv4_32_counts.values().max().copied().unwrap_or(0),
735 max_nodes_per_ipv4_24: self.ipv4_24_counts.values().max().copied().unwrap_or(0),
736 max_nodes_per_ipv4_16: self.ipv4_16_counts.values().max().copied().unwrap_or(0),
737 }
738 }
739
740 pub fn set_network_size(&mut self, size: usize) {
744 self.network_size = size;
745 }
746
747 pub fn get_network_size(&self) -> usize {
749 self.network_size
750 }
751
752 pub fn get_per_ip_limit(&self) -> usize {
755 let fraction_limit =
756 (self.network_size as f64 * self.config.max_network_fraction).floor() as usize;
757 std::cmp::min(self.config.max_per_ip_cap, std::cmp::max(1, fraction_limit))
758 }
759
760 fn extract_ipv4_subnet_24(addr: Ipv4Addr) -> Ipv4Addr {
762 let octets = addr.octets();
763 Ipv4Addr::new(octets[0], octets[1], octets[2], 0)
764 }
765
766 fn extract_ipv4_subnet_16(addr: Ipv4Addr) -> Ipv4Addr {
768 let octets = addr.octets();
769 Ipv4Addr::new(octets[0], octets[1], 0, 0)
770 }
771
772 fn extract_ipv4_subnet_8(addr: Ipv4Addr) -> Ipv4Addr {
774 let octets = addr.octets();
775 Ipv4Addr::new(octets[0], 0, 0, 0)
776 }
777
778 pub fn analyze_ipv4(&self, ipv4_addr: Ipv4Addr) -> Result<IPv4Analysis> {
780 let subnet_24 = Self::extract_ipv4_subnet_24(ipv4_addr);
781 let subnet_16 = Self::extract_ipv4_subnet_16(ipv4_addr);
782 let subnet_8 = Self::extract_ipv4_subnet_8(ipv4_addr);
783
784 let asn = None;
787 let country = None;
788 let is_hosting_provider = false;
789 let is_vpn_provider = false;
790 let reputation_score = 0.5;
791
792 Ok(IPv4Analysis {
793 ip_addr: ipv4_addr,
794 subnet_24,
795 subnet_16,
796 subnet_8,
797 asn,
798 country,
799 is_hosting_provider,
800 is_vpn_provider,
801 reputation_score,
802 })
803 }
804
805 pub fn analyze_unified(&self, addr: std::net::IpAddr) -> Result<UnifiedIPAnalysis> {
807 match addr {
808 std::net::IpAddr::V4(ipv4) => {
809 let analysis = self.analyze_ipv4(ipv4)?;
810 Ok(UnifiedIPAnalysis::IPv4(analysis))
811 }
812 std::net::IpAddr::V6(ipv6) => {
813 let analysis = self.analyze_ip(ipv6)?;
814 Ok(UnifiedIPAnalysis::IPv6(analysis))
815 }
816 }
817 }
818
819 pub fn can_accept_unified(&self, analysis: &UnifiedIPAnalysis) -> bool {
821 match analysis {
822 UnifiedIPAnalysis::IPv4(ipv4_analysis) => self.can_accept_ipv4(ipv4_analysis),
823 UnifiedIPAnalysis::IPv6(ipv6_analysis) => self.can_accept_node(ipv6_analysis),
824 }
825 }
826
827 fn can_accept_ipv4(&self, analysis: &IPv4Analysis) -> bool {
829 let per_ip_limit = self.get_per_ip_limit();
831
832 let limit_32 = per_ip_limit;
834 let limit_24 = std::cmp::min(self.config.max_nodes_per_ipv4_24, per_ip_limit * 3);
835 let limit_16 = std::cmp::min(self.config.max_nodes_per_ipv4_16, per_ip_limit * 10);
836
837 let (limit_32, limit_24, limit_16) =
839 if analysis.is_hosting_provider || analysis.is_vpn_provider {
840 (
841 std::cmp::max(1, limit_32 / 2),
842 std::cmp::max(1, limit_24 / 2),
843 std::cmp::max(1, limit_16 / 2),
844 )
845 } else {
846 (limit_32, limit_24, limit_16)
847 };
848
849 if let Some(&count) = self.ipv4_32_counts.get(&analysis.ip_addr)
851 && count >= limit_32
852 {
853 return false;
854 }
855
856 if let Some(&count) = self.ipv4_24_counts.get(&analysis.subnet_24)
858 && count >= limit_24
859 {
860 return false;
861 }
862
863 if let Some(&count) = self.ipv4_16_counts.get(&analysis.subnet_16)
865 && count >= limit_16
866 {
867 return false;
868 }
869
870 if let Some(asn) = analysis.asn
872 && let Some(&count) = self.asn_counts.get(&asn)
873 && count >= self.config.max_nodes_per_asn
874 {
875 return false;
876 }
877
878 true
879 }
880
881 pub fn add_unified(&mut self, analysis: &UnifiedIPAnalysis) -> Result<()> {
883 match analysis {
884 UnifiedIPAnalysis::IPv4(ipv4_analysis) => self.add_ipv4(ipv4_analysis),
885 UnifiedIPAnalysis::IPv6(ipv6_analysis) => self.add_node(ipv6_analysis),
886 }
887 }
888
889 fn add_ipv4(&mut self, analysis: &IPv4Analysis) -> Result<()> {
891 if !self.can_accept_ipv4(analysis) {
892 return Err(anyhow!("IPv4 diversity limits exceeded"));
893 }
894
895 *self.ipv4_32_counts.entry(analysis.ip_addr).or_insert(0) += 1;
897 *self.ipv4_24_counts.entry(analysis.subnet_24).or_insert(0) += 1;
898 *self.ipv4_16_counts.entry(analysis.subnet_16).or_insert(0) += 1;
899
900 if let Some(asn) = analysis.asn {
901 *self.asn_counts.entry(asn).or_insert(0) += 1;
902 }
903
904 if let Some(ref country) = analysis.country {
905 *self.country_counts.entry(country.clone()).or_insert(0) += 1;
906 }
907
908 Ok(())
909 }
910
911 pub fn remove_unified(&mut self, analysis: &UnifiedIPAnalysis) {
913 match analysis {
914 UnifiedIPAnalysis::IPv4(ipv4_analysis) => self.remove_ipv4(ipv4_analysis),
915 UnifiedIPAnalysis::IPv6(ipv6_analysis) => self.remove_node(ipv6_analysis),
916 }
917 }
918
919 fn remove_ipv4(&mut self, analysis: &IPv4Analysis) {
921 if let Some(count) = self.ipv4_32_counts.get_mut(&analysis.ip_addr) {
922 *count = count.saturating_sub(1);
923 if *count == 0 {
924 self.ipv4_32_counts.remove(&analysis.ip_addr);
925 }
926 }
927
928 if let Some(count) = self.ipv4_24_counts.get_mut(&analysis.subnet_24) {
929 *count = count.saturating_sub(1);
930 if *count == 0 {
931 self.ipv4_24_counts.remove(&analysis.subnet_24);
932 }
933 }
934
935 if let Some(count) = self.ipv4_16_counts.get_mut(&analysis.subnet_16) {
936 *count = count.saturating_sub(1);
937 if *count == 0 {
938 self.ipv4_16_counts.remove(&analysis.subnet_16);
939 }
940 }
941
942 if let Some(asn) = analysis.asn
943 && let Some(count) = self.asn_counts.get_mut(&asn)
944 {
945 *count = count.saturating_sub(1);
946 if *count == 0 {
947 self.asn_counts.remove(&asn);
948 }
949 }
950
951 if let Some(ref country) = analysis.country
952 && let Some(count) = self.country_counts.get_mut(country)
953 {
954 *count = count.saturating_sub(1);
955 if *count == 0 {
956 self.country_counts.remove(country);
957 }
958 }
959 }
960}
961
962pub trait GeoProvider: std::fmt::Debug {
964 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo;
965}
966
967#[derive(Debug, Clone)]
969pub struct GeoInfo {
970 pub asn: Option<u32>,
971 pub country: Option<String>,
972 pub is_hosting_provider: bool,
973 pub is_vpn_provider: bool,
974}
975
976#[derive(Debug)]
978pub struct CachedGeoProvider<P: GeoProvider> {
979 inner: P,
980 cache: parking_lot::RwLock<HashMap<Ipv6Addr, GeoInfo>>,
981}
982
983impl<P: GeoProvider> CachedGeoProvider<P> {
984 pub fn new(inner: P) -> Self {
985 Self {
986 inner,
987 cache: parking_lot::RwLock::new(HashMap::new()),
988 }
989 }
990}
991
992impl<P: GeoProvider> GeoProvider for CachedGeoProvider<P> {
993 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo {
994 if let Some(info) = self.cache.read().get(&ip).cloned() {
995 return info;
996 }
997 let info = self.inner.lookup(ip);
998 self.cache.write().insert(ip, info.clone());
999 info
1000 }
1001}
1002
1003#[derive(Debug)]
1005pub struct StubGeoProvider;
1006impl GeoProvider for StubGeoProvider {
1007 fn lookup(&self, _ip: Ipv6Addr) -> GeoInfo {
1008 GeoInfo {
1009 asn: None,
1010 country: None,
1011 is_hosting_provider: false,
1012 is_vpn_provider: false,
1013 }
1014 }
1015}
1016
1017#[derive(Debug, Clone, Serialize, Deserialize)]
1019pub struct DiversityStats {
1020 pub total_64_subnets: usize,
1023 pub total_48_subnets: usize,
1025 pub total_32_subnets: usize,
1027 pub max_nodes_per_64: usize,
1029 pub max_nodes_per_48: usize,
1031 pub max_nodes_per_32: usize,
1033
1034 pub total_ipv4_32: usize,
1037 pub total_ipv4_24_subnets: usize,
1039 pub total_ipv4_16_subnets: usize,
1041 pub max_nodes_per_ipv4_32: usize,
1043 pub max_nodes_per_ipv4_24: usize,
1045 pub max_nodes_per_ipv4_16: usize,
1047
1048 pub total_asns: usize,
1051 pub total_countries: usize,
1053}
1054
1055#[derive(Debug)]
1057pub struct ReputationManager {
1058 reputations: HashMap<PeerId, NodeReputation>,
1059 reputation_decay: f64,
1060 min_reputation: f64,
1061}
1062
1063impl ReputationManager {
1064 pub fn new(reputation_decay: f64, min_reputation: f64) -> Self {
1066 Self {
1067 reputations: HashMap::new(),
1068 reputation_decay,
1069 min_reputation,
1070 }
1071 }
1072
1073 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<&NodeReputation> {
1075 self.reputations.get(peer_id)
1076 }
1077
1078 pub fn update_reputation(&mut self, peer_id: &PeerId, success: bool, response_time: Duration) {
1080 let reputation =
1081 self.reputations
1082 .entry(peer_id.clone())
1083 .or_insert_with(|| NodeReputation {
1084 peer_id: peer_id.clone(),
1085 response_rate: 0.5,
1086 response_time: Duration::from_millis(500),
1087 consistency_score: 0.5,
1088 uptime_estimate: Duration::from_secs(0),
1089 routing_accuracy: 0.5,
1090 last_seen: SystemTime::now(),
1091 interaction_count: 0,
1092 });
1093
1094 let alpha = 0.3; if success {
1098 reputation.response_rate = reputation.response_rate * (1.0 - alpha) + alpha;
1099 } else {
1100 reputation.response_rate *= 1.0 - alpha;
1101 }
1102
1103 let response_time_ms = response_time.as_millis() as f64;
1105 let current_response_ms = reputation.response_time.as_millis() as f64;
1106 let new_response_ms = current_response_ms * (1.0 - alpha) + response_time_ms * alpha;
1107 reputation.response_time = Duration::from_millis(new_response_ms as u64);
1108
1109 reputation.last_seen = SystemTime::now();
1110 reputation.interaction_count += 1;
1111 }
1112
1113 pub fn apply_decay(&mut self) {
1115 let now = SystemTime::now();
1116
1117 self.reputations.retain(|_, reputation| {
1118 if let Ok(elapsed) = now.duration_since(reputation.last_seen) {
1119 let decay_factor = (-elapsed.as_secs_f64() / 3600.0 * self.reputation_decay).exp();
1121 reputation.response_rate *= decay_factor;
1122 reputation.consistency_score *= decay_factor;
1123 reputation.routing_accuracy *= decay_factor;
1124
1125 reputation.response_rate > self.min_reputation / 10.0
1127 } else {
1128 true
1129 }
1130 });
1131 }
1132}
1133
1134#[cfg(test)]
1137mod tests {
1138 use super::*;
1139 use crate::quantum_crypto::generate_ml_dsa_keypair;
1140
1141 fn create_test_keypair() -> (MlDsaPublicKey, MlDsaSecretKey) {
1142 generate_ml_dsa_keypair().expect("Failed to generate test keypair")
1143 }
1144
1145 fn create_test_ipv6() -> Ipv6Addr {
1146 Ipv6Addr::new(
1147 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334,
1148 )
1149 }
1150
1151 fn create_test_diversity_config() -> IPDiversityConfig {
1152 IPDiversityConfig {
1153 max_nodes_per_64: 1,
1155 max_nodes_per_48: 3,
1156 max_nodes_per_32: 10,
1157 max_nodes_per_ipv4_32: 1,
1159 max_nodes_per_ipv4_24: 3,
1160 max_nodes_per_ipv4_16: 10,
1161 max_per_ip_cap: 50,
1163 max_network_fraction: 0.005,
1164 max_nodes_per_asn: 20,
1166 enable_geolocation_check: true,
1167 min_geographic_diversity: 3,
1168 }
1169 }
1170
1171 #[test]
1172 fn test_ipv6_node_id_generation() -> Result<()> {
1173 let (public_key, secret_key) = create_test_keypair();
1174 let ipv6_addr = create_test_ipv6();
1175
1176 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1177
1178 assert_eq!(node_id.ipv6_addr, ipv6_addr);
1179 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);
1183 assert!(node_id.timestamp_secs > 0);
1184
1185 Ok(())
1186 }
1187
1188 #[test]
1189 fn test_ipv6_node_id_verification() -> Result<()> {
1190 let (public_key, secret_key) = create_test_keypair();
1191 let ipv6_addr = create_test_ipv6();
1192
1193 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1194 let is_valid = node_id.verify()?;
1195
1196 assert!(is_valid);
1197
1198 Ok(())
1199 }
1200
1201 #[test]
1202 fn test_ipv6_node_id_verification_fails_with_wrong_data() -> Result<()> {
1203 let (public_key, secret_key) = create_test_keypair();
1204 let ipv6_addr = create_test_ipv6();
1205
1206 let mut node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1207
1208 node_id.node_id[0] ^= 0xFF;
1210 let is_valid = node_id.verify()?;
1211 assert!(!is_valid);
1212
1213 let mut node_id2 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1215 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
1217 assert!(!is_valid2);
1218
1219 let mut node_id3 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1221 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
1223 assert!(!is_valid3);
1224
1225 Ok(())
1226 }
1227
1228 #[test]
1229 fn test_ipv6_subnet_extraction() -> Result<()> {
1230 let (public_key, secret_key) = create_test_keypair();
1231 let ipv6_addr = Ipv6Addr::new(
1232 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1233 );
1234
1235 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1236
1237 let subnet_64 = node_id.extract_subnet_64();
1239 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
1240 assert_eq!(subnet_64, expected_64);
1241
1242 let subnet_48 = node_id.extract_subnet_48();
1244 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
1245 assert_eq!(subnet_48, expected_48);
1246
1247 let subnet_32 = node_id.extract_subnet_32();
1249 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
1250 assert_eq!(subnet_32, expected_32);
1251
1252 Ok(())
1253 }
1254
1255 fn create_test_ipv4() -> Ipv4Addr {
1258 Ipv4Addr::new(192, 168, 1, 100)
1259 }
1260
1261 #[test]
1262 fn test_ipv4_node_id_generation() -> Result<()> {
1263 let (public_key, secret_key) = create_test_keypair();
1264 let ipv4_addr = create_test_ipv4();
1265
1266 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1267
1268 assert_eq!(node_id.ipv4_addr, ipv4_addr);
1269 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);
1273 assert!(node_id.timestamp_secs > 0);
1274
1275 Ok(())
1276 }
1277
1278 #[test]
1279 fn test_ipv4_node_id_verification() -> Result<()> {
1280 let (public_key, secret_key) = create_test_keypair();
1281 let ipv4_addr = create_test_ipv4();
1282
1283 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1284 let is_valid = node_id.verify()?;
1285
1286 assert!(is_valid);
1287
1288 Ok(())
1289 }
1290
1291 #[test]
1292 fn test_ipv4_node_id_verification_fails_with_wrong_data() -> Result<()> {
1293 let (public_key, secret_key) = create_test_keypair();
1294 let ipv4_addr = create_test_ipv4();
1295
1296 let mut node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1297
1298 node_id.node_id[0] ^= 0xFF;
1300 let is_valid = node_id.verify()?;
1301 assert!(!is_valid);
1302
1303 let mut node_id2 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1305 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
1307 assert!(!is_valid2);
1308
1309 let mut node_id3 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1311 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
1313 assert!(!is_valid3);
1314
1315 Ok(())
1316 }
1317
1318 #[test]
1319 fn test_ipv4_subnet_extraction() -> Result<()> {
1320 let (public_key, secret_key) = create_test_keypair();
1321 let ipv4_addr = Ipv4Addr::new(192, 168, 42, 100);
1322
1323 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1324
1325 let subnet_24 = node_id.extract_subnet_24();
1327 let expected_24 = Ipv4Addr::new(192, 168, 42, 0);
1328 assert_eq!(subnet_24, expected_24);
1329
1330 let subnet_16 = node_id.extract_subnet_16();
1332 let expected_16 = Ipv4Addr::new(192, 168, 0, 0);
1333 assert_eq!(subnet_16, expected_16);
1334
1335 let subnet_8 = node_id.extract_subnet_8();
1337 let expected_8 = Ipv4Addr::new(192, 0, 0, 0);
1338 assert_eq!(subnet_8, expected_8);
1339
1340 Ok(())
1341 }
1342
1343 #[test]
1344 fn test_ipv4_node_id_age() -> Result<()> {
1345 let (public_key, secret_key) = create_test_keypair();
1346 let ipv4_addr = create_test_ipv4();
1347
1348 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1349
1350 assert!(node_id.age_secs() < 5);
1352
1353 assert!(!node_id.is_expired(Duration::from_secs(3600)));
1355
1356 assert!(!node_id.is_expired(Duration::from_secs(0)));
1359
1360 Ok(())
1361 }
1362
1363 #[test]
1364 fn test_ipv4_different_addresses_different_node_ids() -> Result<()> {
1365 let (public_key, secret_key) = create_test_keypair();
1366 let addr1 = Ipv4Addr::new(192, 168, 1, 1);
1367 let addr2 = Ipv4Addr::new(192, 168, 1, 2);
1368
1369 let node_id1 = IPv4NodeID::generate(addr1, &secret_key, &public_key)?;
1370 let node_id2 = IPv4NodeID::generate(addr2, &secret_key, &public_key)?;
1371
1372 assert_ne!(node_id1.node_id, node_id2.node_id);
1374
1375 assert!(node_id1.verify()?);
1377 assert!(node_id2.verify()?);
1378
1379 Ok(())
1380 }
1381
1382 #[test]
1385 fn test_ip_diversity_config_default() {
1386 let config = IPDiversityConfig::default();
1387
1388 assert_eq!(config.max_nodes_per_64, 1);
1389 assert_eq!(config.max_nodes_per_48, 3);
1390 assert_eq!(config.max_nodes_per_32, 10);
1391 assert_eq!(config.max_nodes_per_asn, 20);
1392 assert!(config.enable_geolocation_check);
1393 assert_eq!(config.min_geographic_diversity, 3);
1394 }
1395
1396 #[test]
1397 fn test_ip_diversity_enforcer_creation() {
1398 let config = create_test_diversity_config();
1399 let enforcer = IPDiversityEnforcer::new(config.clone());
1400
1401 assert_eq!(enforcer.config.max_nodes_per_64, config.max_nodes_per_64);
1402 assert_eq!(enforcer.subnet_64_counts.len(), 0);
1403 assert_eq!(enforcer.subnet_48_counts.len(), 0);
1404 assert_eq!(enforcer.subnet_32_counts.len(), 0);
1405 }
1406
1407 #[test]
1408 fn test_ip_analysis() -> Result<()> {
1409 let config = create_test_diversity_config();
1410 let enforcer = IPDiversityEnforcer::new(config);
1411
1412 let ipv6_addr = create_test_ipv6();
1413 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1414
1415 assert_eq!(
1416 analysis.subnet_64,
1417 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 64)
1418 );
1419 assert_eq!(
1420 analysis.subnet_48,
1421 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 48)
1422 );
1423 assert_eq!(
1424 analysis.subnet_32,
1425 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 32)
1426 );
1427 assert!(analysis.asn.is_none()); assert!(analysis.country.is_none()); assert!(!analysis.is_hosting_provider);
1430 assert!(!analysis.is_vpn_provider);
1431 assert_eq!(analysis.reputation_score, 0.5);
1432
1433 Ok(())
1434 }
1435
1436 #[test]
1437 fn test_can_accept_node_basic() -> Result<()> {
1438 let config = create_test_diversity_config();
1439 let enforcer = IPDiversityEnforcer::new(config);
1440
1441 let ipv6_addr = create_test_ipv6();
1442 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1443
1444 assert!(enforcer.can_accept_node(&analysis));
1446
1447 Ok(())
1448 }
1449
1450 #[test]
1451 fn test_add_and_remove_node() -> Result<()> {
1452 let config = create_test_diversity_config();
1453 let mut enforcer = IPDiversityEnforcer::new(config);
1454
1455 let ipv6_addr = create_test_ipv6();
1456 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1457
1458 enforcer.add_node(&analysis)?;
1460 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), Some(&1));
1461 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), Some(&1));
1462 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), Some(&1));
1463
1464 enforcer.remove_node(&analysis);
1466 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), None);
1467 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), None);
1468 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), None);
1469
1470 Ok(())
1471 }
1472
1473 #[test]
1474 fn test_diversity_limits_enforcement() -> Result<()> {
1475 let config = create_test_diversity_config();
1476 let mut enforcer = IPDiversityEnforcer::new(config);
1477
1478 let ipv6_addr1 = Ipv6Addr::new(
1479 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1480 );
1481 let ipv6_addr2 = Ipv6Addr::new(
1482 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7335,
1483 ); let analysis1 = enforcer.analyze_ip(ipv6_addr1)?;
1486 let analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1487
1488 assert!(enforcer.can_accept_node(&analysis1));
1490 enforcer.add_node(&analysis1)?;
1491
1492 assert!(!enforcer.can_accept_node(&analysis2));
1494
1495 let result = enforcer.add_node(&analysis2);
1497 assert!(result.is_err());
1498 assert!(
1499 result
1500 .unwrap_err()
1501 .to_string()
1502 .contains("IP diversity limits exceeded")
1503 );
1504
1505 Ok(())
1506 }
1507
1508 #[test]
1509 fn test_hosting_provider_stricter_limits() -> Result<()> {
1510 let config = IPDiversityConfig {
1511 max_nodes_per_64: 4, max_nodes_per_48: 8,
1513 ..create_test_diversity_config()
1514 };
1515 let mut enforcer = IPDiversityEnforcer::new(config);
1516
1517 let ipv6_addr = create_test_ipv6();
1518 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1519 analysis.is_hosting_provider = true;
1520
1521 assert!(enforcer.can_accept_node(&analysis));
1523 enforcer.add_node(&analysis)?;
1524
1525 let ipv6_addr2 = Ipv6Addr::new(
1527 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7335,
1528 );
1529 let mut analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1530 analysis2.is_hosting_provider = true;
1531 analysis2.subnet_64 = analysis.subnet_64; assert!(enforcer.can_accept_node(&analysis2));
1534 enforcer.add_node(&analysis2)?;
1535
1536 let ipv6_addr3 = Ipv6Addr::new(
1538 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7336,
1539 );
1540 let mut analysis3 = enforcer.analyze_ip(ipv6_addr3)?;
1541 analysis3.is_hosting_provider = true;
1542 analysis3.subnet_64 = analysis.subnet_64; assert!(!enforcer.can_accept_node(&analysis3));
1545
1546 Ok(())
1547 }
1548
1549 #[test]
1550 fn test_diversity_stats() -> Result<()> {
1551 let config = create_test_diversity_config();
1552 let mut enforcer = IPDiversityEnforcer::new(config);
1553
1554 let addresses = [
1556 Ipv6Addr::new(
1557 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1558 ),
1559 Ipv6Addr::new(
1560 0x2001, 0xdb8, 0x85a4, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1561 ), Ipv6Addr::new(
1563 0x2002, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1564 ), ];
1566
1567 for addr in addresses {
1568 let analysis = enforcer.analyze_ip(addr)?;
1569 enforcer.add_node(&analysis)?;
1570 }
1571
1572 let stats = enforcer.get_diversity_stats();
1573 assert_eq!(stats.total_64_subnets, 3);
1574 assert_eq!(stats.total_48_subnets, 3);
1575 assert_eq!(stats.total_32_subnets, 2); assert_eq!(stats.max_nodes_per_64, 1);
1577 assert_eq!(stats.max_nodes_per_48, 1);
1578 assert_eq!(stats.max_nodes_per_32, 2); Ok(())
1581 }
1582
1583 #[test]
1584 fn test_extract_subnet_prefix() {
1585 let addr = Ipv6Addr::new(
1586 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1587 );
1588
1589 let prefix_64 = IPDiversityEnforcer::extract_subnet_prefix(addr, 64);
1591 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
1592 assert_eq!(prefix_64, expected_64);
1593
1594 let prefix_48 = IPDiversityEnforcer::extract_subnet_prefix(addr, 48);
1596 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
1597 assert_eq!(prefix_48, expected_48);
1598
1599 let prefix_32 = IPDiversityEnforcer::extract_subnet_prefix(addr, 32);
1601 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
1602 assert_eq!(prefix_32, expected_32);
1603
1604 let prefix_56 = IPDiversityEnforcer::extract_subnet_prefix(addr, 56);
1606 let expected_56 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1200, 0, 0, 0, 0);
1607 assert_eq!(prefix_56, expected_56);
1608
1609 let prefix_128 = IPDiversityEnforcer::extract_subnet_prefix(addr, 128);
1611 assert_eq!(prefix_128, addr);
1612 }
1613
1614 #[test]
1615 fn test_reputation_manager_creation() {
1616 let manager = ReputationManager::new(0.1, 0.1);
1617 assert_eq!(manager.reputation_decay, 0.1);
1618 assert_eq!(manager.min_reputation, 0.1);
1619 assert_eq!(manager.reputations.len(), 0);
1620 }
1621
1622 #[test]
1623 fn test_reputation_get_nonexistent() {
1624 let manager = ReputationManager::new(0.1, 0.1);
1625 let peer_id = "test_peer".to_string();
1626
1627 let reputation = manager.get_reputation(&peer_id);
1628 assert!(reputation.is_none());
1629 }
1630
1631 #[test]
1632 fn test_reputation_update_creates_entry() {
1633 let mut manager = ReputationManager::new(0.1, 0.1);
1634 let peer_id = "test_peer".to_string();
1635
1636 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1637
1638 let reputation = manager.get_reputation(&peer_id);
1639 assert!(reputation.is_some());
1640
1641 let rep = reputation.unwrap();
1642 assert_eq!(rep.peer_id, peer_id);
1643 assert!(rep.response_rate > 0.5); assert_eq!(rep.interaction_count, 1);
1645 }
1646
1647 #[test]
1648 fn test_reputation_update_success_improves_rate() {
1649 let mut manager = ReputationManager::new(0.1, 0.1);
1650 let peer_id = "test_peer".to_string();
1651
1652 for _ in 0..15 {
1654 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1655 }
1656
1657 let reputation = manager.get_reputation(&peer_id).unwrap();
1658 assert!(reputation.response_rate > 0.85); assert_eq!(reputation.interaction_count, 15);
1660 }
1661
1662 #[test]
1663 fn test_reputation_update_failure_decreases_rate() {
1664 let mut manager = ReputationManager::new(0.1, 0.1);
1665 let peer_id = "test_peer".to_string();
1666
1667 for _ in 0..15 {
1669 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1670 }
1671
1672 let reputation = manager.get_reputation(&peer_id).unwrap();
1673 assert!(reputation.response_rate < 0.15); assert_eq!(reputation.interaction_count, 15);
1675 }
1676
1677 #[test]
1678 fn test_reputation_response_time_tracking() {
1679 let mut manager = ReputationManager::new(0.1, 0.1);
1680 let peer_id = "test_peer".to_string();
1681
1682 manager.update_reputation(&peer_id, true, Duration::from_millis(200));
1684
1685 let reputation = manager.get_reputation(&peer_id).unwrap();
1686 assert!(reputation.response_time.as_millis() > 200);
1688 assert!(reputation.response_time.as_millis() < 500);
1689 }
1690
1691 #[test]
1692 fn test_reputation_decay() {
1693 let mut manager = ReputationManager::new(1.0, 0.01); let peer_id = "test_peer".to_string();
1695
1696 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1698
1699 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1701 reputation.last_seen = SystemTime::now() - Duration::from_secs(7200); }
1703
1704 let original_rate = manager.get_reputation(&peer_id).unwrap().response_rate;
1705
1706 manager.apply_decay();
1708
1709 let reputation = manager.get_reputation(&peer_id);
1710 if let Some(rep) = reputation {
1711 assert!(rep.response_rate < original_rate);
1713 } }
1715
1716 #[test]
1717 fn test_reputation_decay_removes_low_reputation() {
1718 let mut manager = ReputationManager::new(0.1, 0.5); let peer_id = "test_peer".to_string();
1720
1721 for _ in 0..10 {
1723 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1724 }
1725
1726 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1728 reputation.last_seen = SystemTime::now() - Duration::from_secs(3600); reputation.response_rate = 0.01; }
1731
1732 manager.apply_decay();
1734
1735 assert!(manager.get_reputation(&peer_id).is_none());
1737 }
1738
1739 #[test]
1740 fn test_security_types_keypair() {
1741 let (public_key, secret_key) =
1742 generate_ml_dsa_keypair().expect("Failed to generate keypair");
1743
1744 let public_key_bytes = public_key.as_bytes();
1745 assert_eq!(public_key_bytes.len(), 1952); let message = b"test message";
1748 let signature = ml_dsa_sign(&secret_key, message).expect("Failed to sign message");
1749 assert_eq!(signature.as_bytes().len(), 3309); assert!(ml_dsa_verify(&public_key, message, &signature).is_ok());
1753 }
1754
1755 #[test]
1756 fn test_node_reputation_structure() {
1757 let peer_id = "test_peer".to_string();
1758 let reputation = NodeReputation {
1759 peer_id: peer_id.clone(),
1760 response_rate: 0.85,
1761 response_time: Duration::from_millis(150),
1762 consistency_score: 0.9,
1763 uptime_estimate: Duration::from_secs(86400),
1764 routing_accuracy: 0.8,
1765 last_seen: SystemTime::now(),
1766 interaction_count: 42,
1767 };
1768
1769 assert_eq!(reputation.peer_id, peer_id);
1770 assert_eq!(reputation.response_rate, 0.85);
1771 assert_eq!(reputation.response_time, Duration::from_millis(150));
1772 assert_eq!(reputation.consistency_score, 0.9);
1773 assert_eq!(reputation.uptime_estimate, Duration::from_secs(86400));
1774 assert_eq!(reputation.routing_accuracy, 0.8);
1775 assert_eq!(reputation.interaction_count, 42);
1776 }
1777
1778 #[test]
1779 fn test_ip_analysis_structure() {
1780 let analysis = IPAnalysis {
1781 subnet_64: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0),
1782 subnet_48: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0),
1783 subnet_32: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1784 asn: Some(64512),
1785 country: Some("US".to_string()),
1786 is_hosting_provider: true,
1787 is_vpn_provider: false,
1788 reputation_score: 0.75,
1789 };
1790
1791 assert_eq!(analysis.asn, Some(64512));
1792 assert_eq!(analysis.country, Some("US".to_string()));
1793 assert!(analysis.is_hosting_provider);
1794 assert!(!analysis.is_vpn_provider);
1795 assert_eq!(analysis.reputation_score, 0.75);
1796 }
1797
1798 #[test]
1799 fn test_diversity_stats_structure() {
1800 let stats = DiversityStats {
1801 total_64_subnets: 100,
1803 total_48_subnets: 50,
1804 total_32_subnets: 25,
1805 max_nodes_per_64: 1,
1806 max_nodes_per_48: 3,
1807 max_nodes_per_32: 10,
1808 total_ipv4_32: 80,
1810 total_ipv4_24_subnets: 40,
1811 total_ipv4_16_subnets: 20,
1812 max_nodes_per_ipv4_32: 1,
1813 max_nodes_per_ipv4_24: 3,
1814 max_nodes_per_ipv4_16: 10,
1815 total_asns: 15,
1817 total_countries: 8,
1818 };
1819
1820 assert_eq!(stats.total_64_subnets, 100);
1822 assert_eq!(stats.total_48_subnets, 50);
1823 assert_eq!(stats.total_32_subnets, 25);
1824 assert_eq!(stats.max_nodes_per_64, 1);
1825 assert_eq!(stats.max_nodes_per_48, 3);
1826 assert_eq!(stats.max_nodes_per_32, 10);
1827 assert_eq!(stats.total_ipv4_32, 80);
1829 assert_eq!(stats.total_ipv4_24_subnets, 40);
1830 assert_eq!(stats.total_ipv4_16_subnets, 20);
1831 assert_eq!(stats.max_nodes_per_ipv4_32, 1);
1832 assert_eq!(stats.max_nodes_per_ipv4_24, 3);
1833 assert_eq!(stats.max_nodes_per_ipv4_16, 10);
1834 assert_eq!(stats.total_asns, 15);
1836 assert_eq!(stats.total_countries, 8);
1837 }
1838
1839 #[test]
1840 fn test_multiple_same_subnet_nodes() -> Result<()> {
1841 let config = IPDiversityConfig {
1842 max_nodes_per_64: 3, max_nodes_per_48: 5,
1844 max_nodes_per_32: 10,
1845 ..create_test_diversity_config()
1846 };
1847 let mut enforcer = IPDiversityEnforcer::new(config);
1848
1849 let _base_addr = Ipv6Addr::new(
1850 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x0000,
1851 );
1852
1853 for i in 1..=3 {
1855 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, i);
1856 let analysis = enforcer.analyze_ip(addr)?;
1857 assert!(enforcer.can_accept_node(&analysis));
1858 enforcer.add_node(&analysis)?;
1859 }
1860
1861 let addr4 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 4);
1863 let analysis4 = enforcer.analyze_ip(addr4)?;
1864 assert!(!enforcer.can_accept_node(&analysis4));
1865
1866 let stats = enforcer.get_diversity_stats();
1867 assert_eq!(stats.total_64_subnets, 1);
1868 assert_eq!(stats.max_nodes_per_64, 3);
1869
1870 Ok(())
1871 }
1872
1873 #[test]
1874 fn test_asn_and_country_tracking() -> Result<()> {
1875 let config = create_test_diversity_config();
1876 let mut enforcer = IPDiversityEnforcer::new(config);
1877
1878 let ipv6_addr = create_test_ipv6();
1880 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1881 analysis.asn = Some(64512);
1882 analysis.country = Some("US".to_string());
1883
1884 enforcer.add_node(&analysis)?;
1885
1886 assert_eq!(enforcer.asn_counts.get(&64512), Some(&1));
1887 assert_eq!(enforcer.country_counts.get("US"), Some(&1));
1888
1889 enforcer.remove_node(&analysis);
1891 assert!(!enforcer.asn_counts.contains_key(&64512));
1892 assert!(!enforcer.country_counts.contains_key("US"));
1893
1894 Ok(())
1895 }
1896
1897 #[test]
1898 fn test_reputation_mixed_interactions() {
1899 let mut manager = ReputationManager::new(0.1, 0.1);
1900 let peer_id = "test_peer".to_string();
1901
1902 for i in 0..15 {
1904 let success = i % 3 != 0; manager.update_reputation(&peer_id, success, Duration::from_millis(100 + i * 10));
1906 }
1907
1908 let reputation = manager.get_reputation(&peer_id).unwrap();
1909 assert!(reputation.response_rate > 0.55);
1912 assert!(reputation.response_rate < 0.85);
1913 assert_eq!(reputation.interaction_count, 15);
1914 }
1915}