use crate::{
connection,
packet::{number::PacketNumberLen, Tag},
random, stateless_reset,
};
const TAG: u8 = 0b0100_0000;
const TAG_OFFSET: u8 = 2;
const MIN_INDISTINGUISHABLE_PACKET_LEN_WITHOUT_TAG: usize =
core::mem::size_of::<Tag>() + PacketNumberLen::MAX_LEN + connection::id::MAX_LEN + 1;
pub fn min_indistinguishable_packet_len(max_tag_len: usize) -> usize {
MIN_INDISTINGUISHABLE_PACKET_LEN_WITHOUT_TAG + max_tag_len
}
pub fn encode_packet(
token: stateless_reset::Token,
max_tag_len: usize,
triggering_packet_len: usize,
random_generator: &mut dyn random::Generator,
packet_buf: &mut [u8],
) -> Option<usize> {
let min_len = min_indistinguishable_packet_len(max_tag_len);
let max_len = triggering_packet_len
.saturating_sub(1)
.min(packet_buf.len());
if max_len < min_len {
return None;
}
let unpredictable_bits_min_len = min_len - stateless_reset::token::LEN;
let unpredictable_bits_max_len = max_len - stateless_reset::token::LEN;
let unpredictable_bits_len = generate_unpredictable_bits(
random_generator,
unpredictable_bits_min_len,
&mut packet_buf[..unpredictable_bits_max_len],
);
packet_buf[0] = (packet_buf[0] >> TAG_OFFSET) | TAG;
let packet_len = unpredictable_bits_len + stateless_reset::token::LEN;
packet_buf[unpredictable_bits_len..packet_len].copy_from_slice(token.as_ref());
if cfg!(debug_assertions) {
assert!(packet_len >= min_len);
assert!(packet_len <= max_len);
assert!(packet_len < triggering_packet_len);
}
Some(packet_len)
}
fn generate_unpredictable_bits(
random_generator: &mut dyn random::Generator,
min_len: usize,
buffer: &mut [u8],
) -> usize {
let len = random::gen_range_biased(random_generator, min_len..=buffer.len());
random_generator.public_random_fill(&mut buffer[..len]);
len
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{path::MINIMUM_MAX_DATAGRAM_SIZE, stateless_reset::token::testing::TEST_TOKEN_1};
#[test]
#[cfg_attr(miri, ignore)] fn generate_unpredictable_bits_test() {
bolero::check!()
.with_type::<(u8, u16, u16)>()
.cloned()
.for_each(|(seed, mut min, mut max)| {
if min > max {
core::mem::swap(&mut min, &mut max);
}
let mut generator = random::testing::Generator(seed);
let mut buffer = vec![0; max.into()];
let len = generate_unpredictable_bits(&mut generator, min.into(), &mut buffer);
assert!(len >= min.into());
assert!(len <= max.into());
});
}
#[test]
fn unpredictable_bits_are_indistinguishable_from_random() {
const MIN_LEN: usize = 100;
const MAX_LEN: usize = 1000;
let mut generator = random::testing::Generator(123);
let mut buffer = [0; MAX_LEN];
let mut buffer_2 = [0; MAX_LEN];
generate_unpredictable_bits(&mut generator, MIN_LEN, &mut buffer);
generate_unpredictable_bits(&mut generator, MIN_LEN, &mut buffer_2);
assert_ne!(buffer[0..32], buffer_2[0..32]);
}
#[test]
fn encode_packet_test() {
let max_tag_len = 16;
let triggering_packet_len = 600;
let mut generator = random::testing::Generator(123);
let mut buffer = [0; MINIMUM_MAX_DATAGRAM_SIZE as usize];
let packet_len = encode_packet(
TEST_TOKEN_1,
max_tag_len,
triggering_packet_len,
&mut generator,
&mut buffer,
)
.unwrap();
assert!(packet_len < triggering_packet_len);
assert!(matches!(&buffer[0] >> 4, short_tag!()));
assert_eq!(
TEST_TOKEN_1.into_inner(),
buffer[packet_len - stateless_reset::token::LEN..packet_len]
);
}
#[test]
fn min_packet_test() {
let max_tag_len = 16;
let mut triggering_packet_len = min_indistinguishable_packet_len(max_tag_len) + 1;
let mut generator = random::testing::Generator(123);
let mut buffer = [0; MINIMUM_MAX_DATAGRAM_SIZE as usize];
let packet_len = encode_packet(
TEST_TOKEN_1,
max_tag_len,
triggering_packet_len,
&mut generator,
&mut buffer,
);
assert_eq!(packet_len, Some(triggering_packet_len - 1));
triggering_packet_len -= 1;
let packet_len = encode_packet(
TEST_TOKEN_1,
max_tag_len,
triggering_packet_len,
&mut generator,
&mut buffer,
);
assert!(packet_len.is_none());
triggering_packet_len = 0;
let packet_len = encode_packet(
TEST_TOKEN_1,
max_tag_len,
triggering_packet_len,
&mut generator,
&mut buffer,
);
assert!(packet_len.is_none());
}
#[test]
fn max_packet_test() {
let max_tag_len = 16;
let triggering_packet_len = (MINIMUM_MAX_DATAGRAM_SIZE * 2) as usize;
let mut generator = random::testing::Generator(123);
let mut buffer = [0; MINIMUM_MAX_DATAGRAM_SIZE as usize];
let packet_len = encode_packet(
TEST_TOKEN_1,
max_tag_len,
triggering_packet_len,
&mut generator,
&mut buffer,
);
assert!(packet_len.is_some());
assert!(packet_len.unwrap() <= MINIMUM_MAX_DATAGRAM_SIZE as usize);
}
#[test]
#[cfg_attr(miri, ignore)] fn packet_encoding_test() {
let mut buffer = [0; MINIMUM_MAX_DATAGRAM_SIZE as usize];
bolero::check!()
.with_type::<(u8, usize, u16)>()
.cloned()
.for_each(|(seed, triggering_packet_len, max_tag_len)| {
let mut generator = random::testing::Generator(seed);
let packet_len = encode_packet(
TEST_TOKEN_1,
max_tag_len.into(),
triggering_packet_len,
&mut generator,
&mut buffer,
);
let min_len = MIN_INDISTINGUISHABLE_PACKET_LEN_WITHOUT_TAG + max_tag_len as usize;
let max_len = triggering_packet_len.saturating_sub(1).min(buffer.len());
if min_len <= max_len {
assert!(packet_len.is_some());
let packet_len = packet_len.unwrap();
assert!(packet_len <= max_len);
assert!(packet_len >= min_len);
assert!(matches!(&buffer[0] >> 4, short_tag!()));
assert_eq!(
TEST_TOKEN_1.into_inner(),
buffer[packet_len - stateless_reset::token::LEN..packet_len]
);
} else {
assert!(packet_len.is_none());
}
})
}
}