stochastic-routing-extended 1.0.2

SRX (Stochastic Routing eXtended) — a next-generation VPN protocol with stochastic routing, DPI evasion, post-quantum cryptography, and multi-transport channel splitting
Documentation
//! Channel hopping: stochastic activation/deactivation of transports.

use sha2::{Digest, Sha256};

use crate::seed::SeedRng;
use crate::transport::TransportKind;

/// Manages stochastic channel activation/deactivation cycles.
pub struct ChannelHopper {
    rng: SeedRng,
    all_transports: Vec<TransportKind>,
}

impl ChannelHopper {
    pub fn new(rng: SeedRng, transports: Vec<TransportKind>) -> Self {
        Self {
            rng,
            all_transports: transports,
        }
    }

    /// Which transports should be active for `time_slot` (deterministic vs peer with same seed).
    pub fn active_transports(&mut self, time_slot: u64) -> Vec<TransportKind> {
        if self.all_transports.is_empty() {
            return Vec::new();
        }

        let mut hasher = Sha256::new();
        hasher.update(self.rng.seed_bytes());
        hasher.update(time_slot.to_be_bytes());
        let digest = hasher.finalize();

        let mut out = Vec::new();
        for (i, &t) in self.all_transports.iter().enumerate() {
            let byte = digest[(i + 4) % 32];
            if (byte >> (i % 8)) & 1 != 0 {
                out.push(t);
            }
        }

        if out.is_empty() {
            let idx = (digest[0] as usize) % self.all_transports.len();
            out.push(self.all_transports[idx]);
        }

        out
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn peers_agree_on_slot() {
        let kinds = vec![TransportKind::Tcp, TransportKind::Udp];
        let mut a = ChannelHopper::new(SeedRng::new([3u8; 32]), kinds.clone());
        let mut b = ChannelHopper::new(SeedRng::new([3u8; 32]), kinds);
        assert_eq!(a.active_transports(7), b.active_transports(7));
    }

    #[test]
    fn non_empty_when_configured() {
        let kinds = vec![TransportKind::Quic];
        let mut h = ChannelHopper::new(SeedRng::new([9u8; 32]), kinds);
        assert_eq!(h.active_transports(0), vec![TransportKind::Quic]);
    }
}