intentra 0.1.3

High-performance multi-peer UDP transport protocol with cryptographic authentication and DoS protection
Documentation
use intentra::crypto::{compute_cookie, CryptoContext};
use intentra::intent::Intent;
use intentra::packet::{PacketHeader, FLAG_ACK, FLAG_DATA, FLAG_HS};
use intentra::replay::ReplayWindow;
use std::net::SocketAddr;

#[test]
fn packet_encode_decode_roundtrip() {
    let header = PacketHeader {
        flags: FLAG_DATA,
        intent: Intent::Reliable,
        priority: 2,
        payload_len: 100,
        conn_id: 12345,
        seq: 1,
        ack: 0,
    };

    let mut buf = [0u8; 16];
    assert!(header.encode(&mut buf).is_ok());

    let decoded = PacketHeader::decode(&buf);
    assert!(decoded.is_ok());

    let decoded = decoded.unwrap();
    assert_eq!(decoded.flags, FLAG_DATA);
    assert_eq!(decoded.intent, Intent::Reliable);
    assert_eq!(decoded.priority, 2);
    assert_eq!(decoded.payload_len, 100);
    assert_eq!(decoded.conn_id, 12345);
    assert_eq!(decoded.seq, 1);
    assert_eq!(decoded.ack, 0);
}

#[test]
fn crypto_encrypt_decrypt_roundtrip() {
    let key = [0x42u8; 32];
    let ctx = CryptoContext::new(&key, &key);

    let conn_id = 1u32;
    let seq = 5u32;
    let header = [0u8; 16];
    let plaintext = b"Hello, World!";

    let encrypted = ctx.encrypt(conn_id, seq, &header, plaintext);
    assert!(encrypted.is_ok());

    let ciphertext = encrypted.unwrap();
    assert!(ciphertext.len() > plaintext.len());

    let decrypted = ctx.decrypt(conn_id, seq, &header, &ciphertext[16..]);
    assert!(decrypted.is_ok());

    let decrypted = decrypted.unwrap();
    assert_eq!(decrypted, plaintext);
}

#[test]
fn replay_window_accept_new_sequence() {
    let mut window = ReplayWindow::new(64);

    assert!(window.check(1));
    assert!(window.check(2));
    assert!(window.check(3));
    assert!(window.check(5));
}

#[test]
fn replay_window_reject_duplicate() {
    let mut window = ReplayWindow::new(64);

    assert!(window.check(1));
    assert!(window.check(2));

    assert!(!window.check(1));
    assert!(!window.check(2));
}

#[test]
fn replay_window_reject_old_packets() {
    let mut window = ReplayWindow::new(64);

    for i in 1..=70 {
        let _ = window.check(i);
    }

    assert!(!window.check(1));
    assert!(!window.check(10));
}

#[test]
fn rate_limit_token_bucket() {
    use std::time::Instant;

    const RATE_LIMIT_TOKENS_PER_SECOND: f64 = 10000.0;
    const RATE_LIMIT_BURST: f64 = 500.0;

    let mut tokens = RATE_LIMIT_BURST;
    let last_refill = Instant::now();

    for _ in 0..500 {
        tokens -= 1.0;
        assert!(tokens >= 0.0);
    }

    assert!(tokens >= 0.0);

    let elapsed = Instant::now().duration_since(last_refill).as_secs_f64();
    let tokens_to_add = elapsed * RATE_LIMIT_TOKENS_PER_SECOND;
    tokens = (tokens + tokens_to_add).min(RATE_LIMIT_BURST);

    assert!(tokens <= RATE_LIMIT_BURST);
}

#[test]
fn cookie_computation_deterministic() {
    let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();

    let cookie1 = compute_cookie(&addr);
    let cookie2 = compute_cookie(&addr);

    assert_eq!(cookie1, cookie2);
}

#[test]
fn cookie_differs_by_address() {
    let addr1: SocketAddr = "127.0.0.1:8080".parse().unwrap();
    let addr2: SocketAddr = "127.0.0.1:8081".parse().unwrap();

    let cookie1 = compute_cookie(&addr1);
    let cookie2 = compute_cookie(&addr2);

    assert_ne!(cookie1, cookie2);
}

#[test]
fn ack_packet_validation() {
    let header = PacketHeader {
        flags: FLAG_ACK,
        intent: Intent::Reliable,
        priority: 0,
        payload_len: 0,
        conn_id: 1,
        seq: 0,
        ack: 100,
    };

    let mut buf = [0u8; 16];
    assert!(header.encode(&mut buf).is_ok());

    let decoded = PacketHeader::decode(&buf);
    assert!(decoded.is_ok());
}

#[test]
fn handshake_packet_requires_reliable() {
    let header = PacketHeader {
        flags: FLAG_HS,
        intent: Intent::Realtime,
        priority: 0,
        payload_len: 32,
        conn_id: 1,
        seq: 0,
        ack: 0,
    };

    let mut buf = [0u8; 16];
    let result = header.encode(&mut buf);
    assert!(result.is_err());
}