1use crate::PeerId;
21use crate::quantum_crypto::ant_quic_integration::{
22 MlDsaPublicKey, MlDsaSecretKey, MlDsaSignature, ml_dsa_sign, ml_dsa_verify,
23};
24use anyhow::{Result, anyhow};
25use serde::{Deserialize, Serialize};
26use sha2::{Digest, Sha256};
27use std::collections::HashMap;
28use std::net::{Ipv4Addr, Ipv6Addr};
29use std::time::{Duration, SystemTime, UNIX_EPOCH};
30
31use std::sync::Arc;
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct IPv6NodeID {
36 pub node_id: Vec<u8>,
38 pub ipv6_addr: Ipv6Addr,
40 pub public_key: Vec<u8>,
42 pub signature: Vec<u8>,
44 pub timestamp_secs: u64,
46 pub salt: Vec<u8>,
48}
49
50#[derive(Debug, Clone)]
52pub struct IPDiversityConfig {
53 pub max_nodes_per_64: usize,
55 pub max_nodes_per_48: usize,
57 pub max_nodes_per_32: usize,
59 pub max_nodes_per_asn: usize,
61 pub enable_geolocation_check: bool,
63 pub min_geographic_diversity: usize,
65}
66
67#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
69pub struct IPAnalysis {
70 pub subnet_64: Ipv6Addr,
72 pub subnet_48: Ipv6Addr,
74 pub subnet_32: Ipv6Addr,
76 pub asn: Option<u32>,
78 pub country: Option<String>,
80 pub is_hosting_provider: bool,
82 pub is_vpn_provider: bool,
84 pub reputation_score: f64,
86}
87
88#[derive(Debug, Clone)]
90pub struct NodeReputation {
91 pub peer_id: PeerId,
93 pub response_rate: f64,
95 pub response_time: Duration,
97 pub consistency_score: f64,
99 pub uptime_estimate: Duration,
101 pub routing_accuracy: f64,
103 pub last_seen: SystemTime,
105 pub interaction_count: u64,
107}
108
109impl Default for IPDiversityConfig {
110 fn default() -> Self {
111 Self {
112 max_nodes_per_64: 1,
113 max_nodes_per_48: 3,
114 max_nodes_per_32: 10,
115 max_nodes_per_asn: 20,
116 enable_geolocation_check: true,
117 min_geographic_diversity: 3,
118 }
119 }
120}
121
122impl IPv6NodeID {
123 pub fn generate(
125 ipv6_addr: Ipv6Addr,
126 secret: &MlDsaSecretKey,
127 public: &MlDsaPublicKey,
128 ) -> Result<Self> {
129 let mut rng = rand::thread_rng();
130 let mut salt = vec![0u8; 16];
131 rand::RngCore::fill_bytes(&mut rng, &mut salt);
132
133 let timestamp = SystemTime::now();
134 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
135 let public_key = public.as_bytes().to_vec();
136
137 let mut hasher = Sha256::new();
139 hasher.update(ipv6_addr.octets());
140 hasher.update(&public_key);
141 hasher.update(&salt);
142 hasher.update(timestamp_secs.to_le_bytes());
143 let node_id = hasher.finalize().to_vec();
144
145 let mut message_to_sign = Vec::new();
147 message_to_sign.extend_from_slice(&ipv6_addr.octets());
148 message_to_sign.extend_from_slice(&public_key);
149 message_to_sign.extend_from_slice(&salt);
150 message_to_sign.extend_from_slice(×tamp_secs.to_le_bytes());
151
152 let sig = ml_dsa_sign(secret, &message_to_sign)
153 .map_err(|e| anyhow!("ML-DSA sign failed: {:?}", e))?;
154 let signature = sig.0.to_vec();
155
156 Ok(IPv6NodeID {
157 node_id,
158 ipv6_addr,
159 public_key,
160 signature,
161 timestamp_secs,
162 salt,
163 })
164 }
165
166 pub fn verify(&self) -> Result<bool> {
168 let mut hasher = Sha256::new();
170 hasher.update(self.ipv6_addr.octets());
171 hasher.update(&self.public_key);
172 hasher.update(&self.salt);
173 hasher.update(self.timestamp_secs.to_le_bytes());
174 let expected_node_id = hasher.finalize();
175
176 if expected_node_id.as_slice() != self.node_id {
178 return Ok(false);
179 }
180
181 let public_key = MlDsaPublicKey::from_bytes(&self.public_key)
182 .map_err(|e| anyhow!("Invalid ML-DSA public key: {:?}", e))?;
183
184 if self.signature.len() != 3309 {
186 return Ok(false); }
188 let mut sig_bytes = [0u8; 3309];
189 sig_bytes.copy_from_slice(&self.signature);
190 let signature = MlDsaSignature(Box::new(sig_bytes));
191
192 let mut message_to_verify = Vec::new();
193 message_to_verify.extend_from_slice(&self.ipv6_addr.octets());
194 message_to_verify.extend_from_slice(&self.public_key);
195 message_to_verify.extend_from_slice(&self.salt);
196 message_to_verify.extend_from_slice(&self.timestamp_secs.to_le_bytes());
197
198 let ok = ml_dsa_verify(&public_key, &message_to_verify, &signature)
199 .map_err(|e| anyhow!("ML-DSA verify error: {:?}", e))?;
200 Ok(ok)
201 }
202
203 pub fn extract_subnet_64(&self) -> Ipv6Addr {
205 let octets = self.ipv6_addr.octets();
206 let mut subnet = [0u8; 16];
207 subnet[..8].copy_from_slice(&octets[..8]); Ipv6Addr::from(subnet)
209 }
210
211 pub fn extract_subnet_48(&self) -> Ipv6Addr {
213 let octets = self.ipv6_addr.octets();
214 let mut subnet = [0u8; 16];
215 subnet[..6].copy_from_slice(&octets[..6]); Ipv6Addr::from(subnet)
217 }
218
219 pub fn extract_subnet_32(&self) -> Ipv6Addr {
221 let octets = self.ipv6_addr.octets();
222 let mut subnet = [0u8; 16];
223 subnet[..4].copy_from_slice(&octets[..4]); Ipv6Addr::from(subnet)
225 }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct IPv4NodeID {
232 pub node_id: Vec<u8>,
234 pub ipv4_addr: Ipv4Addr,
236 pub public_key: Vec<u8>,
238 pub signature: Vec<u8>,
240 pub timestamp_secs: u64,
242 pub salt: Vec<u8>,
244}
245
246impl IPv4NodeID {
247 pub fn generate(
249 ipv4_addr: Ipv4Addr,
250 secret: &MlDsaSecretKey,
251 public: &MlDsaPublicKey,
252 ) -> Result<Self> {
253 let mut rng = rand::thread_rng();
254 let mut salt = vec![0u8; 16];
255 rand::RngCore::fill_bytes(&mut rng, &mut salt);
256
257 let timestamp = SystemTime::now();
258 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
259 let public_key = public.as_bytes().to_vec();
260
261 let mut hasher = Sha256::new();
263 hasher.update(ipv4_addr.octets());
264 hasher.update(&public_key);
265 hasher.update(&salt);
266 hasher.update(timestamp_secs.to_le_bytes());
267 let node_id = hasher.finalize().to_vec();
268
269 let mut message_to_sign = Vec::new();
271 message_to_sign.extend_from_slice(&ipv4_addr.octets());
272 message_to_sign.extend_from_slice(&public_key);
273 message_to_sign.extend_from_slice(&salt);
274 message_to_sign.extend_from_slice(×tamp_secs.to_le_bytes());
275
276 let sig = ml_dsa_sign(secret, &message_to_sign)
277 .map_err(|e| anyhow!("ML-DSA sign failed: {:?}", e))?;
278 let signature = sig.0.to_vec();
279
280 Ok(IPv4NodeID {
281 node_id,
282 ipv4_addr,
283 public_key,
284 signature,
285 timestamp_secs,
286 salt,
287 })
288 }
289
290 pub fn verify(&self) -> Result<bool> {
292 let mut hasher = Sha256::new();
294 hasher.update(self.ipv4_addr.octets());
295 hasher.update(&self.public_key);
296 hasher.update(&self.salt);
297 hasher.update(self.timestamp_secs.to_le_bytes());
298 let expected_node_id = hasher.finalize();
299
300 if expected_node_id.as_slice() != self.node_id {
302 return Ok(false);
303 }
304
305 let public_key = MlDsaPublicKey::from_bytes(&self.public_key)
306 .map_err(|e| anyhow!("Invalid ML-DSA public key: {:?}", e))?;
307
308 if self.signature.len() != 3309 {
310 return Ok(false); }
312 let mut sig_bytes = [0u8; 3309];
313 sig_bytes.copy_from_slice(&self.signature);
314 let signature = MlDsaSignature(Box::new(sig_bytes));
315
316 let mut message_to_verify = Vec::new();
317 message_to_verify.extend_from_slice(&self.ipv4_addr.octets());
318 message_to_verify.extend_from_slice(&self.public_key);
319 message_to_verify.extend_from_slice(&self.salt);
320 message_to_verify.extend_from_slice(&self.timestamp_secs.to_le_bytes());
321
322 let ok = ml_dsa_verify(&public_key, &message_to_verify, &signature)
323 .map_err(|e| anyhow!("ML-DSA verify error: {:?}", e))?;
324 Ok(ok)
325 }
326
327 pub fn extract_subnet_24(&self) -> Ipv4Addr {
329 let octets = self.ipv4_addr.octets();
330 Ipv4Addr::new(octets[0], octets[1], octets[2], 0)
331 }
332
333 pub fn extract_subnet_16(&self) -> Ipv4Addr {
335 let octets = self.ipv4_addr.octets();
336 Ipv4Addr::new(octets[0], octets[1], 0, 0)
337 }
338
339 pub fn extract_subnet_8(&self) -> Ipv4Addr {
341 let octets = self.ipv4_addr.octets();
342 Ipv4Addr::new(octets[0], 0, 0, 0)
343 }
344
345 pub fn age_secs(&self) -> u64 {
347 let now = SystemTime::now()
348 .duration_since(UNIX_EPOCH)
349 .map(|d| d.as_secs())
350 .unwrap_or(0);
351 now.saturating_sub(self.timestamp_secs)
352 }
353
354 pub fn is_expired(&self, max_age: Duration) -> bool {
356 self.age_secs() > max_age.as_secs()
357 }
358}
359
360#[derive(Debug)]
362pub struct IPDiversityEnforcer {
363 config: IPDiversityConfig,
364 subnet_64_counts: HashMap<Ipv6Addr, usize>,
365 subnet_48_counts: HashMap<Ipv6Addr, usize>,
366 subnet_32_counts: HashMap<Ipv6Addr, usize>,
367 asn_counts: HashMap<u32, usize>,
368 country_counts: HashMap<String, usize>,
369 geo_provider: Option<Arc<dyn GeoProvider + Send + Sync>>,
370}
371
372impl IPDiversityEnforcer {
373 pub fn new(config: IPDiversityConfig) -> Self {
375 Self {
376 config,
377 subnet_64_counts: HashMap::new(),
378 subnet_48_counts: HashMap::new(),
379 subnet_32_counts: HashMap::new(),
380 asn_counts: HashMap::new(),
381 country_counts: HashMap::new(),
382 geo_provider: None,
383 }
384 }
385
386 pub fn with_geo_provider(
388 config: IPDiversityConfig,
389 provider: Arc<dyn GeoProvider + Send + Sync>,
390 ) -> Self {
391 let mut s = Self::new(config);
392 s.geo_provider = Some(provider);
393 s
394 }
395
396 pub fn analyze_ip(&self, ipv6_addr: Ipv6Addr) -> Result<IPAnalysis> {
398 let subnet_64 = Self::extract_subnet_prefix(ipv6_addr, 64);
399 let subnet_48 = Self::extract_subnet_prefix(ipv6_addr, 48);
400 let subnet_32 = Self::extract_subnet_prefix(ipv6_addr, 32);
401
402 let (asn, country, is_hosting_provider, is_vpn_provider) =
404 if let Some(p) = &self.geo_provider {
405 let info = p.lookup(ipv6_addr);
406 (
407 info.asn,
408 info.country,
409 info.is_hosting_provider,
410 info.is_vpn_provider,
411 )
412 } else {
413 (None, None, false, false)
414 };
415
416 let reputation_score = 0.5;
418
419 Ok(IPAnalysis {
420 subnet_64,
421 subnet_48,
422 subnet_32,
423 asn,
424 country,
425 is_hosting_provider,
426 is_vpn_provider,
427 reputation_score,
428 })
429 }
430
431 pub fn can_accept_node(&self, ip_analysis: &IPAnalysis) -> bool {
433 let (limit_64, limit_48, limit_32, limit_asn) =
435 if ip_analysis.is_hosting_provider || ip_analysis.is_vpn_provider {
436 (
438 std::cmp::max(1, self.config.max_nodes_per_64 / 2),
439 std::cmp::max(1, self.config.max_nodes_per_48 / 2),
440 std::cmp::max(1, self.config.max_nodes_per_32 / 2),
441 std::cmp::max(1, self.config.max_nodes_per_asn / 2),
442 )
443 } else {
444 (
446 self.config.max_nodes_per_64,
447 self.config.max_nodes_per_48,
448 self.config.max_nodes_per_32,
449 self.config.max_nodes_per_asn,
450 )
451 };
452
453 if let Some(&count) = self.subnet_64_counts.get(&ip_analysis.subnet_64)
455 && count >= limit_64
456 {
457 return false;
458 }
459
460 if let Some(&count) = self.subnet_48_counts.get(&ip_analysis.subnet_48)
462 && count >= limit_48
463 {
464 return false;
465 }
466
467 if let Some(&count) = self.subnet_32_counts.get(&ip_analysis.subnet_32)
469 && count >= limit_32
470 {
471 return false;
472 }
473
474 if let Some(asn) = ip_analysis.asn
476 && let Some(&count) = self.asn_counts.get(&asn)
477 && count >= limit_asn
478 {
479 return false;
480 }
481
482 true
483 }
484
485 pub fn add_node(&mut self, ip_analysis: &IPAnalysis) -> Result<()> {
487 if !self.can_accept_node(ip_analysis) {
488 return Err(anyhow!("IP diversity limits exceeded"));
489 }
490
491 *self
493 .subnet_64_counts
494 .entry(ip_analysis.subnet_64)
495 .or_insert(0) += 1;
496 *self
497 .subnet_48_counts
498 .entry(ip_analysis.subnet_48)
499 .or_insert(0) += 1;
500 *self
501 .subnet_32_counts
502 .entry(ip_analysis.subnet_32)
503 .or_insert(0) += 1;
504
505 if let Some(asn) = ip_analysis.asn {
506 *self.asn_counts.entry(asn).or_insert(0) += 1;
507 }
508
509 if let Some(ref country) = ip_analysis.country {
510 *self.country_counts.entry(country.clone()).or_insert(0) += 1;
511 }
512
513 Ok(())
514 }
515
516 pub fn remove_node(&mut self, ip_analysis: &IPAnalysis) {
518 if let Some(count) = self.subnet_64_counts.get_mut(&ip_analysis.subnet_64) {
519 *count = count.saturating_sub(1);
520 if *count == 0 {
521 self.subnet_64_counts.remove(&ip_analysis.subnet_64);
522 }
523 }
524
525 if let Some(count) = self.subnet_48_counts.get_mut(&ip_analysis.subnet_48) {
526 *count = count.saturating_sub(1);
527 if *count == 0 {
528 self.subnet_48_counts.remove(&ip_analysis.subnet_48);
529 }
530 }
531
532 if let Some(count) = self.subnet_32_counts.get_mut(&ip_analysis.subnet_32) {
533 *count = count.saturating_sub(1);
534 if *count == 0 {
535 self.subnet_32_counts.remove(&ip_analysis.subnet_32);
536 }
537 }
538
539 if let Some(asn) = ip_analysis.asn
540 && let Some(count) = self.asn_counts.get_mut(&asn)
541 {
542 *count = count.saturating_sub(1);
543 if *count == 0 {
544 self.asn_counts.remove(&asn);
545 }
546 }
547
548 if let Some(ref country) = ip_analysis.country
549 && let Some(count) = self.country_counts.get_mut(country)
550 {
551 *count = count.saturating_sub(1);
552 if *count == 0 {
553 self.country_counts.remove(country);
554 }
555 }
556 }
557
558 pub fn extract_subnet_prefix(addr: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
560 let octets = addr.octets();
561 let mut subnet = [0u8; 16];
562
563 let bytes_to_copy = (prefix_len / 8) as usize;
564 let remaining_bits = prefix_len % 8;
565
566 if bytes_to_copy < 16 {
568 subnet[..bytes_to_copy].copy_from_slice(&octets[..bytes_to_copy]);
569 } else {
570 subnet.copy_from_slice(&octets);
571 }
572
573 if remaining_bits > 0 && bytes_to_copy < 16 {
575 let mask = 0xFF << (8 - remaining_bits);
576 subnet[bytes_to_copy] = octets[bytes_to_copy] & mask;
577 }
578
579 Ipv6Addr::from(subnet)
580 }
581
582 pub fn get_diversity_stats(&self) -> DiversityStats {
584 DiversityStats {
585 total_64_subnets: self.subnet_64_counts.len(),
586 total_48_subnets: self.subnet_48_counts.len(),
587 total_32_subnets: self.subnet_32_counts.len(),
588 total_asns: self.asn_counts.len(),
589 total_countries: self.country_counts.len(),
590 max_nodes_per_64: self.subnet_64_counts.values().max().copied().unwrap_or(0),
591 max_nodes_per_48: self.subnet_48_counts.values().max().copied().unwrap_or(0),
592 max_nodes_per_32: self.subnet_32_counts.values().max().copied().unwrap_or(0),
593 }
594 }
595}
596
597pub trait GeoProvider: std::fmt::Debug {
599 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo;
600}
601
602#[derive(Debug, Clone)]
604pub struct GeoInfo {
605 pub asn: Option<u32>,
606 pub country: Option<String>,
607 pub is_hosting_provider: bool,
608 pub is_vpn_provider: bool,
609}
610
611#[derive(Debug)]
613pub struct CachedGeoProvider<P: GeoProvider> {
614 inner: P,
615 cache: parking_lot::RwLock<HashMap<Ipv6Addr, GeoInfo>>,
616}
617
618impl<P: GeoProvider> CachedGeoProvider<P> {
619 pub fn new(inner: P) -> Self {
620 Self {
621 inner,
622 cache: parking_lot::RwLock::new(HashMap::new()),
623 }
624 }
625}
626
627impl<P: GeoProvider> GeoProvider for CachedGeoProvider<P> {
628 fn lookup(&self, ip: Ipv6Addr) -> GeoInfo {
629 if let Some(info) = self.cache.read().get(&ip).cloned() {
630 return info;
631 }
632 let info = self.inner.lookup(ip);
633 self.cache.write().insert(ip, info.clone());
634 info
635 }
636}
637
638#[derive(Debug)]
640pub struct StubGeoProvider;
641impl GeoProvider for StubGeoProvider {
642 fn lookup(&self, _ip: Ipv6Addr) -> GeoInfo {
643 GeoInfo {
644 asn: None,
645 country: None,
646 is_hosting_provider: false,
647 is_vpn_provider: false,
648 }
649 }
650}
651
652#[derive(Debug, Clone, Serialize, Deserialize)]
654pub struct DiversityStats {
655 pub total_64_subnets: usize,
657 pub total_48_subnets: usize,
659 pub total_32_subnets: usize,
661 pub total_asns: usize,
663 pub total_countries: usize,
665 pub max_nodes_per_64: usize,
667 pub max_nodes_per_48: usize,
669 pub max_nodes_per_32: usize,
671}
672
673#[derive(Debug)]
675pub struct ReputationManager {
676 reputations: HashMap<PeerId, NodeReputation>,
677 reputation_decay: f64,
678 min_reputation: f64,
679}
680
681impl ReputationManager {
682 pub fn new(reputation_decay: f64, min_reputation: f64) -> Self {
684 Self {
685 reputations: HashMap::new(),
686 reputation_decay,
687 min_reputation,
688 }
689 }
690
691 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<&NodeReputation> {
693 self.reputations.get(peer_id)
694 }
695
696 pub fn update_reputation(&mut self, peer_id: &PeerId, success: bool, response_time: Duration) {
698 let reputation =
699 self.reputations
700 .entry(peer_id.clone())
701 .or_insert_with(|| NodeReputation {
702 peer_id: peer_id.clone(),
703 response_rate: 0.5,
704 response_time: Duration::from_millis(500),
705 consistency_score: 0.5,
706 uptime_estimate: Duration::from_secs(0),
707 routing_accuracy: 0.5,
708 last_seen: SystemTime::now(),
709 interaction_count: 0,
710 });
711
712 let alpha = 0.3; if success {
716 reputation.response_rate = reputation.response_rate * (1.0 - alpha) + alpha;
717 } else {
718 reputation.response_rate *= 1.0 - alpha;
719 }
720
721 let response_time_ms = response_time.as_millis() as f64;
723 let current_response_ms = reputation.response_time.as_millis() as f64;
724 let new_response_ms = current_response_ms * (1.0 - alpha) + response_time_ms * alpha;
725 reputation.response_time = Duration::from_millis(new_response_ms as u64);
726
727 reputation.last_seen = SystemTime::now();
728 reputation.interaction_count += 1;
729 }
730
731 pub fn apply_decay(&mut self) {
733 let now = SystemTime::now();
734
735 self.reputations.retain(|_, reputation| {
736 if let Ok(elapsed) = now.duration_since(reputation.last_seen) {
737 let decay_factor = (-elapsed.as_secs_f64() / 3600.0 * self.reputation_decay).exp();
739 reputation.response_rate *= decay_factor;
740 reputation.consistency_score *= decay_factor;
741 reputation.routing_accuracy *= decay_factor;
742
743 reputation.response_rate > self.min_reputation / 10.0
745 } else {
746 true
747 }
748 });
749 }
750}
751
752#[cfg(test)]
755mod tests {
756 use super::*;
757 use crate::quantum_crypto::generate_ml_dsa_keypair;
758
759 fn create_test_keypair() -> (MlDsaPublicKey, MlDsaSecretKey) {
760 generate_ml_dsa_keypair().expect("Failed to generate test keypair")
761 }
762
763 fn create_test_ipv6() -> Ipv6Addr {
764 Ipv6Addr::new(
765 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334,
766 )
767 }
768
769 fn create_test_diversity_config() -> IPDiversityConfig {
770 IPDiversityConfig {
771 max_nodes_per_64: 1,
772 max_nodes_per_48: 3,
773 max_nodes_per_32: 10,
774 max_nodes_per_asn: 20,
775 enable_geolocation_check: true,
776 min_geographic_diversity: 3,
777 }
778 }
779
780 #[test]
781 fn test_ipv6_node_id_generation() -> Result<()> {
782 let (public_key, secret_key) = create_test_keypair();
783 let ipv6_addr = create_test_ipv6();
784
785 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
786
787 assert_eq!(node_id.ipv6_addr, ipv6_addr);
788 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);
792 assert!(node_id.timestamp_secs > 0);
793
794 Ok(())
795 }
796
797 #[test]
798 fn test_ipv6_node_id_verification() -> Result<()> {
799 let (public_key, secret_key) = create_test_keypair();
800 let ipv6_addr = create_test_ipv6();
801
802 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
803 let is_valid = node_id.verify()?;
804
805 assert!(is_valid);
806
807 Ok(())
808 }
809
810 #[test]
811 fn test_ipv6_node_id_verification_fails_with_wrong_data() -> Result<()> {
812 let (public_key, secret_key) = create_test_keypair();
813 let ipv6_addr = create_test_ipv6();
814
815 let mut node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
816
817 node_id.node_id[0] ^= 0xFF;
819 let is_valid = node_id.verify()?;
820 assert!(!is_valid);
821
822 let mut node_id2 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
824 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
826 assert!(!is_valid2);
827
828 let mut node_id3 = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
830 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
832 assert!(!is_valid3);
833
834 Ok(())
835 }
836
837 #[test]
838 fn test_ipv6_subnet_extraction() -> Result<()> {
839 let (public_key, secret_key) = create_test_keypair();
840 let ipv6_addr = Ipv6Addr::new(
841 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
842 );
843
844 let node_id = IPv6NodeID::generate(ipv6_addr, &secret_key, &public_key)?;
845
846 let subnet_64 = node_id.extract_subnet_64();
848 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
849 assert_eq!(subnet_64, expected_64);
850
851 let subnet_48 = node_id.extract_subnet_48();
853 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
854 assert_eq!(subnet_48, expected_48);
855
856 let subnet_32 = node_id.extract_subnet_32();
858 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
859 assert_eq!(subnet_32, expected_32);
860
861 Ok(())
862 }
863
864 fn create_test_ipv4() -> Ipv4Addr {
867 Ipv4Addr::new(192, 168, 1, 100)
868 }
869
870 #[test]
871 fn test_ipv4_node_id_generation() -> Result<()> {
872 let (public_key, secret_key) = create_test_keypair();
873 let ipv4_addr = create_test_ipv4();
874
875 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
876
877 assert_eq!(node_id.ipv4_addr, ipv4_addr);
878 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);
882 assert!(node_id.timestamp_secs > 0);
883
884 Ok(())
885 }
886
887 #[test]
888 fn test_ipv4_node_id_verification() -> Result<()> {
889 let (public_key, secret_key) = create_test_keypair();
890 let ipv4_addr = create_test_ipv4();
891
892 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
893 let is_valid = node_id.verify()?;
894
895 assert!(is_valid);
896
897 Ok(())
898 }
899
900 #[test]
901 fn test_ipv4_node_id_verification_fails_with_wrong_data() -> Result<()> {
902 let (public_key, secret_key) = create_test_keypair();
903 let ipv4_addr = create_test_ipv4();
904
905 let mut node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
906
907 node_id.node_id[0] ^= 0xFF;
909 let is_valid = node_id.verify()?;
910 assert!(!is_valid);
911
912 let mut node_id2 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
914 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
916 assert!(!is_valid2);
917
918 let mut node_id3 = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
920 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
922 assert!(!is_valid3);
923
924 Ok(())
925 }
926
927 #[test]
928 fn test_ipv4_subnet_extraction() -> Result<()> {
929 let (public_key, secret_key) = create_test_keypair();
930 let ipv4_addr = Ipv4Addr::new(192, 168, 42, 100);
931
932 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
933
934 let subnet_24 = node_id.extract_subnet_24();
936 let expected_24 = Ipv4Addr::new(192, 168, 42, 0);
937 assert_eq!(subnet_24, expected_24);
938
939 let subnet_16 = node_id.extract_subnet_16();
941 let expected_16 = Ipv4Addr::new(192, 168, 0, 0);
942 assert_eq!(subnet_16, expected_16);
943
944 let subnet_8 = node_id.extract_subnet_8();
946 let expected_8 = Ipv4Addr::new(192, 0, 0, 0);
947 assert_eq!(subnet_8, expected_8);
948
949 Ok(())
950 }
951
952 #[test]
953 fn test_ipv4_node_id_age() -> Result<()> {
954 let (public_key, secret_key) = create_test_keypair();
955 let ipv4_addr = create_test_ipv4();
956
957 let node_id = IPv4NodeID::generate(ipv4_addr, &secret_key, &public_key)?;
958
959 assert!(node_id.age_secs() < 5);
961
962 assert!(!node_id.is_expired(Duration::from_secs(3600)));
964
965 assert!(!node_id.is_expired(Duration::from_secs(0)));
968
969 Ok(())
970 }
971
972 #[test]
973 fn test_ipv4_different_addresses_different_node_ids() -> Result<()> {
974 let (public_key, secret_key) = create_test_keypair();
975 let addr1 = Ipv4Addr::new(192, 168, 1, 1);
976 let addr2 = Ipv4Addr::new(192, 168, 1, 2);
977
978 let node_id1 = IPv4NodeID::generate(addr1, &secret_key, &public_key)?;
979 let node_id2 = IPv4NodeID::generate(addr2, &secret_key, &public_key)?;
980
981 assert_ne!(node_id1.node_id, node_id2.node_id);
983
984 assert!(node_id1.verify()?);
986 assert!(node_id2.verify()?);
987
988 Ok(())
989 }
990
991 #[test]
994 fn test_ip_diversity_config_default() {
995 let config = IPDiversityConfig::default();
996
997 assert_eq!(config.max_nodes_per_64, 1);
998 assert_eq!(config.max_nodes_per_48, 3);
999 assert_eq!(config.max_nodes_per_32, 10);
1000 assert_eq!(config.max_nodes_per_asn, 20);
1001 assert!(config.enable_geolocation_check);
1002 assert_eq!(config.min_geographic_diversity, 3);
1003 }
1004
1005 #[test]
1006 fn test_ip_diversity_enforcer_creation() {
1007 let config = create_test_diversity_config();
1008 let enforcer = IPDiversityEnforcer::new(config.clone());
1009
1010 assert_eq!(enforcer.config.max_nodes_per_64, config.max_nodes_per_64);
1011 assert_eq!(enforcer.subnet_64_counts.len(), 0);
1012 assert_eq!(enforcer.subnet_48_counts.len(), 0);
1013 assert_eq!(enforcer.subnet_32_counts.len(), 0);
1014 }
1015
1016 #[test]
1017 fn test_ip_analysis() -> Result<()> {
1018 let config = create_test_diversity_config();
1019 let enforcer = IPDiversityEnforcer::new(config);
1020
1021 let ipv6_addr = create_test_ipv6();
1022 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1023
1024 assert_eq!(
1025 analysis.subnet_64,
1026 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 64)
1027 );
1028 assert_eq!(
1029 analysis.subnet_48,
1030 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 48)
1031 );
1032 assert_eq!(
1033 analysis.subnet_32,
1034 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 32)
1035 );
1036 assert!(analysis.asn.is_none()); assert!(analysis.country.is_none()); assert!(!analysis.is_hosting_provider);
1039 assert!(!analysis.is_vpn_provider);
1040 assert_eq!(analysis.reputation_score, 0.5);
1041
1042 Ok(())
1043 }
1044
1045 #[test]
1046 fn test_can_accept_node_basic() -> Result<()> {
1047 let config = create_test_diversity_config();
1048 let enforcer = IPDiversityEnforcer::new(config);
1049
1050 let ipv6_addr = create_test_ipv6();
1051 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1052
1053 assert!(enforcer.can_accept_node(&analysis));
1055
1056 Ok(())
1057 }
1058
1059 #[test]
1060 fn test_add_and_remove_node() -> Result<()> {
1061 let config = create_test_diversity_config();
1062 let mut enforcer = IPDiversityEnforcer::new(config);
1063
1064 let ipv6_addr = create_test_ipv6();
1065 let analysis = enforcer.analyze_ip(ipv6_addr)?;
1066
1067 enforcer.add_node(&analysis)?;
1069 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), Some(&1));
1070 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), Some(&1));
1071 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), Some(&1));
1072
1073 enforcer.remove_node(&analysis);
1075 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), None);
1076 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), None);
1077 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), None);
1078
1079 Ok(())
1080 }
1081
1082 #[test]
1083 fn test_diversity_limits_enforcement() -> Result<()> {
1084 let config = create_test_diversity_config();
1085 let mut enforcer = IPDiversityEnforcer::new(config);
1086
1087 let ipv6_addr1 = Ipv6Addr::new(
1088 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1089 );
1090 let ipv6_addr2 = Ipv6Addr::new(
1091 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7335,
1092 ); let analysis1 = enforcer.analyze_ip(ipv6_addr1)?;
1095 let analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1096
1097 assert!(enforcer.can_accept_node(&analysis1));
1099 enforcer.add_node(&analysis1)?;
1100
1101 assert!(!enforcer.can_accept_node(&analysis2));
1103
1104 let result = enforcer.add_node(&analysis2);
1106 assert!(result.is_err());
1107 assert!(
1108 result
1109 .unwrap_err()
1110 .to_string()
1111 .contains("IP diversity limits exceeded")
1112 );
1113
1114 Ok(())
1115 }
1116
1117 #[test]
1118 fn test_hosting_provider_stricter_limits() -> Result<()> {
1119 let config = IPDiversityConfig {
1120 max_nodes_per_64: 4, max_nodes_per_48: 8,
1122 ..create_test_diversity_config()
1123 };
1124 let mut enforcer = IPDiversityEnforcer::new(config);
1125
1126 let ipv6_addr = create_test_ipv6();
1127 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1128 analysis.is_hosting_provider = true;
1129
1130 assert!(enforcer.can_accept_node(&analysis));
1132 enforcer.add_node(&analysis)?;
1133
1134 let ipv6_addr2 = Ipv6Addr::new(
1136 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7335,
1137 );
1138 let mut analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
1139 analysis2.is_hosting_provider = true;
1140 analysis2.subnet_64 = analysis.subnet_64; assert!(enforcer.can_accept_node(&analysis2));
1143 enforcer.add_node(&analysis2)?;
1144
1145 let ipv6_addr3 = Ipv6Addr::new(
1147 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7336,
1148 );
1149 let mut analysis3 = enforcer.analyze_ip(ipv6_addr3)?;
1150 analysis3.is_hosting_provider = true;
1151 analysis3.subnet_64 = analysis.subnet_64; assert!(!enforcer.can_accept_node(&analysis3));
1154
1155 Ok(())
1156 }
1157
1158 #[test]
1159 fn test_diversity_stats() -> Result<()> {
1160 let config = create_test_diversity_config();
1161 let mut enforcer = IPDiversityEnforcer::new(config);
1162
1163 let addresses = [
1165 Ipv6Addr::new(
1166 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1167 ),
1168 Ipv6Addr::new(
1169 0x2001, 0xdb8, 0x85a4, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1170 ), Ipv6Addr::new(
1172 0x2002, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1173 ), ];
1175
1176 for addr in addresses {
1177 let analysis = enforcer.analyze_ip(addr)?;
1178 enforcer.add_node(&analysis)?;
1179 }
1180
1181 let stats = enforcer.get_diversity_stats();
1182 assert_eq!(stats.total_64_subnets, 3);
1183 assert_eq!(stats.total_48_subnets, 3);
1184 assert_eq!(stats.total_32_subnets, 2); assert_eq!(stats.max_nodes_per_64, 1);
1186 assert_eq!(stats.max_nodes_per_48, 1);
1187 assert_eq!(stats.max_nodes_per_32, 2); Ok(())
1190 }
1191
1192 #[test]
1193 fn test_extract_subnet_prefix() {
1194 let addr = Ipv6Addr::new(
1195 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
1196 );
1197
1198 let prefix_64 = IPDiversityEnforcer::extract_subnet_prefix(addr, 64);
1200 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
1201 assert_eq!(prefix_64, expected_64);
1202
1203 let prefix_48 = IPDiversityEnforcer::extract_subnet_prefix(addr, 48);
1205 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
1206 assert_eq!(prefix_48, expected_48);
1207
1208 let prefix_32 = IPDiversityEnforcer::extract_subnet_prefix(addr, 32);
1210 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
1211 assert_eq!(prefix_32, expected_32);
1212
1213 let prefix_56 = IPDiversityEnforcer::extract_subnet_prefix(addr, 56);
1215 let expected_56 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1200, 0, 0, 0, 0);
1216 assert_eq!(prefix_56, expected_56);
1217
1218 let prefix_128 = IPDiversityEnforcer::extract_subnet_prefix(addr, 128);
1220 assert_eq!(prefix_128, addr);
1221 }
1222
1223 #[test]
1224 fn test_reputation_manager_creation() {
1225 let manager = ReputationManager::new(0.1, 0.1);
1226 assert_eq!(manager.reputation_decay, 0.1);
1227 assert_eq!(manager.min_reputation, 0.1);
1228 assert_eq!(manager.reputations.len(), 0);
1229 }
1230
1231 #[test]
1232 fn test_reputation_get_nonexistent() {
1233 let manager = ReputationManager::new(0.1, 0.1);
1234 let peer_id = "test_peer".to_string();
1235
1236 let reputation = manager.get_reputation(&peer_id);
1237 assert!(reputation.is_none());
1238 }
1239
1240 #[test]
1241 fn test_reputation_update_creates_entry() {
1242 let mut manager = ReputationManager::new(0.1, 0.1);
1243 let peer_id = "test_peer".to_string();
1244
1245 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1246
1247 let reputation = manager.get_reputation(&peer_id);
1248 assert!(reputation.is_some());
1249
1250 let rep = reputation.unwrap();
1251 assert_eq!(rep.peer_id, peer_id);
1252 assert!(rep.response_rate > 0.5); assert_eq!(rep.interaction_count, 1);
1254 }
1255
1256 #[test]
1257 fn test_reputation_update_success_improves_rate() {
1258 let mut manager = ReputationManager::new(0.1, 0.1);
1259 let peer_id = "test_peer".to_string();
1260
1261 for _ in 0..15 {
1263 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1264 }
1265
1266 let reputation = manager.get_reputation(&peer_id).unwrap();
1267 assert!(reputation.response_rate > 0.85); assert_eq!(reputation.interaction_count, 15);
1269 }
1270
1271 #[test]
1272 fn test_reputation_update_failure_decreases_rate() {
1273 let mut manager = ReputationManager::new(0.1, 0.1);
1274 let peer_id = "test_peer".to_string();
1275
1276 for _ in 0..15 {
1278 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1279 }
1280
1281 let reputation = manager.get_reputation(&peer_id).unwrap();
1282 assert!(reputation.response_rate < 0.15); assert_eq!(reputation.interaction_count, 15);
1284 }
1285
1286 #[test]
1287 fn test_reputation_response_time_tracking() {
1288 let mut manager = ReputationManager::new(0.1, 0.1);
1289 let peer_id = "test_peer".to_string();
1290
1291 manager.update_reputation(&peer_id, true, Duration::from_millis(200));
1293
1294 let reputation = manager.get_reputation(&peer_id).unwrap();
1295 assert!(reputation.response_time.as_millis() > 200);
1297 assert!(reputation.response_time.as_millis() < 500);
1298 }
1299
1300 #[test]
1301 fn test_reputation_decay() {
1302 let mut manager = ReputationManager::new(1.0, 0.01); let peer_id = "test_peer".to_string();
1304
1305 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1307
1308 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1310 reputation.last_seen = SystemTime::now() - Duration::from_secs(7200); }
1312
1313 let original_rate = manager.get_reputation(&peer_id).unwrap().response_rate;
1314
1315 manager.apply_decay();
1317
1318 let reputation = manager.get_reputation(&peer_id);
1319 if let Some(rep) = reputation {
1320 assert!(rep.response_rate < original_rate);
1322 } }
1324
1325 #[test]
1326 fn test_reputation_decay_removes_low_reputation() {
1327 let mut manager = ReputationManager::new(0.1, 0.5); let peer_id = "test_peer".to_string();
1329
1330 for _ in 0..10 {
1332 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1333 }
1334
1335 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1337 reputation.last_seen = SystemTime::now() - Duration::from_secs(3600); reputation.response_rate = 0.01; }
1340
1341 manager.apply_decay();
1343
1344 assert!(manager.get_reputation(&peer_id).is_none());
1346 }
1347
1348 #[test]
1349 fn test_security_types_keypair() {
1350 let (public_key, secret_key) =
1351 generate_ml_dsa_keypair().expect("Failed to generate keypair");
1352
1353 let public_key_bytes = public_key.as_bytes();
1354 assert_eq!(public_key_bytes.len(), 1952); let message = b"test message";
1357 let signature = ml_dsa_sign(&secret_key, message).expect("Failed to sign message");
1358 assert_eq!(signature.as_bytes().len(), 3309); assert!(ml_dsa_verify(&public_key, message, &signature).is_ok());
1362 }
1363
1364 #[test]
1365 fn test_node_reputation_structure() {
1366 let peer_id = "test_peer".to_string();
1367 let reputation = NodeReputation {
1368 peer_id: peer_id.clone(),
1369 response_rate: 0.85,
1370 response_time: Duration::from_millis(150),
1371 consistency_score: 0.9,
1372 uptime_estimate: Duration::from_secs(86400),
1373 routing_accuracy: 0.8,
1374 last_seen: SystemTime::now(),
1375 interaction_count: 42,
1376 };
1377
1378 assert_eq!(reputation.peer_id, peer_id);
1379 assert_eq!(reputation.response_rate, 0.85);
1380 assert_eq!(reputation.response_time, Duration::from_millis(150));
1381 assert_eq!(reputation.consistency_score, 0.9);
1382 assert_eq!(reputation.uptime_estimate, Duration::from_secs(86400));
1383 assert_eq!(reputation.routing_accuracy, 0.8);
1384 assert_eq!(reputation.interaction_count, 42);
1385 }
1386
1387 #[test]
1388 fn test_ip_analysis_structure() {
1389 let analysis = IPAnalysis {
1390 subnet_64: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0),
1391 subnet_48: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0),
1392 subnet_32: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1393 asn: Some(64512),
1394 country: Some("US".to_string()),
1395 is_hosting_provider: true,
1396 is_vpn_provider: false,
1397 reputation_score: 0.75,
1398 };
1399
1400 assert_eq!(analysis.asn, Some(64512));
1401 assert_eq!(analysis.country, Some("US".to_string()));
1402 assert!(analysis.is_hosting_provider);
1403 assert!(!analysis.is_vpn_provider);
1404 assert_eq!(analysis.reputation_score, 0.75);
1405 }
1406
1407 #[test]
1408 fn test_diversity_stats_structure() {
1409 let stats = DiversityStats {
1410 total_64_subnets: 100,
1411 total_48_subnets: 50,
1412 total_32_subnets: 25,
1413 total_asns: 15,
1414 total_countries: 8,
1415 max_nodes_per_64: 1,
1416 max_nodes_per_48: 3,
1417 max_nodes_per_32: 10,
1418 };
1419
1420 assert_eq!(stats.total_64_subnets, 100);
1421 assert_eq!(stats.total_48_subnets, 50);
1422 assert_eq!(stats.total_32_subnets, 25);
1423 assert_eq!(stats.total_asns, 15);
1424 assert_eq!(stats.total_countries, 8);
1425 assert_eq!(stats.max_nodes_per_64, 1);
1426 assert_eq!(stats.max_nodes_per_48, 3);
1427 assert_eq!(stats.max_nodes_per_32, 10);
1428 }
1429
1430 #[test]
1431 fn test_multiple_same_subnet_nodes() -> Result<()> {
1432 let config = IPDiversityConfig {
1433 max_nodes_per_64: 3, max_nodes_per_48: 5,
1435 max_nodes_per_32: 10,
1436 ..create_test_diversity_config()
1437 };
1438 let mut enforcer = IPDiversityEnforcer::new(config);
1439
1440 let _base_addr = Ipv6Addr::new(
1441 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x0000,
1442 );
1443
1444 for i in 1..=3 {
1446 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, i);
1447 let analysis = enforcer.analyze_ip(addr)?;
1448 assert!(enforcer.can_accept_node(&analysis));
1449 enforcer.add_node(&analysis)?;
1450 }
1451
1452 let addr4 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 4);
1454 let analysis4 = enforcer.analyze_ip(addr4)?;
1455 assert!(!enforcer.can_accept_node(&analysis4));
1456
1457 let stats = enforcer.get_diversity_stats();
1458 assert_eq!(stats.total_64_subnets, 1);
1459 assert_eq!(stats.max_nodes_per_64, 3);
1460
1461 Ok(())
1462 }
1463
1464 #[test]
1465 fn test_asn_and_country_tracking() -> Result<()> {
1466 let config = create_test_diversity_config();
1467 let mut enforcer = IPDiversityEnforcer::new(config);
1468
1469 let ipv6_addr = create_test_ipv6();
1471 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1472 analysis.asn = Some(64512);
1473 analysis.country = Some("US".to_string());
1474
1475 enforcer.add_node(&analysis)?;
1476
1477 assert_eq!(enforcer.asn_counts.get(&64512), Some(&1));
1478 assert_eq!(enforcer.country_counts.get("US"), Some(&1));
1479
1480 enforcer.remove_node(&analysis);
1482 assert!(!enforcer.asn_counts.contains_key(&64512));
1483 assert!(!enforcer.country_counts.contains_key("US"));
1484
1485 Ok(())
1486 }
1487
1488 #[test]
1489 fn test_reputation_mixed_interactions() {
1490 let mut manager = ReputationManager::new(0.1, 0.1);
1491 let peer_id = "test_peer".to_string();
1492
1493 for i in 0..15 {
1495 let success = i % 3 != 0; manager.update_reputation(&peer_id, success, Duration::from_millis(100 + i * 10));
1497 }
1498
1499 let reputation = manager.get_reputation(&peer_id).unwrap();
1500 assert!(reputation.response_rate > 0.55);
1503 assert!(reputation.response_rate < 0.85);
1504 assert_eq!(reputation.interaction_count, 15);
1505 }
1506}