twox_hash/xxhash3/
secret.rs

1use core::{hint::assert_unchecked, mem};
2
3use super::SliceBackport as _;
4
5#[cfg(feature = "xxhash3_128")]
6use super::pairs_of_u64_bytes;
7
8/// The minimum length of a secret.
9pub const SECRET_MINIMUM_LENGTH: usize = 136;
10
11#[repr(transparent)]
12pub struct Secret([u8]);
13
14impl Secret {
15    #[inline]
16    pub fn new(bytes: &[u8]) -> Result<&Self, Error> {
17        // Safety: We check for validity before returning.
18        unsafe {
19            let this = Self::new_unchecked(bytes);
20            if this.is_valid() {
21                Ok(this)
22            } else {
23                Err(Error(()))
24            }
25        }
26    }
27
28    /// # Safety
29    ///
30    /// You must ensure that the secret byte length is >=
31    /// SECRET_MINIMUM_LENGTH.
32    #[inline]
33    pub const unsafe fn new_unchecked(bytes: &[u8]) -> &Self {
34        // Safety: We are `#[repr(transparent)]`. It's up to the
35        // caller to ensure the length
36        unsafe { mem::transmute(bytes) }
37    }
38
39    #[inline]
40    #[cfg(feature = "xxhash3_64")]
41    pub fn for_64(&self) -> Secret64BitView<'_> {
42        Secret64BitView(self)
43    }
44
45    #[inline]
46    #[cfg(feature = "xxhash3_128")]
47    pub fn for_128(&self) -> Secret128BitView<'_> {
48        Secret128BitView(self)
49    }
50
51    #[inline]
52    pub fn words_for_17_to_128(&self) -> &[[u8; 16]] {
53        self.reassert_preconditions();
54
55        let (words, _) = self.0.bp_as_chunks();
56        words
57    }
58
59    /// # Safety
60    ///
61    /// `i` must be less than the number of stripes in the secret
62    /// ([`Self::n_stripes`][]).
63    #[inline]
64    pub unsafe fn stripe(&self, i: usize) -> &[u8; 64] {
65        self.reassert_preconditions();
66
67        // Safety: The caller has ensured that `i` is
68        // in-bounds. `&[u8]` and `&[u8; 64]` have the same alignment.
69        unsafe {
70            debug_assert!(i < self.n_stripes());
71            &*self.0.get_unchecked(i * 8..).as_ptr().cast()
72        }
73    }
74
75    #[inline]
76    pub fn last_stripe(&self) -> &[u8; 64] {
77        self.reassert_preconditions();
78
79        self.0.last_chunk().unwrap()
80    }
81
82    #[inline]
83    pub fn last_stripe_secret_better_name(&self) -> &[u8; 64] {
84        self.reassert_preconditions();
85
86        self.0[self.0.len() - 71..].first_chunk().unwrap()
87    }
88
89    #[inline]
90    pub fn final_secret(&self) -> &[u8; 64] {
91        self.reassert_preconditions();
92
93        self.0[11..].first_chunk().unwrap()
94    }
95
96    #[inline]
97    pub fn len(&self) -> usize {
98        self.0.len()
99    }
100
101    #[inline]
102    pub fn n_stripes(&self) -> usize {
103        // stripes_per_block
104        (self.len() - 64) / 8
105    }
106
107    #[inline(always)]
108    fn reassert_preconditions(&self) {
109        // Safety: The length of the bytes was checked at value
110        // construction time.
111        unsafe {
112            debug_assert!(self.is_valid());
113            assert_unchecked(self.is_valid());
114        }
115    }
116
117    #[inline(always)]
118    pub fn is_valid(&self) -> bool {
119        self.0.len() >= SECRET_MINIMUM_LENGTH
120    }
121}
122
123#[derive(Copy, Clone)]
124#[cfg(feature = "xxhash3_64")]
125pub struct Secret64BitView<'a>(&'a Secret);
126
127#[cfg(feature = "xxhash3_64")]
128impl<'a> Secret64BitView<'a> {
129    #[inline]
130    pub fn words_for_0(self) -> [u64; 2] {
131        self.0.reassert_preconditions();
132
133        let (q, _) = self.b()[56..].bp_as_chunks();
134        [q[0], q[1]].map(u64::from_le_bytes)
135    }
136
137    #[inline]
138    pub fn words_for_1_to_3(self) -> [u32; 2] {
139        self.0.reassert_preconditions();
140
141        let (q, _) = self.b().bp_as_chunks();
142        [q[0], q[1]].map(u32::from_le_bytes)
143    }
144
145    #[inline]
146    pub fn words_for_4_to_8(self) -> [u64; 2] {
147        self.0.reassert_preconditions();
148
149        let (q, _) = self.b()[8..].bp_as_chunks();
150        [q[0], q[1]].map(u64::from_le_bytes)
151    }
152
153    #[inline]
154    pub fn words_for_9_to_16(self) -> [u64; 4] {
155        self.0.reassert_preconditions();
156
157        let (q, _) = self.b()[24..].bp_as_chunks();
158        [q[0], q[1], q[2], q[3]].map(u64::from_le_bytes)
159    }
160
161    #[inline]
162    pub fn words_for_127_to_240_part1(self) -> &'a [[u8; 16]] {
163        self.0.reassert_preconditions();
164
165        let (ss, _) = self.b().bp_as_chunks();
166        ss
167    }
168
169    #[inline]
170    pub fn words_for_127_to_240_part2(self) -> &'a [[u8; 16]] {
171        self.0.reassert_preconditions();
172
173        let (ss, _) = self.b()[3..].bp_as_chunks();
174        ss
175    }
176
177    #[inline]
178    pub fn words_for_127_to_240_part3(self) -> &'a [u8; 16] {
179        self.0.reassert_preconditions();
180
181        self.b()[119..].first_chunk().unwrap()
182    }
183
184    fn b(self) -> &'a [u8] {
185        &(self.0).0
186    }
187}
188
189#[derive(Copy, Clone)]
190#[cfg(feature = "xxhash3_128")]
191pub struct Secret128BitView<'a>(&'a Secret);
192
193#[cfg(feature = "xxhash3_128")]
194impl<'a> Secret128BitView<'a> {
195    #[inline]
196    pub fn words_for_0(self) -> [u64; 4] {
197        self.0.reassert_preconditions();
198
199        let (q, _) = self.b()[64..].bp_as_chunks();
200        [q[0], q[1], q[2], q[3]].map(u64::from_le_bytes)
201    }
202
203    #[inline]
204    pub fn words_for_1_to_3(self) -> [u32; 4] {
205        self.0.reassert_preconditions();
206
207        let (q, _) = self.b().bp_as_chunks();
208        [q[0], q[1], q[2], q[3]].map(u32::from_le_bytes)
209    }
210
211    #[inline]
212    pub fn words_for_4_to_8(self) -> [u64; 2] {
213        self.0.reassert_preconditions();
214
215        let (q, _) = self.b()[16..].bp_as_chunks();
216        [q[0], q[1]].map(u64::from_le_bytes)
217    }
218
219    #[inline]
220    pub fn words_for_9_to_16(self) -> [u64; 4] {
221        self.0.reassert_preconditions();
222
223        let (q, _) = self.b()[32..].bp_as_chunks();
224        [q[0], q[1], q[2], q[3]].map(u64::from_le_bytes)
225    }
226
227    #[inline]
228    pub fn words_for_127_to_240_part1(self) -> &'a [[[u8; 16]; 2]] {
229        self.0.reassert_preconditions();
230
231        pairs_of_u64_bytes(self.b())
232    }
233
234    #[inline]
235    pub fn words_for_127_to_240_part2(self) -> &'a [[[u8; 16]; 2]] {
236        self.0.reassert_preconditions();
237
238        pairs_of_u64_bytes(&self.b()[3..])
239    }
240
241    #[inline]
242    pub fn words_for_127_to_240_part3(self) -> &'a [[u8; 16]; 2] {
243        self.0.reassert_preconditions();
244
245        pairs_of_u64_bytes(&self.b()[103..]).first().unwrap()
246    }
247
248    #[inline]
249    pub fn final_secret(self) -> &'a [u8; 64] {
250        self.0.reassert_preconditions();
251
252        let b = self.b();
253        b[b.len() - 75..].first_chunk().unwrap()
254    }
255
256    fn b(self) -> &'a [u8] {
257        &(self.0).0
258    }
259}
260
261#[derive(Debug)]
262pub struct Error(());
263
264impl core::error::Error for Error {}
265
266impl core::fmt::Display for Error {
267    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
268        write!(
269            f,
270            "The secret must have at least {SECRET_MINIMUM_LENGTH} bytes"
271        )
272    }
273}