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 lru::LruCache;
26use serde::{Deserialize, Serialize};
27use sha2::{Digest, Sha256};
28use std::collections::HashMap;
29use std::fmt::Debug;
30use std::net::{Ipv4Addr, Ipv6Addr};
31use std::num::NonZeroUsize;
32use std::time::{Duration, SystemTime, UNIX_EPOCH};
33
34use std::sync::Arc;
35
36const MAX_SUBNET_TRACKING: usize = 50_000;
38
39pub trait NodeIpAddress: Debug + Clone + Send + Sync + 'static {
45 fn octets_vec(&self) -> Vec<u8>;
47}
48
49impl NodeIpAddress for Ipv6Addr {
50 fn octets_vec(&self) -> Vec<u8> {
51 self.octets().to_vec()
52 }
53}
54
55impl NodeIpAddress for Ipv4Addr {
56 fn octets_vec(&self) -> Vec<u8> {
57 self.octets().to_vec()
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct GenericIpNodeID<A: NodeIpAddress> {
71 pub node_id: Vec<u8>,
73 pub ip_addr: A,
75 pub public_key: Vec<u8>,
77 pub signature: Vec<u8>,
79 pub timestamp_secs: u64,
81 pub salt: Vec<u8>,
83}
84
85impl<A: NodeIpAddress> GenericIpNodeID<A> {
86 const SIGNATURE_LENGTH: usize = 3309;
88
89 pub fn generate(ip_addr: A, secret: &MlDsaSecretKey, public: &MlDsaPublicKey) -> Result<Self> {
91 let mut rng = rand::thread_rng();
92 let mut salt = vec![0u8; 16];
93 rand::RngCore::fill_bytes(&mut rng, &mut salt);
94
95 let timestamp = SystemTime::now();
96 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
97 let public_key = public.as_bytes().to_vec();
98 let ip_octets = ip_addr.octets_vec();
99
100 let node_id = Self::compute_node_id(&ip_octets, &public_key, &salt, timestamp_secs);
102
103 let message_to_sign = Self::build_message(&ip_octets, &public_key, &salt, timestamp_secs);
105 let sig = ml_dsa_sign(secret, &message_to_sign)
106 .map_err(|e| anyhow!("ML-DSA sign failed: {:?}", e))?;
107 let signature = sig.0.to_vec();
108
109 Ok(Self {
110 node_id,
111 ip_addr,
112 public_key,
113 signature,
114 timestamp_secs,
115 salt,
116 })
117 }
118
119 pub fn verify(&self) -> Result<bool> {
121 let ip_octets = self.ip_addr.octets_vec();
122
123 let expected_node_id = Self::compute_node_id(
125 &ip_octets,
126 &self.public_key,
127 &self.salt,
128 self.timestamp_secs,
129 );
130
131 if expected_node_id != self.node_id {
132 return Ok(false);
133 }
134
135 let public_key = MlDsaPublicKey::from_bytes(&self.public_key)
137 .map_err(|e| anyhow!("Invalid ML-DSA public key: {:?}", e))?;
138
139 if self.signature.len() != Self::SIGNATURE_LENGTH {
140 return Ok(false);
141 }
142
143 let mut sig_bytes = [0u8; 3309];
144 sig_bytes.copy_from_slice(&self.signature);
145 let signature = MlDsaSignature(Box::new(sig_bytes));
146
147 let message_to_verify = Self::build_message(
148 &ip_octets,
149 &self.public_key,
150 &self.salt,
151 self.timestamp_secs,
152 );
153
154 let ok = ml_dsa_verify(&public_key, &message_to_verify, &signature)
155 .map_err(|e| anyhow!("ML-DSA verify error: {:?}", e))?;
156 Ok(ok)
157 }
158
159 pub fn age_secs(&self) -> u64 {
161 let now = SystemTime::now()
162 .duration_since(UNIX_EPOCH)
163 .map(|d| d.as_secs())
164 .unwrap_or(0);
165 now.saturating_sub(self.timestamp_secs)
166 }
167
168 pub fn is_expired(&self, max_age: Duration) -> bool {
170 self.age_secs() > max_age.as_secs()
171 }
172
173 #[inline]
176 fn compute_node_id(
177 ip_octets: &[u8],
178 public_key: &[u8],
179 salt: &[u8],
180 timestamp_secs: u64,
181 ) -> Vec<u8> {
182 let mut hasher = Sha256::new();
183 hasher.update(ip_octets);
184 hasher.update(public_key);
185 hasher.update(salt);
186 hasher.update(timestamp_secs.to_le_bytes());
187 hasher.finalize().to_vec()
188 }
189
190 #[inline]
191 fn build_message(
192 ip_octets: &[u8],
193 public_key: &[u8],
194 salt: &[u8],
195 timestamp_secs: u64,
196 ) -> Vec<u8> {
197 let mut message = Vec::with_capacity(ip_octets.len() + public_key.len() + salt.len() + 8);
198 message.extend_from_slice(ip_octets);
199 message.extend_from_slice(public_key);
200 message.extend_from_slice(salt);
201 message.extend_from_slice(×tamp_secs.to_le_bytes());
202 message
203 }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct IPv6NodeID {
213 pub node_id: Vec<u8>,
215 pub ipv6_addr: Ipv6Addr,
217 pub public_key: Vec<u8>,
219 pub signature: Vec<u8>,
221 pub timestamp_secs: u64,
223 pub salt: Vec<u8>,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct IPDiversityConfig {
230 pub max_nodes_per_64: usize,
233 pub max_nodes_per_48: usize,
235 pub max_nodes_per_32: usize,
237
238 pub max_nodes_per_ipv4_32: usize,
241 pub max_nodes_per_ipv4_24: usize,
243 pub max_nodes_per_ipv4_16: usize,
245
246 pub max_per_ip_cap: usize,
249 pub max_network_fraction: f64,
251
252 pub max_nodes_per_asn: usize,
255 pub enable_geolocation_check: bool,
257 pub min_geographic_diversity: usize,
259}
260
261#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
263pub struct IPAnalysis {
264 pub subnet_64: Ipv6Addr,
266 pub subnet_48: Ipv6Addr,
268 pub subnet_32: Ipv6Addr,
270 pub asn: Option<u32>,
272 pub country: Option<String>,
274 pub is_hosting_provider: bool,
276 pub is_vpn_provider: bool,
278 pub reputation_score: f64,
280}
281
282#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
284pub struct IPv4Analysis {
285 pub ip_addr: Ipv4Addr,
287 pub subnet_24: Ipv4Addr,
289 pub subnet_16: Ipv4Addr,
291 pub subnet_8: Ipv4Addr,
293 pub asn: Option<u32>,
295 pub country: Option<String>,
297 pub is_hosting_provider: bool,
299 pub is_vpn_provider: bool,
301 pub reputation_score: f64,
303}
304
305#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
307pub enum UnifiedIPAnalysis {
308 IPv4(IPv4Analysis),
310 IPv6(IPAnalysis),
312}
313
314#[derive(Debug, Clone)]
316pub struct NodeReputation {
317 pub peer_id: PeerId,
319 pub response_rate: f64,
321 pub response_time: Duration,
323 pub consistency_score: f64,
325 pub uptime_estimate: Duration,
327 pub routing_accuracy: f64,
329 pub last_seen: SystemTime,
331 pub interaction_count: u64,
333}
334
335impl Default for IPDiversityConfig {
336 fn default() -> Self {
337 Self {
338 max_nodes_per_64: 1,
340 max_nodes_per_48: 3,
341 max_nodes_per_32: 10,
342 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,
351 enable_geolocation_check: true,
352 min_geographic_diversity: 3,
353 }
354 }
355}
356
357impl IPDiversityConfig {
358 #[must_use]
369 pub fn testnet() -> Self {
370 Self {
371 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, }
387 }
388
389 #[must_use]
394 pub fn permissive() -> Self {
395 Self {
396 max_nodes_per_64: usize::MAX,
398 max_nodes_per_48: usize::MAX,
399 max_nodes_per_32: usize::MAX,
400 max_nodes_per_ipv4_32: usize::MAX,
402 max_nodes_per_ipv4_24: usize::MAX,
403 max_nodes_per_ipv4_16: usize::MAX,
404 max_per_ip_cap: usize::MAX,
406 max_network_fraction: 1.0, max_nodes_per_asn: usize::MAX,
409 enable_geolocation_check: false,
410 min_geographic_diversity: 0,
411 }
412 }
413
414 #[must_use]
416 pub fn is_relaxed(&self) -> bool {
417 self.max_nodes_per_asn > 100 || !self.enable_geolocation_check
418 }
419}
420
421impl IPv6NodeID {
422 pub fn generate(
426 ipv6_addr: Ipv6Addr,
427 secret: &MlDsaSecretKey,
428 public: &MlDsaPublicKey,
429 ) -> Result<Self> {
430 let generic = GenericIpNodeID::generate(ipv6_addr, secret, public)?;
431 Ok(Self::from_generic(generic))
432 }
433
434 pub fn verify(&self) -> Result<bool> {
436 self.to_generic().verify()
437 }
438
439 pub fn extract_subnet_64(&self) -> Ipv6Addr {
441 let octets = self.ipv6_addr.octets();
442 let mut subnet = [0u8; 16];
443 subnet[..8].copy_from_slice(&octets[..8]);
444 Ipv6Addr::from(subnet)
445 }
446
447 pub fn extract_subnet_48(&self) -> Ipv6Addr {
449 let octets = self.ipv6_addr.octets();
450 let mut subnet = [0u8; 16];
451 subnet[..6].copy_from_slice(&octets[..6]);
452 Ipv6Addr::from(subnet)
453 }
454
455 pub fn extract_subnet_32(&self) -> Ipv6Addr {
457 let octets = self.ipv6_addr.octets();
458 let mut subnet = [0u8; 16];
459 subnet[..4].copy_from_slice(&octets[..4]);
460 Ipv6Addr::from(subnet)
461 }
462
463 fn from_generic(g: GenericIpNodeID<Ipv6Addr>) -> Self {
466 Self {
467 node_id: g.node_id,
468 ipv6_addr: g.ip_addr,
469 public_key: g.public_key,
470 signature: g.signature,
471 timestamp_secs: g.timestamp_secs,
472 salt: g.salt,
473 }
474 }
475
476 fn to_generic(&self) -> GenericIpNodeID<Ipv6Addr> {
477 GenericIpNodeID {
478 node_id: self.node_id.clone(),
479 ip_addr: self.ipv6_addr,
480 public_key: self.public_key.clone(),
481 signature: self.signature.clone(),
482 timestamp_secs: self.timestamp_secs,
483 salt: self.salt.clone(),
484 }
485 }
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize)]
491pub struct IPv4NodeID {
492 pub node_id: Vec<u8>,
494 pub ipv4_addr: Ipv4Addr,
496 pub public_key: Vec<u8>,
498 pub signature: Vec<u8>,
500 pub timestamp_secs: u64,
502 pub salt: Vec<u8>,
504}
505
506impl IPv4NodeID {
507 pub fn generate(
511 ipv4_addr: Ipv4Addr,
512 secret: &MlDsaSecretKey,
513 public: &MlDsaPublicKey,
514 ) -> Result<Self> {
515 let generic = GenericIpNodeID::generate(ipv4_addr, secret, public)?;
516 Ok(Self::from_generic(generic))
517 }
518
519 pub fn verify(&self) -> Result<bool> {
521 self.to_generic().verify()
522 }
523
524 pub fn extract_subnet_24(&self) -> Ipv4Addr {
526 let octets = self.ipv4_addr.octets();
527 Ipv4Addr::new(octets[0], octets[1], octets[2], 0)
528 }
529
530 pub fn extract_subnet_16(&self) -> Ipv4Addr {
532 let octets = self.ipv4_addr.octets();
533 Ipv4Addr::new(octets[0], octets[1], 0, 0)
534 }
535
536 pub fn extract_subnet_8(&self) -> Ipv4Addr {
538 let octets = self.ipv4_addr.octets();
539 Ipv4Addr::new(octets[0], 0, 0, 0)
540 }
541
542 pub fn age_secs(&self) -> u64 {
544 self.to_generic().age_secs()
545 }
546
547 pub fn is_expired(&self, max_age: Duration) -> bool {
549 self.to_generic().is_expired(max_age)
550 }
551
552 fn from_generic(g: GenericIpNodeID<Ipv4Addr>) -> Self {
555 Self {
556 node_id: g.node_id,
557 ipv4_addr: g.ip_addr,
558 public_key: g.public_key,
559 signature: g.signature,
560 timestamp_secs: g.timestamp_secs,
561 salt: g.salt,
562 }
563 }
564
565 fn to_generic(&self) -> GenericIpNodeID<Ipv4Addr> {
566 GenericIpNodeID {
567 node_id: self.node_id.clone(),
568 ip_addr: self.ipv4_addr,
569 public_key: self.public_key.clone(),
570 signature: self.signature.clone(),
571 timestamp_secs: self.timestamp_secs,
572 salt: self.salt.clone(),
573 }
574 }
575}
576
577#[derive(Debug)]
579pub struct IPDiversityEnforcer {
580 config: IPDiversityConfig,
581 subnet_64_counts: LruCache<Ipv6Addr, usize>,
583 subnet_48_counts: LruCache<Ipv6Addr, usize>,
584 subnet_32_counts: LruCache<Ipv6Addr, usize>,
585 ipv4_32_counts: LruCache<Ipv4Addr, usize>, ipv4_24_counts: LruCache<Ipv4Addr, usize>, ipv4_16_counts: LruCache<Ipv4Addr, usize>, asn_counts: LruCache<u32, usize>,
591 country_counts: LruCache<String, usize>,
592 geo_provider: Option<Arc<dyn GeoProvider + Send + Sync>>,
593 network_size: usize,
595}
596
597impl IPDiversityEnforcer {
598 pub fn new(config: IPDiversityConfig) -> Self {
600 let cache_size = NonZeroUsize::new(MAX_SUBNET_TRACKING).unwrap_or(NonZeroUsize::MIN);
601 Self {
602 config,
603 subnet_64_counts: LruCache::new(cache_size),
605 subnet_48_counts: LruCache::new(cache_size),
606 subnet_32_counts: LruCache::new(cache_size),
607 ipv4_32_counts: LruCache::new(cache_size),
609 ipv4_24_counts: LruCache::new(cache_size),
610 ipv4_16_counts: LruCache::new(cache_size),
611 asn_counts: LruCache::new(cache_size),
613 country_counts: LruCache::new(cache_size),
614 geo_provider: None,
615 network_size: 0,
616 }
617 }
618
619 pub fn with_geo_provider(
621 config: IPDiversityConfig,
622 provider: Arc<dyn GeoProvider + Send + Sync>,
623 ) -> Self {
624 let mut s = Self::new(config);
625 s.geo_provider = Some(provider);
626 s
627 }
628
629 pub fn analyze_ip(&self, ipv6_addr: Ipv6Addr) -> Result<IPAnalysis> {
631 let subnet_64 = Self::extract_subnet_prefix(ipv6_addr, 64);
632 let subnet_48 = Self::extract_subnet_prefix(ipv6_addr, 48);
633 let subnet_32 = Self::extract_subnet_prefix(ipv6_addr, 32);
634
635 let (asn, country, is_hosting_provider, is_vpn_provider) =
637 if let Some(p) = &self.geo_provider {
638 let info = p.lookup(ipv6_addr);
639 (
640 info.asn,
641 info.country,
642 info.is_hosting_provider,
643 info.is_vpn_provider,
644 )
645 } else {
646 (None, None, false, false)
647 };
648
649 let reputation_score = 0.5;
651
652 Ok(IPAnalysis {
653 subnet_64,
654 subnet_48,
655 subnet_32,
656 asn,
657 country,
658 is_hosting_provider,
659 is_vpn_provider,
660 reputation_score,
661 })
662 }
663
664 pub fn can_accept_node(&self, ip_analysis: &IPAnalysis) -> bool {
666 let (limit_64, limit_48, limit_32, limit_asn) =
668 if ip_analysis.is_hosting_provider || ip_analysis.is_vpn_provider {
669 (
671 std::cmp::max(1, self.config.max_nodes_per_64 / 2),
672 std::cmp::max(1, self.config.max_nodes_per_48 / 2),
673 std::cmp::max(1, self.config.max_nodes_per_32 / 2),
674 std::cmp::max(1, self.config.max_nodes_per_asn / 2),
675 )
676 } else {
677 (
679 self.config.max_nodes_per_64,
680 self.config.max_nodes_per_48,
681 self.config.max_nodes_per_32,
682 self.config.max_nodes_per_asn,
683 )
684 };
685
686 if let Some(&count) = self.subnet_64_counts.peek(&ip_analysis.subnet_64)
688 && count >= limit_64
689 {
690 return false;
691 }
692
693 if let Some(&count) = self.subnet_48_counts.peek(&ip_analysis.subnet_48)
695 && count >= limit_48
696 {
697 return false;
698 }
699
700 if let Some(&count) = self.subnet_32_counts.peek(&ip_analysis.subnet_32)
702 && count >= limit_32
703 {
704 return false;
705 }
706
707 if let Some(asn) = ip_analysis.asn
709 && let Some(&count) = self.asn_counts.peek(&asn)
710 && count >= limit_asn
711 {
712 return false;
713 }
714
715 true
716 }
717
718 pub fn add_node(&mut self, ip_analysis: &IPAnalysis) -> Result<()> {
720 if !self.can_accept_node(ip_analysis) {
721 return Err(anyhow!("IP diversity limits exceeded"));
722 }
723
724 let count_64 = self
726 .subnet_64_counts
727 .get(&ip_analysis.subnet_64)
728 .copied()
729 .unwrap_or(0)
730 + 1;
731 self.subnet_64_counts.put(ip_analysis.subnet_64, count_64);
732
733 let count_48 = self
734 .subnet_48_counts
735 .get(&ip_analysis.subnet_48)
736 .copied()
737 .unwrap_or(0)
738 + 1;
739 self.subnet_48_counts.put(ip_analysis.subnet_48, count_48);
740
741 let count_32 = self
742 .subnet_32_counts
743 .get(&ip_analysis.subnet_32)
744 .copied()
745 .unwrap_or(0)
746 + 1;
747 self.subnet_32_counts.put(ip_analysis.subnet_32, count_32);
748
749 if let Some(asn) = ip_analysis.asn {
750 let count = self.asn_counts.get(&asn).copied().unwrap_or(0) + 1;
751 self.asn_counts.put(asn, count);
752 }
753
754 if let Some(ref country) = ip_analysis.country {
755 let count = self.country_counts.get(country).copied().unwrap_or(0) + 1;
756 self.country_counts.put(country.clone(), count);
757 }
758
759 Ok(())
760 }
761
762 pub fn remove_node(&mut self, ip_analysis: &IPAnalysis) {
764 if let Some(count) = self.subnet_64_counts.pop(&ip_analysis.subnet_64) {
766 let new_count = count.saturating_sub(1);
767 if new_count > 0 {
768 self.subnet_64_counts.put(ip_analysis.subnet_64, new_count);
769 }
770 }
771
772 if let Some(count) = self.subnet_48_counts.pop(&ip_analysis.subnet_48) {
773 let new_count = count.saturating_sub(1);
774 if new_count > 0 {
775 self.subnet_48_counts.put(ip_analysis.subnet_48, new_count);
776 }
777 }
778
779 if let Some(count) = self.subnet_32_counts.pop(&ip_analysis.subnet_32) {
780 let new_count = count.saturating_sub(1);
781 if new_count > 0 {
782 self.subnet_32_counts.put(ip_analysis.subnet_32, new_count);
783 }
784 }
785
786 if let Some(asn) = ip_analysis.asn
787 && let Some(count) = self.asn_counts.pop(&asn)
788 {
789 let new_count = count.saturating_sub(1);
790 if new_count > 0 {
791 self.asn_counts.put(asn, new_count);
792 }
793 }
794
795 if let Some(ref country) = ip_analysis.country
796 && let Some(count) = self.country_counts.pop(country)
797 {
798 let new_count = count.saturating_sub(1);
799 if new_count > 0 {
800 self.country_counts.put(country.clone(), new_count);
801 }
802 }
803 }
804
805 pub fn extract_subnet_prefix(addr: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
807 let octets = addr.octets();
808 let mut subnet = [0u8; 16];
809
810 let bytes_to_copy = (prefix_len / 8) as usize;
811 let remaining_bits = prefix_len % 8;
812
813 if bytes_to_copy < 16 {
815 subnet[..bytes_to_copy].copy_from_slice(&octets[..bytes_to_copy]);
816 } else {
817 subnet.copy_from_slice(&octets);
818 }
819
820 if remaining_bits > 0 && bytes_to_copy < 16 {
822 let mask = 0xFF << (8 - remaining_bits);
823 subnet[bytes_to_copy] = octets[bytes_to_copy] & mask;
824 }
825
826 Ipv6Addr::from(subnet)
827 }
828
829 pub fn get_diversity_stats(&self) -> DiversityStats {
831 let max_nodes_per_64 = self
833 .subnet_64_counts
834 .iter()
835 .map(|(_, &v)| v)
836 .max()
837 .unwrap_or(0);
838 let max_nodes_per_48 = self
839 .subnet_48_counts
840 .iter()
841 .map(|(_, &v)| v)
842 .max()
843 .unwrap_or(0);
844 let max_nodes_per_32 = self
845 .subnet_32_counts
846 .iter()
847 .map(|(_, &v)| v)
848 .max()
849 .unwrap_or(0);
850 let max_nodes_per_ipv4_32 = self
851 .ipv4_32_counts
852 .iter()
853 .map(|(_, &v)| v)
854 .max()
855 .unwrap_or(0);
856 let max_nodes_per_ipv4_24 = self
857 .ipv4_24_counts
858 .iter()
859 .map(|(_, &v)| v)
860 .max()
861 .unwrap_or(0);
862 let max_nodes_per_ipv4_16 = self
863 .ipv4_16_counts
864 .iter()
865 .map(|(_, &v)| v)
866 .max()
867 .unwrap_or(0);
868
869 DiversityStats {
870 total_64_subnets: self.subnet_64_counts.len(),
871 total_48_subnets: self.subnet_48_counts.len(),
872 total_32_subnets: self.subnet_32_counts.len(),
873 total_asns: self.asn_counts.len(),
874 total_countries: self.country_counts.len(),
875 max_nodes_per_64,
876 max_nodes_per_48,
877 max_nodes_per_32,
878 total_ipv4_32: self.ipv4_32_counts.len(),
880 total_ipv4_24_subnets: self.ipv4_24_counts.len(),
881 total_ipv4_16_subnets: self.ipv4_16_counts.len(),
882 max_nodes_per_ipv4_32,
883 max_nodes_per_ipv4_24,
884 max_nodes_per_ipv4_16,
885 }
886 }
887
888 pub fn set_network_size(&mut self, size: usize) {
892 self.network_size = size;
893 }
894
895 pub fn get_network_size(&self) -> usize {
897 self.network_size
898 }
899
900 pub fn get_per_ip_limit(&self) -> usize {
903 let fraction_limit =
904 (self.network_size as f64 * self.config.max_network_fraction).floor() as usize;
905 std::cmp::min(self.config.max_per_ip_cap, std::cmp::max(1, fraction_limit))
906 }
907
908 fn extract_ipv4_subnet_24(addr: Ipv4Addr) -> Ipv4Addr {
910 let octets = addr.octets();
911 Ipv4Addr::new(octets[0], octets[1], octets[2], 0)
912 }
913
914 fn extract_ipv4_subnet_16(addr: Ipv4Addr) -> Ipv4Addr {
916 let octets = addr.octets();
917 Ipv4Addr::new(octets[0], octets[1], 0, 0)
918 }
919
920 fn extract_ipv4_subnet_8(addr: Ipv4Addr) -> Ipv4Addr {
922 let octets = addr.octets();
923 Ipv4Addr::new(octets[0], 0, 0, 0)
924 }
925
926 pub fn analyze_ipv4(&self, ipv4_addr: Ipv4Addr) -> Result<IPv4Analysis> {
928 let subnet_24 = Self::extract_ipv4_subnet_24(ipv4_addr);
929 let subnet_16 = Self::extract_ipv4_subnet_16(ipv4_addr);
930 let subnet_8 = Self::extract_ipv4_subnet_8(ipv4_addr);
931
932 let asn = None;
935 let country = None;
936 let is_hosting_provider = false;
937 let is_vpn_provider = false;
938 let reputation_score = 0.5;
939
940 Ok(IPv4Analysis {
941 ip_addr: ipv4_addr,
942 subnet_24,
943 subnet_16,
944 subnet_8,
945 asn,
946 country,
947 is_hosting_provider,
948 is_vpn_provider,
949 reputation_score,
950 })
951 }
952
953 pub fn analyze_unified(&self, addr: std::net::IpAddr) -> Result<UnifiedIPAnalysis> {
955 match addr {
956 std::net::IpAddr::V4(ipv4) => {
957 let analysis = self.analyze_ipv4(ipv4)?;
958 Ok(UnifiedIPAnalysis::IPv4(analysis))
959 }
960 std::net::IpAddr::V6(ipv6) => {
961 let analysis = self.analyze_ip(ipv6)?;
962 Ok(UnifiedIPAnalysis::IPv6(analysis))
963 }
964 }
965 }
966
967 pub fn can_accept_unified(&self, analysis: &UnifiedIPAnalysis) -> bool {
969 match analysis {
970 UnifiedIPAnalysis::IPv4(ipv4_analysis) => self.can_accept_ipv4(ipv4_analysis),
971 UnifiedIPAnalysis::IPv6(ipv6_analysis) => self.can_accept_node(ipv6_analysis),
972 }
973 }
974
975 fn can_accept_ipv4(&self, analysis: &IPv4Analysis) -> bool {
977 let per_ip_limit = self.get_per_ip_limit();
979
980 let limit_32 = per_ip_limit;
982 let limit_24 = std::cmp::min(self.config.max_nodes_per_ipv4_24, per_ip_limit * 3);
983 let limit_16 = std::cmp::min(self.config.max_nodes_per_ipv4_16, per_ip_limit * 10);
984
985 let (limit_32, limit_24, limit_16) =
987 if analysis.is_hosting_provider || analysis.is_vpn_provider {
988 (
989 std::cmp::max(1, limit_32 / 2),
990 std::cmp::max(1, limit_24 / 2),
991 std::cmp::max(1, limit_16 / 2),
992 )
993 } else {
994 (limit_32, limit_24, limit_16)
995 };
996
997 if let Some(&count) = self.ipv4_32_counts.peek(&analysis.ip_addr)
999 && count >= limit_32
1000 {
1001 return false;
1002 }
1003
1004 if let Some(&count) = self.ipv4_24_counts.peek(&analysis.subnet_24)
1006 && count >= limit_24
1007 {
1008 return false;
1009 }
1010
1011 if let Some(&count) = self.ipv4_16_counts.peek(&analysis.subnet_16)
1013 && count >= limit_16
1014 {
1015 return false;
1016 }
1017
1018 if let Some(asn) = analysis.asn
1020 && let Some(&count) = self.asn_counts.peek(&asn)
1021 && count >= self.config.max_nodes_per_asn
1022 {
1023 return false;
1024 }
1025
1026 true
1027 }
1028
1029 pub fn add_unified(&mut self, analysis: &UnifiedIPAnalysis) -> Result<()> {
1031 match analysis {
1032 UnifiedIPAnalysis::IPv4(ipv4_analysis) => self.add_ipv4(ipv4_analysis),
1033 UnifiedIPAnalysis::IPv6(ipv6_analysis) => self.add_node(ipv6_analysis),
1034 }
1035 }
1036
1037 fn add_ipv4(&mut self, analysis: &IPv4Analysis) -> Result<()> {
1039 if !self.can_accept_ipv4(analysis) {
1040 return Err(anyhow!("IPv4 diversity limits exceeded"));
1041 }
1042
1043 let count_32 = self
1045 .ipv4_32_counts
1046 .get(&analysis.ip_addr)
1047 .copied()
1048 .unwrap_or(0)
1049 + 1;
1050 self.ipv4_32_counts.put(analysis.ip_addr, count_32);
1051
1052 let count_24 = self
1053 .ipv4_24_counts
1054 .get(&analysis.subnet_24)
1055 .copied()
1056 .unwrap_or(0)
1057 + 1;
1058 self.ipv4_24_counts.put(analysis.subnet_24, count_24);
1059
1060 let count_16 = self
1061 .ipv4_16_counts
1062 .get(&analysis.subnet_16)
1063 .copied()
1064 .unwrap_or(0)
1065 + 1;
1066 self.ipv4_16_counts.put(analysis.subnet_16, count_16);
1067
1068 if let Some(asn) = analysis.asn {
1069 let count = self.asn_counts.get(&asn).copied().unwrap_or(0) + 1;
1070 self.asn_counts.put(asn, count);
1071 }
1072
1073 if let Some(ref country) = analysis.country {
1074 let count = self.country_counts.get(country).copied().unwrap_or(0) + 1;
1075 self.country_counts.put(country.clone(), count);
1076 }
1077
1078 Ok(())
1079 }
1080
1081 pub fn remove_unified(&mut self, analysis: &UnifiedIPAnalysis) {
1083 match analysis {
1084 UnifiedIPAnalysis::IPv4(ipv4_analysis) => self.remove_ipv4(ipv4_analysis),
1085 UnifiedIPAnalysis::IPv6(ipv6_analysis) => self.remove_node(ipv6_analysis),
1086 }
1087 }
1088
1089 fn remove_ipv4(&mut self, analysis: &IPv4Analysis) {
1091 if let Some(count) = self.ipv4_32_counts.pop(&analysis.ip_addr) {
1093 let new_count = count.saturating_sub(1);
1094 if new_count > 0 {
1095 self.ipv4_32_counts.put(analysis.ip_addr, new_count);
1096 }
1097 }
1098
1099 if let Some(count) = self.ipv4_24_counts.pop(&analysis.subnet_24) {
1100 let new_count = count.saturating_sub(1);
1101 if new_count > 0 {
1102 self.ipv4_24_counts.put(analysis.subnet_24, new_count);
1103 }
1104 }
1105
1106 if let Some(count) = self.ipv4_16_counts.pop(&analysis.subnet_16) {
1107 let new_count = count.saturating_sub(1);
1108 if new_count > 0 {
1109 self.ipv4_16_counts.put(analysis.subnet_16, new_count);
1110 }
1111 }
1112
1113 if let Some(asn) = analysis.asn
1114 && let Some(count) = self.asn_counts.pop(&asn)
1115 {
1116 let new_count = count.saturating_sub(1);
1117 if new_count > 0 {
1118 self.asn_counts.put(asn, new_count);
1119 }
1120 }
1121
1122 if let Some(ref country) = analysis.country
1123 && let Some(count) = self.country_counts.pop(country)
1124 {
1125 let new_count = count.saturating_sub(1);
1126 if new_count > 0 {
1127 self.country_counts.put(country.clone(), new_count);
1128 }
1129 }
1130 }
1131}
1132
1133#[cfg(test)]
1134impl IPDiversityEnforcer {
1135 pub fn config(&self) -> &IPDiversityConfig {
1136 &self.config
1137 }
1138}
1139
1140pub trait GeoProvider: std::fmt::Debug {
1142 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo;
1143}
1144
1145#[derive(Debug, Clone)]
1147pub struct GeoInfo {
1148 pub asn: Option<u32>,
1149 pub country: Option<String>,
1150 pub is_hosting_provider: bool,
1151 pub is_vpn_provider: bool,
1152}
1153
1154#[derive(Debug)]
1156pub struct CachedGeoProvider<P: GeoProvider> {
1157 inner: P,
1158 cache: parking_lot::RwLock<HashMap<Ipv6Addr, GeoInfo>>,
1159}
1160
1161impl<P: GeoProvider> CachedGeoProvider<P> {
1162 pub fn new(inner: P) -> Self {
1163 Self {
1164 inner,
1165 cache: parking_lot::RwLock::new(HashMap::new()),
1166 }
1167 }
1168}
1169
1170impl<P: GeoProvider> GeoProvider for CachedGeoProvider<P> {
1171 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo {
1172 if let Some(info) = self.cache.read().get(&ip).cloned() {
1173 return info;
1174 }
1175 let info = self.inner.lookup(ip);
1176 self.cache.write().insert(ip, info.clone());
1177 info
1178 }
1179}
1180
1181#[derive(Debug)]
1183pub struct StubGeoProvider;
1184impl GeoProvider for StubGeoProvider {
1185 fn lookup(&self, _ip: Ipv6Addr) -> GeoInfo {
1186 GeoInfo {
1187 asn: None,
1188 country: None,
1189 is_hosting_provider: false,
1190 is_vpn_provider: false,
1191 }
1192 }
1193}
1194
1195#[derive(Debug, Clone, Serialize, Deserialize)]
1197pub struct DiversityStats {
1198 pub total_64_subnets: usize,
1201 pub total_48_subnets: usize,
1203 pub total_32_subnets: usize,
1205 pub max_nodes_per_64: usize,
1207 pub max_nodes_per_48: usize,
1209 pub max_nodes_per_32: usize,
1211
1212 pub total_ipv4_32: usize,
1215 pub total_ipv4_24_subnets: usize,
1217 pub total_ipv4_16_subnets: usize,
1219 pub max_nodes_per_ipv4_32: usize,
1221 pub max_nodes_per_ipv4_24: usize,
1223 pub max_nodes_per_ipv4_16: usize,
1225
1226 pub total_asns: usize,
1229 pub total_countries: usize,
1231}
1232
1233#[derive(Debug)]
1235pub struct ReputationManager {
1236 reputations: HashMap<PeerId, NodeReputation>,
1237 reputation_decay: f64,
1238 min_reputation: f64,
1239}
1240
1241impl ReputationManager {
1242 pub fn new(reputation_decay: f64, min_reputation: f64) -> Self {
1244 Self {
1245 reputations: HashMap::new(),
1246 reputation_decay,
1247 min_reputation,
1248 }
1249 }
1250
1251 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<&NodeReputation> {
1253 self.reputations.get(peer_id)
1254 }
1255
1256 pub fn update_reputation(&mut self, peer_id: &PeerId, success: bool, response_time: Duration) {
1258 let reputation =
1259 self.reputations
1260 .entry(peer_id.clone())
1261 .or_insert_with(|| NodeReputation {
1262 peer_id: peer_id.clone(),
1263 response_rate: 0.5,
1264 response_time: Duration::from_millis(500),
1265 consistency_score: 0.5,
1266 uptime_estimate: Duration::from_secs(0),
1267 routing_accuracy: 0.5,
1268 last_seen: SystemTime::now(),
1269 interaction_count: 0,
1270 });
1271
1272 let alpha = 0.3; if success {
1276 reputation.response_rate = reputation.response_rate * (1.0 - alpha) + alpha;
1277 } else {
1278 reputation.response_rate *= 1.0 - alpha;
1279 }
1280
1281 let response_time_ms = response_time.as_millis() as f64;
1283 let current_response_ms = reputation.response_time.as_millis() as f64;
1284 let new_response_ms = current_response_ms * (1.0 - alpha) + response_time_ms * alpha;
1285 reputation.response_time = Duration::from_millis(new_response_ms as u64);
1286
1287 reputation.last_seen = SystemTime::now();
1288 reputation.interaction_count += 1;
1289 }
1290
1291 pub fn apply_decay(&mut self) {
1293 let now = SystemTime::now();
1294
1295 self.reputations.retain(|_, reputation| {
1296 if let Ok(elapsed) = now.duration_since(reputation.last_seen) {
1297 let decay_factor = (-elapsed.as_secs_f64() / 3600.0 * self.reputation_decay).exp();
1299 reputation.response_rate *= decay_factor;
1300 reputation.consistency_score *= decay_factor;
1301 reputation.routing_accuracy *= decay_factor;
1302
1303 reputation.response_rate > self.min_reputation / 10.0
1305 } else {
1306 true
1307 }
1308 });
1309 }
1310}
1311
1312#[cfg(test)]
1315mod tests {
1316 use super::*;
1317 use crate::quantum_crypto::generate_ml_dsa_keypair;
1318
1319 fn create_test_keypair() -> (MlDsaPublicKey, MlDsaSecretKey) {
1320 generate_ml_dsa_keypair().expect("Failed to generate test keypair")
1321 }
1322
1323 fn create_test_ipv6() -> Ipv6Addr {
1324 Ipv6Addr::new(
1325 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334,
1326 )
1327 }
1328
1329 fn create_test_diversity_config() -> IPDiversityConfig {
1330 IPDiversityConfig {
1331 max_nodes_per_64: 1,
1333 max_nodes_per_48: 3,
1334 max_nodes_per_32: 10,
1335 max_nodes_per_ipv4_32: 1,
1337 max_nodes_per_ipv4_24: 3,
1338 max_nodes_per_ipv4_16: 10,
1339 max_per_ip_cap: 50,
1341 max_network_fraction: 0.005,
1342 max_nodes_per_asn: 20,
1344 enable_geolocation_check: true,
1345 min_geographic_diversity: 3,
1346 }
1347 }
1348
1349 #[test]
1350 fn test_ipv6_node_id_generation() -> Result<()> {
1351 let (public_key, secret_key) = create_test_keypair();
1352 let ipv6_addr = create_test_ipv6();
1353
1354 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1355
1356 assert_eq!(node_id.ipv6_addr, ipv6_addr);
1357 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);
1361 assert!(node_id.timestamp_secs > 0);
1362
1363 Ok(())
1364 }
1365
1366 #[test]
1367 fn test_ipv6_node_id_verification() -> Result<()> {
1368 let (public_key, secret_key) = create_test_keypair();
1369 let ipv6_addr = create_test_ipv6();
1370
1371 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1372 let is_valid = node_id.verify()?;
1373
1374 assert!(is_valid);
1375
1376 Ok(())
1377 }
1378
1379 #[test]
1380 fn test_ipv6_node_id_verification_fails_with_wrong_data() -> Result<()> {
1381 let (public_key, secret_key) = create_test_keypair();
1382 let ipv6_addr = create_test_ipv6();
1383
1384 let mut node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1385
1386 node_id.node_id[0] ^= 0xFF;
1388 let is_valid = node_id.verify()?;
1389 assert!(!is_valid);
1390
1391 let mut node_id2 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1393 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
1395 assert!(!is_valid2);
1396
1397 let mut node_id3 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1399 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
1401 assert!(!is_valid3);
1402
1403 Ok(())
1404 }
1405
1406 #[test]
1407 fn test_ipv6_subnet_extraction() -> Result<()> {
1408 let (public_key, secret_key) = create_test_keypair();
1409 let ipv6_addr = Ipv6Addr::new(
1410 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1411 );
1412
1413 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
1414
1415 let subnet_64 = node_id.extract_subnet_64();
1417 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
1418 assert_eq!(subnet_64, expected_64);
1419
1420 let subnet_48 = node_id.extract_subnet_48();
1422 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
1423 assert_eq!(subnet_48, expected_48);
1424
1425 let subnet_32 = node_id.extract_subnet_32();
1427 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
1428 assert_eq!(subnet_32, expected_32);
1429
1430 Ok(())
1431 }
1432
1433 fn create_test_ipv4() -> Ipv4Addr {
1436 Ipv4Addr::new(192, 168, 1, 100)
1437 }
1438
1439 #[test]
1440 fn test_ipv4_node_id_generation() -> Result<()> {
1441 let (public_key, secret_key) = create_test_keypair();
1442 let ipv4_addr = create_test_ipv4();
1443
1444 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1445
1446 assert_eq!(node_id.ipv4_addr, ipv4_addr);
1447 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);
1451 assert!(node_id.timestamp_secs > 0);
1452
1453 Ok(())
1454 }
1455
1456 #[test]
1457 fn test_ipv4_node_id_verification() -> Result<()> {
1458 let (public_key, secret_key) = create_test_keypair();
1459 let ipv4_addr = create_test_ipv4();
1460
1461 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1462 let is_valid = node_id.verify()?;
1463
1464 assert!(is_valid);
1465
1466 Ok(())
1467 }
1468
1469 #[test]
1470 fn test_ipv4_node_id_verification_fails_with_wrong_data() -> Result<()> {
1471 let (public_key, secret_key) = create_test_keypair();
1472 let ipv4_addr = create_test_ipv4();
1473
1474 let mut node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1475
1476 node_id.node_id[0] ^= 0xFF;
1478 let is_valid = node_id.verify()?;
1479 assert!(!is_valid);
1480
1481 let mut node_id2 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1483 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
1485 assert!(!is_valid2);
1486
1487 let mut node_id3 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1489 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
1491 assert!(!is_valid3);
1492
1493 Ok(())
1494 }
1495
1496 #[test]
1497 fn test_ipv4_subnet_extraction() -> Result<()> {
1498 let (public_key, secret_key) = create_test_keypair();
1499 let ipv4_addr = Ipv4Addr::new(192, 168, 42, 100);
1500
1501 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1502
1503 let subnet_24 = node_id.extract_subnet_24();
1505 let expected_24 = Ipv4Addr::new(192, 168, 42, 0);
1506 assert_eq!(subnet_24, expected_24);
1507
1508 let subnet_16 = node_id.extract_subnet_16();
1510 let expected_16 = Ipv4Addr::new(192, 168, 0, 0);
1511 assert_eq!(subnet_16, expected_16);
1512
1513 let subnet_8 = node_id.extract_subnet_8();
1515 let expected_8 = Ipv4Addr::new(192, 0, 0, 0);
1516 assert_eq!(subnet_8, expected_8);
1517
1518 Ok(())
1519 }
1520
1521 #[test]
1522 fn test_ipv4_node_id_age() -> Result<()> {
1523 let (public_key, secret_key) = create_test_keypair();
1524 let ipv4_addr = create_test_ipv4();
1525
1526 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
1527
1528 assert!(node_id.age_secs() < 5);
1530
1531 assert!(!node_id.is_expired(Duration::from_secs(3600)));
1533
1534 assert!(!node_id.is_expired(Duration::from_secs(0)));
1537
1538 Ok(())
1539 }
1540
1541 #[test]
1542 fn test_ipv4_different_addresses_different_node_ids() -> Result<()> {
1543 let (public_key, secret_key) = create_test_keypair();
1544 let addr1 = Ipv4Addr::new(192, 168, 1, 1);
1545 let addr2 = Ipv4Addr::new(192, 168, 1, 2);
1546
1547 let node_id1 = IPv4NodeID::generate(addr1, &secret_key, &public_key)?;
1548 let node_id2 = IPv4NodeID::generate(addr2, &secret_key, &public_key)?;
1549
1550 assert_ne!(node_id1.node_id, node_id2.node_id);
1552
1553 assert!(node_id1.verify()?);
1555 assert!(node_id2.verify()?);
1556
1557 Ok(())
1558 }
1559
1560 #[test]
1563 fn test_ip_diversity_config_default() {
1564 let config = IPDiversityConfig::default();
1565
1566 assert_eq!(config.max_nodes_per_64, 1);
1567 assert_eq!(config.max_nodes_per_48, 3);
1568 assert_eq!(config.max_nodes_per_32, 10);
1569 assert_eq!(config.max_nodes_per_asn, 20);
1570 assert!(config.enable_geolocation_check);
1571 assert_eq!(config.min_geographic_diversity, 3);
1572 }
1573
1574 #[test]
1575 fn test_ip_diversity_enforcer_creation() {
1576 let config = create_test_diversity_config();
1577 let enforcer = IPDiversityEnforcer::new(config.clone());
1578
1579 assert_eq!(enforcer.config.max_nodes_per_64, config.max_nodes_per_64);
1580 assert_eq!(enforcer.subnet_64_counts.len(), 0);
1581 assert_eq!(enforcer.subnet_48_counts.len(), 0);
1582 assert_eq!(enforcer.subnet_32_counts.len(), 0);
1583 }
1584
1585 #[test]
1586 fn test_ip_analysis() -> Result<()> {
1587 let config = create_test_diversity_config();
1588 let enforcer = IPDiversityEnforcer::new(config);
1589
1590 let ipv6_addr = create_test_ipv6();
1591 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1592
1593 assert_eq!(
1594 analysis.subnet_64,
1595 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 64)
1596 );
1597 assert_eq!(
1598 analysis.subnet_48,
1599 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 48)
1600 );
1601 assert_eq!(
1602 analysis.subnet_32,
1603 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 32)
1604 );
1605 assert!(analysis.asn.is_none()); assert!(analysis.country.is_none()); assert!(!analysis.is_hosting_provider);
1608 assert!(!analysis.is_vpn_provider);
1609 assert_eq!(analysis.reputation_score, 0.5);
1610
1611 Ok(())
1612 }
1613
1614 #[test]
1615 fn test_can_accept_node_basic() -> Result<()> {
1616 let config = create_test_diversity_config();
1617 let enforcer = IPDiversityEnforcer::new(config);
1618
1619 let ipv6_addr = create_test_ipv6();
1620 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1621
1622 assert!(enforcer.can_accept_node(&analysis));
1624
1625 Ok(())
1626 }
1627
1628 #[test]
1629 fn test_add_and_remove_node() -> Result<()> {
1630 let config = create_test_diversity_config();
1631 let mut enforcer = IPDiversityEnforcer::new(config);
1632
1633 let ipv6_addr = create_test_ipv6();
1634 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1635
1636 enforcer.add_node(&analysis)?;
1638 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), Some(&1));
1639 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), Some(&1));
1640 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), Some(&1));
1641
1642 enforcer.remove_node(&analysis);
1644 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), None);
1645 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), None);
1646 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), None);
1647
1648 Ok(())
1649 }
1650
1651 #[test]
1652 fn test_diversity_limits_enforcement() -> Result<()> {
1653 let config = create_test_diversity_config();
1654 let mut enforcer = IPDiversityEnforcer::new(config);
1655
1656 let ipv6_addr1 = Ipv6Addr::new(
1657 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1658 );
1659 let ipv6_addr2 = Ipv6Addr::new(
1660 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7335,
1661 ); let analysis1 = enforcer.analyze_ip(ipv6_addr1)?;
1664 let analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1665
1666 assert!(enforcer.can_accept_node(&analysis1));
1668 enforcer.add_node(&analysis1)?;
1669
1670 assert!(!enforcer.can_accept_node(&analysis2));
1672
1673 let result = enforcer.add_node(&analysis2);
1675 assert!(result.is_err());
1676 assert!(
1677 result
1678 .unwrap_err()
1679 .to_string()
1680 .contains("IP diversity limits exceeded")
1681 );
1682
1683 Ok(())
1684 }
1685
1686 #[test]
1687 fn test_hosting_provider_stricter_limits() -> Result<()> {
1688 let config = IPDiversityConfig {
1689 max_nodes_per_64: 4, max_nodes_per_48: 8,
1691 ..create_test_diversity_config()
1692 };
1693 let mut enforcer = IPDiversityEnforcer::new(config);
1694
1695 let ipv6_addr = create_test_ipv6();
1696 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1697 analysis.is_hosting_provider = true;
1698
1699 assert!(enforcer.can_accept_node(&analysis));
1701 enforcer.add_node(&analysis)?;
1702
1703 let ipv6_addr2 = Ipv6Addr::new(
1705 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7335,
1706 );
1707 let mut analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1708 analysis2.is_hosting_provider = true;
1709 analysis2.subnet_64 = analysis.subnet_64; assert!(enforcer.can_accept_node(&analysis2));
1712 enforcer.add_node(&analysis2)?;
1713
1714 let ipv6_addr3 = Ipv6Addr::new(
1716 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7336,
1717 );
1718 let mut analysis3 = enforcer.analyze_ip(ipv6_addr3)?;
1719 analysis3.is_hosting_provider = true;
1720 analysis3.subnet_64 = analysis.subnet_64; assert!(!enforcer.can_accept_node(&analysis3));
1723
1724 Ok(())
1725 }
1726
1727 #[test]
1728 fn test_diversity_stats() -> Result<()> {
1729 let config = create_test_diversity_config();
1730 let mut enforcer = IPDiversityEnforcer::new(config);
1731
1732 let addresses = [
1734 Ipv6Addr::new(
1735 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1736 ),
1737 Ipv6Addr::new(
1738 0x2001, 0xdb8, 0x85a4, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1739 ), Ipv6Addr::new(
1741 0x2002, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1742 ), ];
1744
1745 for addr in addresses {
1746 let analysis = enforcer.analyze_ip(addr)?;
1747 enforcer.add_node(&analysis)?;
1748 }
1749
1750 let stats = enforcer.get_diversity_stats();
1751 assert_eq!(stats.total_64_subnets, 3);
1752 assert_eq!(stats.total_48_subnets, 3);
1753 assert_eq!(stats.total_32_subnets, 2); assert_eq!(stats.max_nodes_per_64, 1);
1755 assert_eq!(stats.max_nodes_per_48, 1);
1756 assert_eq!(stats.max_nodes_per_32, 2); Ok(())
1759 }
1760
1761 #[test]
1762 fn test_extract_subnet_prefix() {
1763 let addr = Ipv6Addr::new(
1764 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1765 );
1766
1767 let prefix_64 = IPDiversityEnforcer::extract_subnet_prefix(addr, 64);
1769 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
1770 assert_eq!(prefix_64, expected_64);
1771
1772 let prefix_48 = IPDiversityEnforcer::extract_subnet_prefix(addr, 48);
1774 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
1775 assert_eq!(prefix_48, expected_48);
1776
1777 let prefix_32 = IPDiversityEnforcer::extract_subnet_prefix(addr, 32);
1779 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
1780 assert_eq!(prefix_32, expected_32);
1781
1782 let prefix_56 = IPDiversityEnforcer::extract_subnet_prefix(addr, 56);
1784 let expected_56 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1200, 0, 0, 0, 0);
1785 assert_eq!(prefix_56, expected_56);
1786
1787 let prefix_128 = IPDiversityEnforcer::extract_subnet_prefix(addr, 128);
1789 assert_eq!(prefix_128, addr);
1790 }
1791
1792 #[test]
1793 fn test_reputation_manager_creation() {
1794 let manager = ReputationManager::new(0.1, 0.1);
1795 assert_eq!(manager.reputation_decay, 0.1);
1796 assert_eq!(manager.min_reputation, 0.1);
1797 assert_eq!(manager.reputations.len(), 0);
1798 }
1799
1800 #[test]
1801 fn test_reputation_get_nonexistent() {
1802 let manager = ReputationManager::new(0.1, 0.1);
1803 let peer_id = "test_peer".to_string();
1804
1805 let reputation = manager.get_reputation(&peer_id);
1806 assert!(reputation.is_none());
1807 }
1808
1809 #[test]
1810 fn test_reputation_update_creates_entry() {
1811 let mut manager = ReputationManager::new(0.1, 0.1);
1812 let peer_id = "test_peer".to_string();
1813
1814 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1815
1816 let reputation = manager.get_reputation(&peer_id);
1817 assert!(reputation.is_some());
1818
1819 let rep = reputation.unwrap();
1820 assert_eq!(rep.peer_id, peer_id);
1821 assert!(rep.response_rate > 0.5); assert_eq!(rep.interaction_count, 1);
1823 }
1824
1825 #[test]
1826 fn test_reputation_update_success_improves_rate() {
1827 let mut manager = ReputationManager::new(0.1, 0.1);
1828 let peer_id = "test_peer".to_string();
1829
1830 for _ in 0..15 {
1832 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1833 }
1834
1835 let reputation = manager.get_reputation(&peer_id).unwrap();
1836 assert!(reputation.response_rate > 0.85); assert_eq!(reputation.interaction_count, 15);
1838 }
1839
1840 #[test]
1841 fn test_reputation_update_failure_decreases_rate() {
1842 let mut manager = ReputationManager::new(0.1, 0.1);
1843 let peer_id = "test_peer".to_string();
1844
1845 for _ in 0..15 {
1847 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1848 }
1849
1850 let reputation = manager.get_reputation(&peer_id).unwrap();
1851 assert!(reputation.response_rate < 0.15); assert_eq!(reputation.interaction_count, 15);
1853 }
1854
1855 #[test]
1856 fn test_reputation_response_time_tracking() {
1857 let mut manager = ReputationManager::new(0.1, 0.1);
1858 let peer_id = "test_peer".to_string();
1859
1860 manager.update_reputation(&peer_id, true, Duration::from_millis(200));
1862
1863 let reputation = manager.get_reputation(&peer_id).unwrap();
1864 assert!(reputation.response_time.as_millis() > 200);
1866 assert!(reputation.response_time.as_millis() < 500);
1867 }
1868
1869 #[test]
1870 fn test_reputation_decay() {
1871 let mut manager = ReputationManager::new(1.0, 0.01); let peer_id = "test_peer".to_string();
1873
1874 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1876
1877 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1879 reputation.last_seen = SystemTime::now() - Duration::from_secs(7200); }
1881
1882 let original_rate = manager.get_reputation(&peer_id).unwrap().response_rate;
1883
1884 manager.apply_decay();
1886
1887 let reputation = manager.get_reputation(&peer_id);
1888 if let Some(rep) = reputation {
1889 assert!(rep.response_rate < original_rate);
1891 } }
1893
1894 #[test]
1895 fn test_reputation_decay_removes_low_reputation() {
1896 let mut manager = ReputationManager::new(0.1, 0.5); let peer_id = "test_peer".to_string();
1898
1899 for _ in 0..10 {
1901 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1902 }
1903
1904 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1906 reputation.last_seen = SystemTime::now() - Duration::from_secs(3600); reputation.response_rate = 0.01; }
1909
1910 manager.apply_decay();
1912
1913 assert!(manager.get_reputation(&peer_id).is_none());
1915 }
1916
1917 #[test]
1918 fn test_security_types_keypair() {
1919 let (public_key, secret_key) =
1920 generate_ml_dsa_keypair().expect("Failed to generate keypair");
1921
1922 let public_key_bytes = public_key.as_bytes();
1923 assert_eq!(public_key_bytes.len(), 1952); let message = b"test message";
1926 let signature = ml_dsa_sign(&secret_key, message).expect("Failed to sign message");
1927 assert_eq!(signature.as_bytes().len(), 3309); assert!(ml_dsa_verify(&public_key, message, &signature).is_ok());
1931 }
1932
1933 #[test]
1934 fn test_node_reputation_structure() {
1935 let peer_id = "test_peer".to_string();
1936 let reputation = NodeReputation {
1937 peer_id: peer_id.clone(),
1938 response_rate: 0.85,
1939 response_time: Duration::from_millis(150),
1940 consistency_score: 0.9,
1941 uptime_estimate: Duration::from_secs(86400),
1942 routing_accuracy: 0.8,
1943 last_seen: SystemTime::now(),
1944 interaction_count: 42,
1945 };
1946
1947 assert_eq!(reputation.peer_id, peer_id);
1948 assert_eq!(reputation.response_rate, 0.85);
1949 assert_eq!(reputation.response_time, Duration::from_millis(150));
1950 assert_eq!(reputation.consistency_score, 0.9);
1951 assert_eq!(reputation.uptime_estimate, Duration::from_secs(86400));
1952 assert_eq!(reputation.routing_accuracy, 0.8);
1953 assert_eq!(reputation.interaction_count, 42);
1954 }
1955
1956 #[test]
1957 fn test_ip_analysis_structure() {
1958 let analysis = IPAnalysis {
1959 subnet_64: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0),
1960 subnet_48: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0),
1961 subnet_32: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1962 asn: Some(64512),
1963 country: Some("US".to_string()),
1964 is_hosting_provider: true,
1965 is_vpn_provider: false,
1966 reputation_score: 0.75,
1967 };
1968
1969 assert_eq!(analysis.asn, Some(64512));
1970 assert_eq!(analysis.country, Some("US".to_string()));
1971 assert!(analysis.is_hosting_provider);
1972 assert!(!analysis.is_vpn_provider);
1973 assert_eq!(analysis.reputation_score, 0.75);
1974 }
1975
1976 #[test]
1977 fn test_diversity_stats_structure() {
1978 let stats = DiversityStats {
1979 total_64_subnets: 100,
1981 total_48_subnets: 50,
1982 total_32_subnets: 25,
1983 max_nodes_per_64: 1,
1984 max_nodes_per_48: 3,
1985 max_nodes_per_32: 10,
1986 total_ipv4_32: 80,
1988 total_ipv4_24_subnets: 40,
1989 total_ipv4_16_subnets: 20,
1990 max_nodes_per_ipv4_32: 1,
1991 max_nodes_per_ipv4_24: 3,
1992 max_nodes_per_ipv4_16: 10,
1993 total_asns: 15,
1995 total_countries: 8,
1996 };
1997
1998 assert_eq!(stats.total_64_subnets, 100);
2000 assert_eq!(stats.total_48_subnets, 50);
2001 assert_eq!(stats.total_32_subnets, 25);
2002 assert_eq!(stats.max_nodes_per_64, 1);
2003 assert_eq!(stats.max_nodes_per_48, 3);
2004 assert_eq!(stats.max_nodes_per_32, 10);
2005 assert_eq!(stats.total_ipv4_32, 80);
2007 assert_eq!(stats.total_ipv4_24_subnets, 40);
2008 assert_eq!(stats.total_ipv4_16_subnets, 20);
2009 assert_eq!(stats.max_nodes_per_ipv4_32, 1);
2010 assert_eq!(stats.max_nodes_per_ipv4_24, 3);
2011 assert_eq!(stats.max_nodes_per_ipv4_16, 10);
2012 assert_eq!(stats.total_asns, 15);
2014 assert_eq!(stats.total_countries, 8);
2015 }
2016
2017 #[test]
2018 fn test_multiple_same_subnet_nodes() -> Result<()> {
2019 let config = IPDiversityConfig {
2020 max_nodes_per_64: 3, max_nodes_per_48: 5,
2022 max_nodes_per_32: 10,
2023 ..create_test_diversity_config()
2024 };
2025 let mut enforcer = IPDiversityEnforcer::new(config);
2026
2027 let _base_addr = Ipv6Addr::new(
2028 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x0000,
2029 );
2030
2031 for i in 1..=3 {
2033 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, i);
2034 let analysis = enforcer.analyze_ip(addr)?;
2035 assert!(enforcer.can_accept_node(&analysis));
2036 enforcer.add_node(&analysis)?;
2037 }
2038
2039 let addr4 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 4);
2041 let analysis4 = enforcer.analyze_ip(addr4)?;
2042 assert!(!enforcer.can_accept_node(&analysis4));
2043
2044 let stats = enforcer.get_diversity_stats();
2045 assert_eq!(stats.total_64_subnets, 1);
2046 assert_eq!(stats.max_nodes_per_64, 3);
2047
2048 Ok(())
2049 }
2050
2051 #[test]
2052 fn test_asn_and_country_tracking() -> Result<()> {
2053 let config = create_test_diversity_config();
2054 let mut enforcer = IPDiversityEnforcer::new(config);
2055
2056 let ipv6_addr = create_test_ipv6();
2058 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
2059 analysis.asn = Some(64512);
2060 analysis.country = Some("US".to_string());
2061
2062 enforcer.add_node(&analysis)?;
2063
2064 assert_eq!(enforcer.asn_counts.get(&64512), Some(&1));
2065 assert_eq!(enforcer.country_counts.get("US"), Some(&1));
2066
2067 enforcer.remove_node(&analysis);
2069 assert!(!enforcer.asn_counts.contains(&64512));
2070 assert!(!enforcer.country_counts.contains("US"));
2071
2072 Ok(())
2073 }
2074
2075 #[test]
2076 fn test_reputation_mixed_interactions() {
2077 let mut manager = ReputationManager::new(0.1, 0.1);
2078 let peer_id = "test_peer".to_string();
2079
2080 for i in 0..15 {
2082 let success = i % 3 != 0; manager.update_reputation(&peer_id, success, Duration::from_millis(100 + i * 10));
2084 }
2085
2086 let reputation = manager.get_reputation(&peer_id).unwrap();
2087 assert!(reputation.response_rate > 0.55);
2090 assert!(reputation.response_rate < 0.85);
2091 assert_eq!(reputation.interaction_count, 15);
2092 }
2093}