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, Serialize, Deserialize)]
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
962#[cfg(test)]
963impl IPDiversityEnforcer {
964 pub fn config(&self) -> &IPDiversityConfig {
965 &self.config
966 }
967}
968
969pub trait GeoProvider: std::fmt::Debug {
971 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo;
972}
973
974#[derive(Debug, Clone)]
976pub struct GeoInfo {
977 pub asn: Option<u32>,
978 pub country: Option<String>,
979 pub is_hosting_provider: bool,
980 pub is_vpn_provider: bool,
981}
982
983#[derive(Debug)]
985pub struct CachedGeoProvider<P: GeoProvider> {
986 inner: P,
987 cache: parking_lot::RwLock<HashMap<Ipv6Addr, GeoInfo>>,
988}
989
990impl<P: GeoProvider> CachedGeoProvider<P> {
991 pub fn new(inner: P) -> Self {
992 Self {
993 inner,
994 cache: parking_lot::RwLock::new(HashMap::new()),
995 }
996 }
997}
998
999impl<P: GeoProvider> GeoProvider for CachedGeoProvider<P> {
1000 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo {
1001 if let Some(info) = self.cache.read().get(&ip).cloned() {
1002 return info;
1003 }
1004 let info = self.inner.lookup(ip);
1005 self.cache.write().insert(ip, info.clone());
1006 info
1007 }
1008}
1009
1010#[derive(Debug)]
1012pub struct StubGeoProvider;
1013impl GeoProvider for StubGeoProvider {
1014 fn lookup(&self, _ip: Ipv6Addr) -> GeoInfo {
1015 GeoInfo {
1016 asn: None,
1017 country: None,
1018 is_hosting_provider: false,
1019 is_vpn_provider: false,
1020 }
1021 }
1022}
1023
1024#[derive(Debug, Clone, Serialize, Deserialize)]
1026pub struct DiversityStats {
1027 pub total_64_subnets: usize,
1030 pub total_48_subnets: usize,
1032 pub total_32_subnets: usize,
1034 pub max_nodes_per_64: usize,
1036 pub max_nodes_per_48: usize,
1038 pub max_nodes_per_32: usize,
1040
1041 pub total_ipv4_32: usize,
1044 pub total_ipv4_24_subnets: usize,
1046 pub total_ipv4_16_subnets: usize,
1048 pub max_nodes_per_ipv4_32: usize,
1050 pub max_nodes_per_ipv4_24: usize,
1052 pub max_nodes_per_ipv4_16: usize,
1054
1055 pub total_asns: usize,
1058 pub total_countries: usize,
1060}
1061
1062#[derive(Debug)]
1064pub struct ReputationManager {
1065 reputations: HashMap<PeerId, NodeReputation>,
1066 reputation_decay: f64,
1067 min_reputation: f64,
1068}
1069
1070impl ReputationManager {
1071 pub fn new(reputation_decay: f64, min_reputation: f64) -> Self {
1073 Self {
1074 reputations: HashMap::new(),
1075 reputation_decay,
1076 min_reputation,
1077 }
1078 }
1079
1080 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<&NodeReputation> {
1082 self.reputations.get(peer_id)
1083 }
1084
1085 pub fn update_reputation(&mut self, peer_id: &PeerId, success: bool, response_time: Duration) {
1087 let reputation =
1088 self.reputations
1089 .entry(peer_id.clone())
1090 .or_insert_with(|| NodeReputation {
1091 peer_id: peer_id.clone(),
1092 response_rate: 0.5,
1093 response_time: Duration::from_millis(500),
1094 consistency_score: 0.5,
1095 uptime_estimate: Duration::from_secs(0),
1096 routing_accuracy: 0.5,
1097 last_seen: SystemTime::now(),
1098 interaction_count: 0,
1099 });
1100
1101 let alpha = 0.3; if success {
1105 reputation.response_rate = reputation.response_rate * (1.0 - alpha) + alpha;
1106 } else {
1107 reputation.response_rate *= 1.0 - alpha;
1108 }
1109
1110 let response_time_ms = response_time.as_millis() as f64;
1112 let current_response_ms = reputation.response_time.as_millis() as f64;
1113 let new_response_ms = current_response_ms * (1.0 - alpha) + response_time_ms * alpha;
1114 reputation.response_time = Duration::from_millis(new_response_ms as u64);
1115
1116 reputation.last_seen = SystemTime::now();
1117 reputation.interaction_count += 1;
1118 }
1119
1120 pub fn apply_decay(&mut self) {
1122 let now = SystemTime::now();
1123
1124 self.reputations.retain(|_, reputation| {
1125 if let Ok(elapsed) = now.duration_since(reputation.last_seen) {
1126 let decay_factor = (-elapsed.as_secs_f64() / 3600.0 * self.reputation_decay).exp();
1128 reputation.response_rate *= decay_factor;
1129 reputation.consistency_score *= decay_factor;
1130 reputation.routing_accuracy *= decay_factor;
1131
1132 reputation.response_rate > self.min_reputation / 10.0
1134 } else {
1135 true
1136 }
1137 });
1138 }
1139}
1140
1141#[cfg(test)]
1144mod tests {
1145 use super::*;
1146 use crate::quantum_crypto::generate_ml_dsa_keypair;
1147
1148 fn create_test_keypair() -> (MlDsaPublicKey, MlDsaSecretKey) {
1149 generate_ml_dsa_keypair().expect("Failed to generate test keypair")
1150 }
1151
1152 fn create_test_ipv6() -> Ipv6Addr {
1153 Ipv6Addr::new(
1154 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334,
1155 )
1156 }
1157
1158 fn create_test_diversity_config() -> IPDiversityConfig {
1159 IPDiversityConfig {
1160 max_nodes_per_64: 1,
1162 max_nodes_per_48: 3,
1163 max_nodes_per_32: 10,
1164 max_nodes_per_ipv4_32: 1,
1166 max_nodes_per_ipv4_24: 3,
1167 max_nodes_per_ipv4_16: 10,
1168 max_per_ip_cap: 50,
1170 max_network_fraction: 0.005,
1171 max_nodes_per_asn: 20,
1173 enable_geolocation_check: true,
1174 min_geographic_diversity: 3,
1175 }
1176 }
1177
1178 #[test]
1179 fn test_ipv6_node_id_generation() -> Result<()> {
1180 let (public_key, secret_key) = create_test_keypair();
1181 let ipv6_addr = create_test_ipv6();
1182
1183 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1184
1185 assert_eq!(node_id.ipv6_addr, ipv6_addr);
1186 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);
1190 assert!(node_id.timestamp_secs > 0);
1191
1192 Ok(())
1193 }
1194
1195 #[test]
1196 fn test_ipv6_node_id_verification() -> Result<()> {
1197 let (public_key, secret_key) = create_test_keypair();
1198 let ipv6_addr = create_test_ipv6();
1199
1200 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1201 let is_valid = node_id.verify()?;
1202
1203 assert!(is_valid);
1204
1205 Ok(())
1206 }
1207
1208 #[test]
1209 fn test_ipv6_node_id_verification_fails_with_wrong_data() -> Result<()> {
1210 let (public_key, secret_key) = create_test_keypair();
1211 let ipv6_addr = create_test_ipv6();
1212
1213 let mut node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1214
1215 node_id.node_id[0] ^= 0xFF;
1217 let is_valid = node_id.verify()?;
1218 assert!(!is_valid);
1219
1220 let mut node_id2 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1222 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
1224 assert!(!is_valid2);
1225
1226 let mut node_id3 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1228 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
1230 assert!(!is_valid3);
1231
1232 Ok(())
1233 }
1234
1235 #[test]
1236 fn test_ipv6_subnet_extraction() -> Result<()> {
1237 let (public_key, secret_key) = create_test_keypair();
1238 let ipv6_addr = Ipv6Addr::new(
1239 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1240 );
1241
1242 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1243
1244 let subnet_64 = node_id.extract_subnet_64();
1246 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
1247 assert_eq!(subnet_64, expected_64);
1248
1249 let subnet_48 = node_id.extract_subnet_48();
1251 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
1252 assert_eq!(subnet_48, expected_48);
1253
1254 let subnet_32 = node_id.extract_subnet_32();
1256 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
1257 assert_eq!(subnet_32, expected_32);
1258
1259 Ok(())
1260 }
1261
1262 fn create_test_ipv4() -> Ipv4Addr {
1265 Ipv4Addr::new(192, 168, 1, 100)
1266 }
1267
1268 #[test]
1269 fn test_ipv4_node_id_generation() -> Result<()> {
1270 let (public_key, secret_key) = create_test_keypair();
1271 let ipv4_addr = create_test_ipv4();
1272
1273 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1274
1275 assert_eq!(node_id.ipv4_addr, ipv4_addr);
1276 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);
1280 assert!(node_id.timestamp_secs > 0);
1281
1282 Ok(())
1283 }
1284
1285 #[test]
1286 fn test_ipv4_node_id_verification() -> Result<()> {
1287 let (public_key, secret_key) = create_test_keypair();
1288 let ipv4_addr = create_test_ipv4();
1289
1290 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1291 let is_valid = node_id.verify()?;
1292
1293 assert!(is_valid);
1294
1295 Ok(())
1296 }
1297
1298 #[test]
1299 fn test_ipv4_node_id_verification_fails_with_wrong_data() -> Result<()> {
1300 let (public_key, secret_key) = create_test_keypair();
1301 let ipv4_addr = create_test_ipv4();
1302
1303 let mut node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1304
1305 node_id.node_id[0] ^= 0xFF;
1307 let is_valid = node_id.verify()?;
1308 assert!(!is_valid);
1309
1310 let mut node_id2 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1312 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
1314 assert!(!is_valid2);
1315
1316 let mut node_id3 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1318 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
1320 assert!(!is_valid3);
1321
1322 Ok(())
1323 }
1324
1325 #[test]
1326 fn test_ipv4_subnet_extraction() -> Result<()> {
1327 let (public_key, secret_key) = create_test_keypair();
1328 let ipv4_addr = Ipv4Addr::new(192, 168, 42, 100);
1329
1330 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1331
1332 let subnet_24 = node_id.extract_subnet_24();
1334 let expected_24 = Ipv4Addr::new(192, 168, 42, 0);
1335 assert_eq!(subnet_24, expected_24);
1336
1337 let subnet_16 = node_id.extract_subnet_16();
1339 let expected_16 = Ipv4Addr::new(192, 168, 0, 0);
1340 assert_eq!(subnet_16, expected_16);
1341
1342 let subnet_8 = node_id.extract_subnet_8();
1344 let expected_8 = Ipv4Addr::new(192, 0, 0, 0);
1345 assert_eq!(subnet_8, expected_8);
1346
1347 Ok(())
1348 }
1349
1350 #[test]
1351 fn test_ipv4_node_id_age() -> Result<()> {
1352 let (public_key, secret_key) = create_test_keypair();
1353 let ipv4_addr = create_test_ipv4();
1354
1355 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1356
1357 assert!(node_id.age_secs() < 5);
1359
1360 assert!(!node_id.is_expired(Duration::from_secs(3600)));
1362
1363 assert!(!node_id.is_expired(Duration::from_secs(0)));
1366
1367 Ok(())
1368 }
1369
1370 #[test]
1371 fn test_ipv4_different_addresses_different_node_ids() -> Result<()> {
1372 let (public_key, secret_key) = create_test_keypair();
1373 let addr1 = Ipv4Addr::new(192, 168, 1, 1);
1374 let addr2 = Ipv4Addr::new(192, 168, 1, 2);
1375
1376 let node_id1 = IPv4NodeID::generate(addr1, &secret_key, &public_key)?;
1377 let node_id2 = IPv4NodeID::generate(addr2, &secret_key, &public_key)?;
1378
1379 assert_ne!(node_id1.node_id, node_id2.node_id);
1381
1382 assert!(node_id1.verify()?);
1384 assert!(node_id2.verify()?);
1385
1386 Ok(())
1387 }
1388
1389 #[test]
1392 fn test_ip_diversity_config_default() {
1393 let config = IPDiversityConfig::default();
1394
1395 assert_eq!(config.max_nodes_per_64, 1);
1396 assert_eq!(config.max_nodes_per_48, 3);
1397 assert_eq!(config.max_nodes_per_32, 10);
1398 assert_eq!(config.max_nodes_per_asn, 20);
1399 assert!(config.enable_geolocation_check);
1400 assert_eq!(config.min_geographic_diversity, 3);
1401 }
1402
1403 #[test]
1404 fn test_ip_diversity_enforcer_creation() {
1405 let config = create_test_diversity_config();
1406 let enforcer = IPDiversityEnforcer::new(config.clone());
1407
1408 assert_eq!(enforcer.config.max_nodes_per_64, config.max_nodes_per_64);
1409 assert_eq!(enforcer.subnet_64_counts.len(), 0);
1410 assert_eq!(enforcer.subnet_48_counts.len(), 0);
1411 assert_eq!(enforcer.subnet_32_counts.len(), 0);
1412 }
1413
1414 #[test]
1415 fn test_ip_analysis() -> Result<()> {
1416 let config = create_test_diversity_config();
1417 let enforcer = IPDiversityEnforcer::new(config);
1418
1419 let ipv6_addr = create_test_ipv6();
1420 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1421
1422 assert_eq!(
1423 analysis.subnet_64,
1424 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 64)
1425 );
1426 assert_eq!(
1427 analysis.subnet_48,
1428 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 48)
1429 );
1430 assert_eq!(
1431 analysis.subnet_32,
1432 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 32)
1433 );
1434 assert!(analysis.asn.is_none()); assert!(analysis.country.is_none()); assert!(!analysis.is_hosting_provider);
1437 assert!(!analysis.is_vpn_provider);
1438 assert_eq!(analysis.reputation_score, 0.5);
1439
1440 Ok(())
1441 }
1442
1443 #[test]
1444 fn test_can_accept_node_basic() -> Result<()> {
1445 let config = create_test_diversity_config();
1446 let enforcer = IPDiversityEnforcer::new(config);
1447
1448 let ipv6_addr = create_test_ipv6();
1449 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1450
1451 assert!(enforcer.can_accept_node(&analysis));
1453
1454 Ok(())
1455 }
1456
1457 #[test]
1458 fn test_add_and_remove_node() -> Result<()> {
1459 let config = create_test_diversity_config();
1460 let mut enforcer = IPDiversityEnforcer::new(config);
1461
1462 let ipv6_addr = create_test_ipv6();
1463 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1464
1465 enforcer.add_node(&analysis)?;
1467 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), Some(&1));
1468 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), Some(&1));
1469 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), Some(&1));
1470
1471 enforcer.remove_node(&analysis);
1473 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), None);
1474 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), None);
1475 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), None);
1476
1477 Ok(())
1478 }
1479
1480 #[test]
1481 fn test_diversity_limits_enforcement() -> Result<()> {
1482 let config = create_test_diversity_config();
1483 let mut enforcer = IPDiversityEnforcer::new(config);
1484
1485 let ipv6_addr1 = Ipv6Addr::new(
1486 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1487 );
1488 let ipv6_addr2 = Ipv6Addr::new(
1489 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7335,
1490 ); let analysis1 = enforcer.analyze_ip(ipv6_addr1)?;
1493 let analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1494
1495 assert!(enforcer.can_accept_node(&analysis1));
1497 enforcer.add_node(&analysis1)?;
1498
1499 assert!(!enforcer.can_accept_node(&analysis2));
1501
1502 let result = enforcer.add_node(&analysis2);
1504 assert!(result.is_err());
1505 assert!(
1506 result
1507 .unwrap_err()
1508 .to_string()
1509 .contains("IP diversity limits exceeded")
1510 );
1511
1512 Ok(())
1513 }
1514
1515 #[test]
1516 fn test_hosting_provider_stricter_limits() -> Result<()> {
1517 let config = IPDiversityConfig {
1518 max_nodes_per_64: 4, max_nodes_per_48: 8,
1520 ..create_test_diversity_config()
1521 };
1522 let mut enforcer = IPDiversityEnforcer::new(config);
1523
1524 let ipv6_addr = create_test_ipv6();
1525 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1526 analysis.is_hosting_provider = true;
1527
1528 assert!(enforcer.can_accept_node(&analysis));
1530 enforcer.add_node(&analysis)?;
1531
1532 let ipv6_addr2 = Ipv6Addr::new(
1534 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7335,
1535 );
1536 let mut analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1537 analysis2.is_hosting_provider = true;
1538 analysis2.subnet_64 = analysis.subnet_64; assert!(enforcer.can_accept_node(&analysis2));
1541 enforcer.add_node(&analysis2)?;
1542
1543 let ipv6_addr3 = Ipv6Addr::new(
1545 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7336,
1546 );
1547 let mut analysis3 = enforcer.analyze_ip(ipv6_addr3)?;
1548 analysis3.is_hosting_provider = true;
1549 analysis3.subnet_64 = analysis.subnet_64; assert!(!enforcer.can_accept_node(&analysis3));
1552
1553 Ok(())
1554 }
1555
1556 #[test]
1557 fn test_diversity_stats() -> Result<()> {
1558 let config = create_test_diversity_config();
1559 let mut enforcer = IPDiversityEnforcer::new(config);
1560
1561 let addresses = [
1563 Ipv6Addr::new(
1564 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1565 ),
1566 Ipv6Addr::new(
1567 0x2001, 0xdb8, 0x85a4, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1568 ), Ipv6Addr::new(
1570 0x2002, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1571 ), ];
1573
1574 for addr in addresses {
1575 let analysis = enforcer.analyze_ip(addr)?;
1576 enforcer.add_node(&analysis)?;
1577 }
1578
1579 let stats = enforcer.get_diversity_stats();
1580 assert_eq!(stats.total_64_subnets, 3);
1581 assert_eq!(stats.total_48_subnets, 3);
1582 assert_eq!(stats.total_32_subnets, 2); assert_eq!(stats.max_nodes_per_64, 1);
1584 assert_eq!(stats.max_nodes_per_48, 1);
1585 assert_eq!(stats.max_nodes_per_32, 2); Ok(())
1588 }
1589
1590 #[test]
1591 fn test_extract_subnet_prefix() {
1592 let addr = Ipv6Addr::new(
1593 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1594 );
1595
1596 let prefix_64 = IPDiversityEnforcer::extract_subnet_prefix(addr, 64);
1598 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
1599 assert_eq!(prefix_64, expected_64);
1600
1601 let prefix_48 = IPDiversityEnforcer::extract_subnet_prefix(addr, 48);
1603 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
1604 assert_eq!(prefix_48, expected_48);
1605
1606 let prefix_32 = IPDiversityEnforcer::extract_subnet_prefix(addr, 32);
1608 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
1609 assert_eq!(prefix_32, expected_32);
1610
1611 let prefix_56 = IPDiversityEnforcer::extract_subnet_prefix(addr, 56);
1613 let expected_56 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1200, 0, 0, 0, 0);
1614 assert_eq!(prefix_56, expected_56);
1615
1616 let prefix_128 = IPDiversityEnforcer::extract_subnet_prefix(addr, 128);
1618 assert_eq!(prefix_128, addr);
1619 }
1620
1621 #[test]
1622 fn test_reputation_manager_creation() {
1623 let manager = ReputationManager::new(0.1, 0.1);
1624 assert_eq!(manager.reputation_decay, 0.1);
1625 assert_eq!(manager.min_reputation, 0.1);
1626 assert_eq!(manager.reputations.len(), 0);
1627 }
1628
1629 #[test]
1630 fn test_reputation_get_nonexistent() {
1631 let manager = ReputationManager::new(0.1, 0.1);
1632 let peer_id = "test_peer".to_string();
1633
1634 let reputation = manager.get_reputation(&peer_id);
1635 assert!(reputation.is_none());
1636 }
1637
1638 #[test]
1639 fn test_reputation_update_creates_entry() {
1640 let mut manager = ReputationManager::new(0.1, 0.1);
1641 let peer_id = "test_peer".to_string();
1642
1643 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1644
1645 let reputation = manager.get_reputation(&peer_id);
1646 assert!(reputation.is_some());
1647
1648 let rep = reputation.unwrap();
1649 assert_eq!(rep.peer_id, peer_id);
1650 assert!(rep.response_rate > 0.5); assert_eq!(rep.interaction_count, 1);
1652 }
1653
1654 #[test]
1655 fn test_reputation_update_success_improves_rate() {
1656 let mut manager = ReputationManager::new(0.1, 0.1);
1657 let peer_id = "test_peer".to_string();
1658
1659 for _ in 0..15 {
1661 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1662 }
1663
1664 let reputation = manager.get_reputation(&peer_id).unwrap();
1665 assert!(reputation.response_rate > 0.85); assert_eq!(reputation.interaction_count, 15);
1667 }
1668
1669 #[test]
1670 fn test_reputation_update_failure_decreases_rate() {
1671 let mut manager = ReputationManager::new(0.1, 0.1);
1672 let peer_id = "test_peer".to_string();
1673
1674 for _ in 0..15 {
1676 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1677 }
1678
1679 let reputation = manager.get_reputation(&peer_id).unwrap();
1680 assert!(reputation.response_rate < 0.15); assert_eq!(reputation.interaction_count, 15);
1682 }
1683
1684 #[test]
1685 fn test_reputation_response_time_tracking() {
1686 let mut manager = ReputationManager::new(0.1, 0.1);
1687 let peer_id = "test_peer".to_string();
1688
1689 manager.update_reputation(&peer_id, true, Duration::from_millis(200));
1691
1692 let reputation = manager.get_reputation(&peer_id).unwrap();
1693 assert!(reputation.response_time.as_millis() > 200);
1695 assert!(reputation.response_time.as_millis() < 500);
1696 }
1697
1698 #[test]
1699 fn test_reputation_decay() {
1700 let mut manager = ReputationManager::new(1.0, 0.01); let peer_id = "test_peer".to_string();
1702
1703 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1705
1706 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1708 reputation.last_seen = SystemTime::now() - Duration::from_secs(7200); }
1710
1711 let original_rate = manager.get_reputation(&peer_id).unwrap().response_rate;
1712
1713 manager.apply_decay();
1715
1716 let reputation = manager.get_reputation(&peer_id);
1717 if let Some(rep) = reputation {
1718 assert!(rep.response_rate < original_rate);
1720 } }
1722
1723 #[test]
1724 fn test_reputation_decay_removes_low_reputation() {
1725 let mut manager = ReputationManager::new(0.1, 0.5); let peer_id = "test_peer".to_string();
1727
1728 for _ in 0..10 {
1730 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1731 }
1732
1733 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1735 reputation.last_seen = SystemTime::now() - Duration::from_secs(3600); reputation.response_rate = 0.01; }
1738
1739 manager.apply_decay();
1741
1742 assert!(manager.get_reputation(&peer_id).is_none());
1744 }
1745
1746 #[test]
1747 fn test_security_types_keypair() {
1748 let (public_key, secret_key) =
1749 generate_ml_dsa_keypair().expect("Failed to generate keypair");
1750
1751 let public_key_bytes = public_key.as_bytes();
1752 assert_eq!(public_key_bytes.len(), 1952); let message = b"test message";
1755 let signature = ml_dsa_sign(&secret_key, message).expect("Failed to sign message");
1756 assert_eq!(signature.as_bytes().len(), 3309); assert!(ml_dsa_verify(&public_key, message, &signature).is_ok());
1760 }
1761
1762 #[test]
1763 fn test_node_reputation_structure() {
1764 let peer_id = "test_peer".to_string();
1765 let reputation = NodeReputation {
1766 peer_id: peer_id.clone(),
1767 response_rate: 0.85,
1768 response_time: Duration::from_millis(150),
1769 consistency_score: 0.9,
1770 uptime_estimate: Duration::from_secs(86400),
1771 routing_accuracy: 0.8,
1772 last_seen: SystemTime::now(),
1773 interaction_count: 42,
1774 };
1775
1776 assert_eq!(reputation.peer_id, peer_id);
1777 assert_eq!(reputation.response_rate, 0.85);
1778 assert_eq!(reputation.response_time, Duration::from_millis(150));
1779 assert_eq!(reputation.consistency_score, 0.9);
1780 assert_eq!(reputation.uptime_estimate, Duration::from_secs(86400));
1781 assert_eq!(reputation.routing_accuracy, 0.8);
1782 assert_eq!(reputation.interaction_count, 42);
1783 }
1784
1785 #[test]
1786 fn test_ip_analysis_structure() {
1787 let analysis = IPAnalysis {
1788 subnet_64: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0),
1789 subnet_48: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0),
1790 subnet_32: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1791 asn: Some(64512),
1792 country: Some("US".to_string()),
1793 is_hosting_provider: true,
1794 is_vpn_provider: false,
1795 reputation_score: 0.75,
1796 };
1797
1798 assert_eq!(analysis.asn, Some(64512));
1799 assert_eq!(analysis.country, Some("US".to_string()));
1800 assert!(analysis.is_hosting_provider);
1801 assert!(!analysis.is_vpn_provider);
1802 assert_eq!(analysis.reputation_score, 0.75);
1803 }
1804
1805 #[test]
1806 fn test_diversity_stats_structure() {
1807 let stats = DiversityStats {
1808 total_64_subnets: 100,
1810 total_48_subnets: 50,
1811 total_32_subnets: 25,
1812 max_nodes_per_64: 1,
1813 max_nodes_per_48: 3,
1814 max_nodes_per_32: 10,
1815 total_ipv4_32: 80,
1817 total_ipv4_24_subnets: 40,
1818 total_ipv4_16_subnets: 20,
1819 max_nodes_per_ipv4_32: 1,
1820 max_nodes_per_ipv4_24: 3,
1821 max_nodes_per_ipv4_16: 10,
1822 total_asns: 15,
1824 total_countries: 8,
1825 };
1826
1827 assert_eq!(stats.total_64_subnets, 100);
1829 assert_eq!(stats.total_48_subnets, 50);
1830 assert_eq!(stats.total_32_subnets, 25);
1831 assert_eq!(stats.max_nodes_per_64, 1);
1832 assert_eq!(stats.max_nodes_per_48, 3);
1833 assert_eq!(stats.max_nodes_per_32, 10);
1834 assert_eq!(stats.total_ipv4_32, 80);
1836 assert_eq!(stats.total_ipv4_24_subnets, 40);
1837 assert_eq!(stats.total_ipv4_16_subnets, 20);
1838 assert_eq!(stats.max_nodes_per_ipv4_32, 1);
1839 assert_eq!(stats.max_nodes_per_ipv4_24, 3);
1840 assert_eq!(stats.max_nodes_per_ipv4_16, 10);
1841 assert_eq!(stats.total_asns, 15);
1843 assert_eq!(stats.total_countries, 8);
1844 }
1845
1846 #[test]
1847 fn test_multiple_same_subnet_nodes() -> Result<()> {
1848 let config = IPDiversityConfig {
1849 max_nodes_per_64: 3, max_nodes_per_48: 5,
1851 max_nodes_per_32: 10,
1852 ..create_test_diversity_config()
1853 };
1854 let mut enforcer = IPDiversityEnforcer::new(config);
1855
1856 let _base_addr = Ipv6Addr::new(
1857 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x0000,
1858 );
1859
1860 for i in 1..=3 {
1862 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, i);
1863 let analysis = enforcer.analyze_ip(addr)?;
1864 assert!(enforcer.can_accept_node(&analysis));
1865 enforcer.add_node(&analysis)?;
1866 }
1867
1868 let addr4 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 4);
1870 let analysis4 = enforcer.analyze_ip(addr4)?;
1871 assert!(!enforcer.can_accept_node(&analysis4));
1872
1873 let stats = enforcer.get_diversity_stats();
1874 assert_eq!(stats.total_64_subnets, 1);
1875 assert_eq!(stats.max_nodes_per_64, 3);
1876
1877 Ok(())
1878 }
1879
1880 #[test]
1881 fn test_asn_and_country_tracking() -> Result<()> {
1882 let config = create_test_diversity_config();
1883 let mut enforcer = IPDiversityEnforcer::new(config);
1884
1885 let ipv6_addr = create_test_ipv6();
1887 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1888 analysis.asn = Some(64512);
1889 analysis.country = Some("US".to_string());
1890
1891 enforcer.add_node(&analysis)?;
1892
1893 assert_eq!(enforcer.asn_counts.get(&64512), Some(&1));
1894 assert_eq!(enforcer.country_counts.get("US"), Some(&1));
1895
1896 enforcer.remove_node(&analysis);
1898 assert!(!enforcer.asn_counts.contains_key(&64512));
1899 assert!(!enforcer.country_counts.contains_key("US"));
1900
1901 Ok(())
1902 }
1903
1904 #[test]
1905 fn test_reputation_mixed_interactions() {
1906 let mut manager = ReputationManager::new(0.1, 0.1);
1907 let peer_id = "test_peer".to_string();
1908
1909 for i in 0..15 {
1911 let success = i % 3 != 0; manager.update_reputation(&peer_id, success, Duration::from_millis(100 + i * 10));
1913 }
1914
1915 let reputation = manager.get_reputation(&peer_id).unwrap();
1916 assert!(reputation.response_rate > 0.55);
1919 assert!(reputation.response_rate < 0.85);
1920 assert_eq!(reputation.interaction_count, 15);
1921 }
1922}