citadel_crypt 0.3.0

Higher-level cryptographic library for the Citadel Protocol
Documentation
use crate::entropy_bank::EntropyBank;

/// The `scrambled_sequence` that is returned by `get_packet_coordinates` is scrambled; the true value of the sequence
/// is NOT given, because it is expected that the values be imprinted upon the packet header and thus are public-facing
#[derive(Debug, Default, Clone)]
pub struct PacketVector {
    /// The group ID of this packet
    pub group_id: u64,
    /// The sequence is the position in the wave ID. Repeating sequences CANNOT exist, and as such,
    /// the drill generator must ensure all values in the port range are non-repeating. TODO: Unique RNG.
    ///
    ///
    /// A wave is a set of packets in scrambled order in respect to the in/out ports. There are a maximum
    /// of multiport_range packets per wave. The wave index starts at 0, and increments to u32::max
    pub wave_id: u32,
    /// The local port from which the packet will leave from, thus implying the sequence
    pub local_port: u16,
    /// The remote port to which the packet will arrive, thus implying the sequence
    pub remote_port: u16,
    /// The original true sequence
    pub true_sequence: usize,
}

use num_integer::Integer;

/// The true sequence should just be the exact order of the data without any consideration of sequence nor wave-ID
pub fn generate_packet_vector(
    true_sequence: usize,
    group_id: u64,
    drill: &EntropyBank,
) -> PacketVector {
    // To get the wave_id, we must floor divide the true sequence by the port range. The remainder is the sequence
    let port_range = &drill.get_multiport_width();
    let (true_wave_id, relative_sequence) = true_sequence.div_mod_floor(port_range);
    // To scramble the true values, we get their corresponding values in the drill
    let (local_port, remote_port) = *drill.scramble_mappings.get(relative_sequence).unwrap();

    PacketVector {
        group_id,
        wave_id: true_wave_id as u32,
        local_port,
        remote_port,
        true_sequence,
    }
}

/// This will return None if the values are invalid
#[inline]
pub fn generate_packet_coordinates_inv(
    wave_id: u32,
    src_port: u16,
    local_port: u16,
    scramble_drill: &EntropyBank,
) -> Option<usize> {
    for (idx, (in_port, out_port)) in scramble_drill.scramble_mappings.iter().enumerate() {
        if *in_port == src_port && *out_port == local_port {
            let port_range = scramble_drill.scramble_mappings.len();
            let true_position = (wave_id as usize * port_range) + idx;
            return Some(true_position);
        }
    }

    None
}