• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use core::{hint::assert_unchecked, mem};
2 
3 use super::SliceBackport as _;
4 
5 #[cfg(feature = "xxhash3_128")]
6 use super::pairs_of_u64_bytes;
7 
8 /// The minimum length of a secret.
9 pub const SECRET_MINIMUM_LENGTH: usize = 136;
10 
11 #[repr(transparent)]
12 pub struct Secret([u8]);
13 
14 impl Secret {
15     #[inline]
new(bytes: &[u8]) -> Result<&Self, Error>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]
new_unchecked(bytes: &[u8]) -> &Self33     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")]
for_64(&self) -> Secret64BitView<'_>41     pub fn for_64(&self) -> Secret64BitView<'_> {
42         Secret64BitView(self)
43     }
44 
45     #[inline]
46     #[cfg(feature = "xxhash3_128")]
for_128(&self) -> Secret128BitView<'_>47     pub fn for_128(&self) -> Secret128BitView<'_> {
48         Secret128BitView(self)
49     }
50 
51     #[inline]
words_for_17_to_128(&self) -> &[[u8; 16]]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]
stripe(&self, i: usize) -> &[u8; 64]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]
last_stripe(&self) -> &[u8; 64]76     pub fn last_stripe(&self) -> &[u8; 64] {
77         self.reassert_preconditions();
78 
79         self.0.last_chunk().unwrap()
80     }
81 
82     #[inline]
last_stripe_secret_better_name(&self) -> &[u8; 64]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]
final_secret(&self) -> &[u8; 64]90     pub fn final_secret(&self) -> &[u8; 64] {
91         self.reassert_preconditions();
92 
93         self.0[11..].first_chunk().unwrap()
94     }
95 
96     #[inline]
len(&self) -> usize97     pub fn len(&self) -> usize {
98         self.0.len()
99     }
100 
101     #[inline]
n_stripes(&self) -> usize102     pub fn n_stripes(&self) -> usize {
103         // stripes_per_block
104         (self.len() - 64) / 8
105     }
106 
107     #[inline(always)]
reassert_preconditions(&self)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)]
is_valid(&self) -> bool118     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")]
125 pub struct Secret64BitView<'a>(&'a Secret);
126 
127 #[cfg(feature = "xxhash3_64")]
128 impl<'a> Secret64BitView<'a> {
129     #[inline]
words_for_0(self) -> [u64; 2]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]
words_for_1_to_3(self) -> [u32; 2]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]
words_for_4_to_8(self) -> [u64; 2]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]
words_for_9_to_16(self) -> [u64; 4]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]
words_for_127_to_240_part1(self) -> &'a [[u8; 16]]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]
words_for_127_to_240_part2(self) -> &'a [[u8; 16]]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]
words_for_127_to_240_part3(self) -> &'a [u8; 16]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 
b(self) -> &'a [u8]184     fn b(self) -> &'a [u8] {
185         &(self.0).0
186     }
187 }
188 
189 #[derive(Copy, Clone)]
190 #[cfg(feature = "xxhash3_128")]
191 pub struct Secret128BitView<'a>(&'a Secret);
192 
193 #[cfg(feature = "xxhash3_128")]
194 impl<'a> Secret128BitView<'a> {
195     #[inline]
words_for_0(self) -> [u64; 4]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]
words_for_1_to_3(self) -> [u32; 4]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]
words_for_4_to_8(self) -> [u64; 2]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]
words_for_9_to_16(self) -> [u64; 4]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]
words_for_127_to_240_part1(self) -> &'a [[[u8; 16]; 2]]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]
words_for_127_to_240_part2(self) -> &'a [[[u8; 16]; 2]]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]
words_for_127_to_240_part3(self) -> &'a [[u8; 16]; 2]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]
final_secret(self) -> &'a [u8; 64]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 
b(self) -> &'a [u8]256     fn b(self) -> &'a [u8] {
257         &(self.0).0
258     }
259 }
260 
261 #[derive(Debug)]
262 pub struct Error(());
263 
264 impl core::error::Error for Error {}
265 
266 impl core::fmt::Display for Error {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result267     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 }
274