mls-spec 2.0.0

This crate is a repository of MLS / RFC9420-related data structures.
Documentation
#![allow(dead_code)]

fn vlvec_overhead(data_len: usize) -> usize {
    const MLS_VLBYTES_MAX_LEN: usize = (1 << 30) - 1;
    debug_assert!(
        data_len <= MLS_VLBYTES_MAX_LEN,
        "The serialized size is above the MLS-defined limits of Variable-Length vectors [actual = {data_len}, max = {MLS_VLBYTES_MAX_LEN}]"
    );

    if data_len <= 0x3f {
        1
    } else if data_len <= 0x3fff {
        2
    } else if data_len <= 0x3fff_ffff {
        4
    } else {
        8
    }
}

#[inline]
pub fn tls_serialized_len_as_vlvec(data_len: usize) -> usize {
    vlvec_overhead(data_len) + data_len
}

pub fn write_vlvec_prefix<W: std::io::Write>(
    data_len: usize,
    writer: &mut W,
) -> Result<usize, tls_codec::Error> {
    let overhead = vlvec_overhead(data_len);
    let prefix: u8 = match overhead {
        1 => 0x00,
        2 => 0x40,
        4 => 0x80,
        8 => 0xC0,
        _ => unreachable!(),
    };
    let mut data_len_mix = data_len;

    for i in 0..overhead {
        let base = if i == 0 { prefix } else { 0x00 };
        let byte = base | (data_len_mix & 0xFF) as u8;
        writer.write_all(&[byte])?;
        data_len_mix >>= 8;
    }

    Ok(overhead)
}

pub mod bytes {
    use tls_codec::{Deserialize as _, Serialize as _, Size as _, VLByteSlice, VLBytes};

    pub fn tls_serialized_len(v: &[u8]) -> usize {
        VLByteSlice(v).tls_serialized_len()
    }

    pub fn tls_serialize<W: std::io::Write>(
        v: &[u8],
        writer: &mut W,
    ) -> Result<usize, tls_codec::Error> {
        VLByteSlice(v).tls_serialize(writer)
    }

    pub fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Vec<u8>, tls_codec::Error> {
        Ok(VLBytes::tls_deserialize(bytes)?.into())
    }
}

pub mod optbytes {
    use tls_codec::{Deserialize as _, Serialize as _, Size as _, VLByteSlice, VLBytes};

    pub fn tls_serialized_len<B: AsRef<[u8]>>(v: &Option<B>) -> usize {
        v.as_ref()
            .map(|v| VLByteSlice(v.as_ref()))
            .tls_serialized_len()
    }

    pub fn tls_serialize<W: std::io::Write, B: AsRef<[u8]>>(
        v: &Option<B>,
        writer: &mut W,
    ) -> Result<usize, tls_codec::Error> {
        v.as_ref()
            .map(|v| VLByteSlice(v.as_ref()))
            .tls_serialize(writer)
    }

    pub fn tls_deserialize<R: std::io::Read>(
        bytes: &mut R,
    ) -> Result<Option<Vec<u8>>, tls_codec::Error> {
        Ok(Option::<VLBytes>::tls_deserialize(bytes)?.map(Into::into))
    }
}

pub mod string {
    pub fn tls_serialized_len(v: &str) -> usize {
        super::bytes::tls_serialized_len(v.as_bytes())
    }

    pub fn tls_serialize<W: std::io::Write>(
        v: &str,
        writer: &mut W,
    ) -> Result<usize, tls_codec::Error> {
        super::bytes::tls_serialize(v.as_bytes(), writer)
    }

    #[allow(dead_code)]
    pub fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<String, tls_codec::Error> {
        super::bytes::tls_deserialize(bytes).and_then(|bytes| {
            String::from_utf8(bytes).map_err(|e| {
                tls_codec::Error::DecodingError(format!("Could not decode utf8 string: {e:?}"))
            })
        })
    }
}