s2n_quic_core/stateless_reset/
token.rs1use s2n_codec::{
7 decoder_value,
8 zerocopy::{FromBytes, Immutable, IntoBytes, Unaligned},
9 Encoder, EncoderValue,
10};
11use subtle::ConstantTimeEq;
12
13pub const LEN: usize = 128 / 8;
20
21#[allow(clippy::derived_hash_with_manual_eq)]
25#[derive(Copy, Clone, Debug, Eq, Hash, FromBytes, IntoBytes, Unaligned, Immutable)]
26#[cfg_attr(
27 any(test, feature = "generator"),
28 derive(bolero_generator::TypeGenerator)
29)]
30#[repr(C)]
31pub struct Token([u8; LEN]);
32
33impl Token {
34 pub const ZEROED: Self = Self([0; LEN]);
36
37 pub fn into_inner(self) -> [u8; LEN] {
39 self.0
40 }
41}
42
43impl From<[u8; LEN]> for Token {
44 fn from(bytes: [u8; LEN]) -> Self {
45 Self(bytes)
46 }
47}
48
49impl TryFrom<&[u8]> for Token {
50 type Error = core::array::TryFromSliceError;
51
52 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
53 let bytes = bytes.try_into()?;
54 Ok(Self(bytes))
55 }
56}
57
58impl AsRef<[u8]> for Token {
59 fn as_ref(&self) -> &[u8] {
60 &self.0[..]
61 }
62}
63
64impl AsMut<[u8]> for Token {
65 fn as_mut(&mut self) -> &mut [u8] {
66 self.0.as_mut()
67 }
68}
69
70impl PartialEq for Token {
71 fn eq(&self, other: &Self) -> bool {
76 self.0.ct_eq(&other.0).into()
77 }
78}
79
80decoder_value!(
81 impl<'a> Token {
82 fn decode(buffer: Buffer) -> Result<Self> {
83 let (value, buffer) = buffer.decode_slice(LEN)?;
84 let value: &[u8] = value.into_less_safe_slice();
85 let token = Token::try_from(value).expect("slice len already verified");
86
87 Ok((token, buffer))
88 }
89 }
90);
91
92impl EncoderValue for Token {
93 fn encoding_size(&self) -> usize {
94 LEN
95 }
96
97 fn encode<E: Encoder>(&self, encoder: &mut E) {
98 self.as_ref().encode(encoder)
99 }
100}
101
102pub trait Generator: 'static + Send {
104 const ENABLED: bool = true;
109
110 fn generate(&mut self, local_connection_id: &[u8]) -> Token;
117}
118
119#[cfg(any(test, feature = "testing"))]
120pub mod testing {
121 use crate::{
122 stateless_reset,
123 stateless_reset::token::{Token, LEN},
124 };
125
126 pub const TEST_TOKEN_1: Token = Token(11111111123456578987654321u128.to_be_bytes());
127 pub const TEST_TOKEN_2: Token = Token(222222222123456578987654321u128.to_be_bytes());
128 pub const TEST_TOKEN_3: Token = Token(333333333123456578987654321u128.to_be_bytes());
129 pub const TEST_TOKEN_4: Token = Token(444444444123456578987654321u128.to_be_bytes());
130
131 const KEY: u8 = 123;
132
133 #[derive(Debug, Default)]
134 pub struct Generator();
135
136 impl stateless_reset::token::Generator for Generator {
137 fn generate(&mut self, connection_id: &[u8]) -> Token {
138 let mut token = [0; LEN];
139
140 for (index, byte) in connection_id.as_ref().iter().enumerate() {
141 token[index] = byte ^ KEY;
142 }
143
144 token.into()
145 }
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use crate::stateless_reset::token::{testing::TEST_TOKEN_1, LEN};
152
153 #[test]
159 fn equality_test() {
160 let token_1 = TEST_TOKEN_1;
161 let token_2 = TEST_TOKEN_1;
162
163 assert_eq!(token_1, token_2);
164
165 for i in 0..LEN {
166 let mut token = TEST_TOKEN_1;
167 token.0[i] = !TEST_TOKEN_1.0[i];
168
169 assert_ne!(TEST_TOKEN_1, token);
170 }
171 }
172}