shadow-network 0.1.0

Covert peer-to-peer communication infrastructure with steganography, onion routing, and traffic analysis resistance
//! Phase 2 Demo — showcases all new capabilities:
//!   • P2P Transport (libp2p Swarm)
//!   • DHT Replication
//!   • E2E Encrypted Messaging
//!   • Steganographic Data Transfer
//!
//! Run with: cargo run --example phase2_demo

use bytes::Bytes;
use shadow_core::{PeerId, PeerInfo, Packet, PacketType};

fn main() {
    println!("╔══════════════════════════════════════════════════════╗");
    println!("║      Shadow Network — Phase 2 Demo                  ║");
    println!("╚══════════════════════════════════════════════════════╝\n");

    demo_transport_config();
    demo_dht_replication();
    demo_messaging();
    demo_stego_transport();

    println!("\nAll Phase 2 subsystems operational.");
    println!("   12 crates | 125 tests | P2P + Replication + E2E + Stego");
}

// ─── 1. P2P Transport ──────────────────────────────────────────────────────

fn demo_transport_config() {
    use transport::{P2PConfig, ShadowSwarm};

    println!("━━━ 1. P2P Transport (libp2p) ━━━━━━━━━━━━━━━━━━━━━━━━━");

    let config = P2PConfig::default();
    println!("  Listen addresses:  {:?}", config.listen_addresses);
    println!("  Bootstrap peers:   {:?}", config.bootstrap_peers);
    println!("  mDNS enabled:      {}", config.enable_mdns);
    println!("  Idle timeout:      {:?}", config.idle_timeout);
    println!("  Gossipsub interval:{:?}", config.gossipsub_heartbeat);

    let custom = P2PConfig::with_port(9090)
        .add_bootstrap("/ip4/192.168.1.1/tcp/9090")
        .add_bootstrap("/ip4/10.0.0.1/tcp/9090");
    println!("  Custom config:     port=9090, {} bootstrap peers", custom.bootstrap_peers.len());

    println!("  ShadowSwarm ready (TCP+Noise+Yamux, Gossipsub, Kademlia, mDNS)\n");
}

// ─── 2. DHT Replication ────────────────────────────────────────────────────

fn demo_dht_replication() {
    use dht::{DHTNode, NodeConfig, ReplicationManager, ReplicationConfig};

    println!("━━━ 2. DHT Replication ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

    let local_id = PeerId::random();
    let dht = DHTNode::new(local_id, NodeConfig::default());

    // Add some peers
    let peers: Vec<PeerInfo> = (1..=6).map(|i| {
        PeerInfo::new(
            PeerId::from_bytes([i; 32]),
            vec![format!("/ip4/10.0.0.{}/tcp/9000", i)],
            [i; 32],
            [i; 32],
        )
    }).collect();
    for p in &peers {
        let _ = dht.add_peer(p.clone());
    }
    println!("  Peers in routing table: {}", dht.peer_count());

    // Store a value
    let key = *crypto::hash::hash_data(b"important-document").as_bytes();
    let value = Bytes::from_static(b"classified content");
    dht.store_value(key, value.clone(), [0u8; 32]).unwrap();
    println!("  Stored value: key={}", hex::encode(&key[..8]));

    // Schedule replication
    let mut repl = ReplicationManager::new(ReplicationConfig {
        factor: 3,
        ..Default::default()
    });

    let tasks = repl.schedule_replication(key, value, &peers);
    println!("  Replication tasks:  {}", tasks.len());
    for task in &tasks {
        println!("    → replicate to peer {}", task.target_peer);
    }

    // Confirm replicas
    for task in &tasks {
        repl.confirm_replication(key, task.target_peer);
    }
    let stats = repl.stats();
    println!("  Replica count:     {}/{}", repl.replica_count(&key), stats.total_keys);
    println!("  Fully replicated:  {}", stats.fully_replicated);
    println!("  Under-replicated:  {}", stats.under_replicated);

    // Simulate peer loss
    let lost = tasks[0].target_peer;
    let re_tasks = repl.handle_peer_lost(&lost, &dht);
    println!("  Peer {} lost → {} re-replication tasks", lost, re_tasks.len());
    println!("  DHT replication fully operational\n");
}

// ─── 3. E2E Encrypted Messaging ────────────────────────────────────────────

fn demo_messaging() {
    use messaging::{Message, MessageTarget, MessageContent, SecureChannel, OfflineQueue, Group, GroupManager};
    use messaging::queue::QueuePriority;
    use crypto::{EncryptionKey, SigningKey};

    println!("━━━ 3. E2E Encrypted Messaging ━━━━━━━━━━━━━━━━━━━━━━━");

    let alice_id = PeerId::random();
    let bob_id = PeerId::random();

    // --- Key exchange ---
    let alice_sign = SigningKey::generate();
    let bob_sign = SigningKey::generate();

    let (alice_state, alice_pub) = SecureChannel::initiate(alice_sign.clone(), alice_id);
    let (bob_state, bob_pub) = SecureChannel::initiate(bob_sign.clone(), bob_id);

    let alice_ch = SecureChannel::complete(alice_state, &bob_pub, bob_sign.verify_key()).unwrap();
    let bob_ch = SecureChannel::complete(bob_state, &alice_pub, alice_sign.verify_key()).unwrap();
    println!("  Key exchange:     X25519 DH -- ok");

    // --- Encrypt & decrypt ---
    let msg = Message::text(alice_id, MessageTarget::Direct(bob_id), "Top secret intel");
    println!("  Original message: \"Top secret intel\"");

    let envelope = alice_ch.encrypt_message(&msg).unwrap();
    println!("  Encrypted size:   {} bytes (ChaCha20-Poly1305)", envelope.ciphertext.len());
    println!("  Signature:        {} bytes (Ed25519)", envelope.signature.len());

    let decrypted = bob_ch.decrypt_message(&envelope).unwrap();
    if let MessageContent::Text(t) = &decrypted.content {
        println!("  Decrypted:        \"{}\" -- ok", t);
    }

    // --- Offline queue ---
    let mut queue = OfflineQueue::new();
    let offline_peer = PeerId::random();
    for i in 0..5 {
        let env = alice_ch.encrypt_message(
            &Message::text(alice_id, MessageTarget::Direct(offline_peer), format!("msg {}", i))
        ).unwrap();
        queue.enqueue(offline_peer, env, QueuePriority::Normal);
    }
    println!("  Offline queue:    {} messages for disconnected peer", queue.count_for(&offline_peer));

    let delivered = queue.dequeue_for(&offline_peer);
    println!("  Peer reconnected: delivered {} messages", delivered.len());

    // --- Group chat ---
    let mut groups = GroupManager::new();
    let gid = groups.create_group("Ops Team", alice_id);
    groups.join_group(&gid, bob_id);
    let group = groups.get_group(&gid).unwrap();
    println!("  Group \"{}\":  {} members", group.name, group.member_count());
    println!("  Group key:        {} (auto-rotated on join/leave)", hex::encode(&group.group_key[..8]));
    println!("  E2E messaging fully operational\n");
}

// ─── 4. Steganographic Data Transfer ────────────────────────────────────────

fn demo_stego_transport() {
    use stego_transport::{StegoChannel, StegoChannelConfig, CoverTrafficGenerator, StegoPacketPipeline, PipelineConfig};
    use stego_transport::cover::CoverStyle;

    println!("━━━ 4. Steganographic Data Transfer ━━━━━━━━━━━━━━━━━━━");

    // --- Basic stego channel ---
    let config = StegoChannelConfig {
        width: 128,
        height: 128,
        channels: 4,
        bits_per_channel: 1,
        adaptive: false,
        randomize: false,
        seed: 42,
    };
    let channel = StegoChannel::new(config);
    println!("  Cover image:      128×128 RGBA");
    println!("  Embedding:        1 bit/channel (LSB)");
    println!("  Capacity:         {} bytes per image", channel.capacity());

    let secret = b"covert message hidden in plain sight";
    let stego_image = channel.encode(secret).unwrap();
    println!("  Encoded {} bytes into {} byte image", secret.len(), stego_image.len());

    let extracted = channel.decode(&stego_image).unwrap();
    assert_eq!(&extracted[..secret.len()], secret.as_slice());
    println!("  Extracted:        \"{}\" -- ok", String::from_utf8_lossy(&extracted[..secret.len()]));

    // --- Cover traffic ---
    let cover_gen = CoverTrafficGenerator::new(64, 64);
    for style in [CoverStyle::NaturalNoise, CoverStyle::Gradient, CoverStyle::BlockPattern] {
        let cover = cover_gen.generate(style);
        println!("  Cover {:?}: {} bytes", style, cover.len());
    }

    // --- Full pipeline ---
    let pipeline_cfg = PipelineConfig {
        stego: StegoChannelConfig {
            width: 64,
            height: 64,
            channels: 4,
            bits_per_channel: 2,
            adaptive: false,
            randomize: false,
            seed: 0,
        },
        encrypt: false, // disabled for demo (no shared key needed)
        ..Default::default()
    };
    let mut pipeline = StegoPacketPipeline::unencrypted(pipeline_cfg);

    let packet = Packet::new(
        PacketType::Data,
        Some(PeerId::random()),
        Some(PeerId::random()),
        Bytes::from_static(b"steganographic payload"),
    );
    let stego = pipeline.encode_packet(&packet).unwrap();
    let decoded = pipeline.decode_packet(&stego).unwrap();
    assert_eq!(decoded.payload, Bytes::from_static(b"steganographic payload"));
    println!("  Pipeline:         Packet->Stego->Packet roundtrip -- ok");
    println!("  Capacity:         {} bytes/image", pipeline.capacity());
    println!("  Encoded packets:  {}", pipeline.packets_encoded());

    let dummy = pipeline.generate_dummy_packet().unwrap();
    println!("  Dummy traffic:    {} bytes (indistinguishable)", dummy.len());
    println!("  Steganographic transport fully operational");
}