use crate::{Deserialize, DeserializeBytes, Error, Serialize, SerializeBytes, Size};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct TlsVarInt(u64);
impl TlsVarInt {
pub const MAX: u64 = (1 << 62) - 1;
const MAX_LOG: usize = 3;
#[inline]
pub(crate) fn try_new(value: u64) -> Result<Self, Error> {
if Self::MAX < value {
Err(Error::InvalidVectorLength)
} else {
Ok(Self(value))
}
}
#[inline]
pub const fn value(&self) -> u64 {
self.0
}
pub(crate) const fn bytes_len(&self) -> usize {
let value = self.0;
if value <= 0x3f {
1
} else if value <= 0x3fff {
2
} else if value <= 0x3fff_ffff {
4
} else {
8
}
}
pub(crate) fn write_bytes(&self, buf: &mut [u8]) -> Result<usize, Error> {
let len = self.bytes_len();
if buf.len() < len {
return Err(Error::InvalidVectorLength);
}
let bytes = &mut buf[..len];
match len {
1 => bytes[0] = 0x00,
2 => bytes[0] = 0x40,
4 => bytes[0] = 0x80,
8 => bytes[0] = 0xc0,
_ => {
if !cfg!(fuzzing) {
debug_assert!(false, "Invalid varint len {len}");
}
return Err(Error::LibraryError);
}
}
let mut value = self.0;
for b in bytes.iter_mut().rev() {
*b |= (value & 0xFF) as u8;
value >>= 8;
}
Ok(len)
}
}
impl TryFrom<u64> for TlsVarInt {
type Error = Error;
#[inline]
fn try_from(value: u64) -> Result<Self, Self::Error> {
Self::try_new(value)
}
}
impl From<TlsVarInt> for u64 {
#[inline]
fn from(value: TlsVarInt) -> Self {
value.0
}
}
fn check_min_len(_value: u64, _len: usize) -> Result<(), Error> {
#[cfg(feature = "mls")]
{
let min_len = TlsVarInt::try_new(_value)?.bytes_len();
if min_len != _len {
return Err(Error::InvalidVectorLength);
}
}
Ok(())
}
impl Deserialize for TlsVarInt {
#[cfg(feature = "std")]
#[inline]
fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, Error> {
let mut len_byte = [0u8; 1];
if bytes.read(&mut len_byte)? == 0 {
return Err(Error::EndOfStream);
};
let len_byte = len_byte[0];
let (value, len) = calculate_value(len_byte)?;
let mut value: u64 = value.try_into().map_err(|_| Error::InvalidInput)?;
for _ in 1..len {
let mut next = [0u8; 1];
bytes.read_exact(&mut next)?;
value = (value << 8) + u64::from(next[0]);
}
check_min_len(value, len)?;
Ok(TlsVarInt(value))
}
}
impl DeserializeBytes for TlsVarInt {
#[inline]
fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error>
where
Self: Sized,
{
let (len_byte, mut remainder) = u8::tls_deserialize_bytes(bytes)?;
let (value, len) = calculate_value(len_byte)?;
let mut value: u64 = value.try_into().map_err(|_| Error::InvalidInput)?;
for _ in 1..len {
let (next, next_remainder) = u8::tls_deserialize_bytes(remainder)?;
remainder = next_remainder;
value = (value << 8) + u64::from(next);
}
check_min_len(value, len)?;
Ok((TlsVarInt(value), remainder))
}
}
impl Serialize for TlsVarInt {
#[cfg(feature = "std")]
#[inline]
fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
let mut bytes = [0u8; 8];
let len = self.write_bytes(&mut bytes)?;
writer.write_all(&bytes[..len])?;
Ok(len)
}
}
impl SerializeBytes for TlsVarInt {
#[inline]
fn tls_serialize_bytes(&self) -> Result<alloc::vec::Vec<u8>, Error> {
let len = self.bytes_len();
let mut bytes = alloc::vec![0u8; len];
self.write_bytes(&mut bytes)?;
Ok(bytes)
}
}
impl Size for TlsVarInt {
#[inline]
fn tls_serialized_len(&self) -> usize {
self.bytes_len()
}
}
#[inline(always)]
pub(crate) fn calculate_value(byte: u8) -> Result<(usize, usize), Error> {
let value: usize = (byte & 0x3F).into();
let len_log = (byte >> 6).into();
if !cfg!(fuzzing) {
debug_assert!(len_log <= TlsVarInt::MAX_LOG);
}
if len_log > TlsVarInt::MAX_LOG {
return Err(Error::InvalidVectorLength);
}
let len = match len_log {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
_ => unreachable!(),
};
Ok((value, len))
}
#[cfg(test)]
mod tests {
use super::*;
const TESTS: [(u64, usize, &[u8]); 5] = [
(37, 1, &[0x25]),
(15_293, 2, &[0x7b, 0xbd]),
(494_878_333, 4, &[0x9d, 0x7f, 0x3e, 0x7d]),
(
151_288_809_941_952_652,
8,
&[0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c],
),
(
TlsVarInt::MAX,
8,
&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
),
];
#[test]
fn tls_serialized_len() {
for (value, len, _) in TESTS {
assert_eq!(
TlsVarInt::try_from(value)
.expect("value too large")
.tls_serialized_len(),
len
);
}
}
#[cfg(feature = "std")]
#[test]
fn tls_serialize() {
use crate::alloc::vec::Vec;
for (value, len, bytes) in TESTS {
let mut buf = Vec::new();
let written = Serialize::tls_serialize(
&TlsVarInt::try_from(value).expect("value too large"),
&mut buf,
)
.expect("tls serialize failed");
assert_eq!(written, len, "{value}");
assert_eq!(buf.len(), len, "{value}");
assert_eq!(&buf[..], bytes, "{value}");
}
}
#[test]
fn tls_deserialize_bytes() {
for (value, len, bytes) in TESTS {
assert_eq!(len, bytes.len());
let (out, remainder) =
TlsVarInt::tls_deserialize_bytes(bytes).expect("tls deserialize bytes failed");
assert_eq!(remainder.len(), 0);
assert_eq!(out, TlsVarInt::try_from(value).expect("value too large"));
}
}
#[cfg(feature = "std")]
#[test]
fn tls_deserialize() {
use std::io::Cursor;
for (value, len, bytes) in TESTS {
assert_eq!(len, bytes.len());
let out = TlsVarInt::tls_deserialize(&mut Cursor::new(bytes))
.expect("tls deserialize failed");
assert_eq!(out, TlsVarInt::try_from(value).expect("value too large"));
}
}
#[test]
#[cfg_attr(feature = "mls", should_panic)]
fn non_minimum_size_deserialize_bytes() {
let (out, remaining) =
TlsVarInt::tls_deserialize_bytes(&[0x40, 0x25]).expect("tls deserialize bytes failed");
assert_eq!(remaining.len(), 0);
assert_eq!(out, TlsVarInt(37));
}
#[cfg(feature = "std")]
#[test]
#[cfg_attr(feature = "mls", should_panic)]
fn non_minimum_size_tls_deserialize() {
use std::io::Cursor;
let out = TlsVarInt::tls_deserialize(&mut Cursor::new(&[0x40, 0x25]))
.expect("tls deserialize failed");
assert_eq!(out, TlsVarInt(37));
}
}