1#![no_std]
5#![cfg_attr(docsrs, feature(doc_auto_cfg))]
6#![doc = include_str!("../README.md")]
7#![forbid(unsafe_code)]
8#![warn(missing_docs)]
9
10use core::mem::size_of;
11
12#[cfg(feature = "zeroize")]
13use zeroize::{Zeroize, ZeroizeOnDrop};
14
15#[inline(always)]
17pub const fn pad(n: usize) -> u64 {
18 0x80_u64 << (56 - 8 * n)
19}
20
21#[inline(always)]
23const fn round_constant(round: u64) -> u64 {
24 ((0xfu64 - round) << 4) | round
25}
26
27#[derive(Clone, Debug, Default)]
31pub struct State {
32 x: [u64; 5],
33}
34
35const fn round(x: [u64; 5], c: u64) -> [u64; 5] {
37 let x0 = x[0] ^ x[4];
39 let x2 = x[2] ^ x[1] ^ c; let x4 = x[4] ^ x[3];
41
42 let tx0 = x0 ^ (!x[1] & x2);
43 let tx1 = x[1] ^ (!x2 & x[3]);
44 let tx2 = x2 ^ (!x[3] & x4);
45 let tx3 = x[3] ^ (!x4 & x0);
46 let tx4 = x4 ^ (!x0 & x[1]);
47 let tx1 = tx1 ^ tx0;
48 let tx3 = tx3 ^ tx2;
49 let tx0 = tx0 ^ tx4;
50
51 let x0 = tx0 ^ tx0.rotate_right(9);
53 let x1 = tx1 ^ tx1.rotate_right(22);
54 let x2 = tx2 ^ tx2.rotate_right(5);
55 let x3 = tx3 ^ tx3.rotate_right(7);
56 let x4 = tx4 ^ tx4.rotate_right(34);
57 [
58 tx0 ^ x0.rotate_right(19),
59 tx1 ^ x1.rotate_right(39),
60 !(tx2 ^ x2.rotate_right(1)),
61 tx3 ^ x3.rotate_right(10),
62 tx4 ^ x4.rotate_right(7),
63 ]
64}
65
66impl State {
67 pub fn new(x0: u64, x1: u64, x2: u64, x3: u64, x4: u64) -> Self {
69 State {
70 x: [x0, x1, x2, x3, x4],
71 }
72 }
73
74 #[cfg(not(feature = "no_unroll"))]
75 pub fn permute_12(&mut self) {
77 self.x = round(
81 round(
82 round(
83 round(
84 round(
85 round(
86 round(
87 round(
88 round(round(round(round(self.x, 0xf0), 0xe1), 0xd2), 0xc3),
89 0xb4,
90 ),
91 0xa5,
92 ),
93 0x96,
94 ),
95 0x87,
96 ),
97 0x78,
98 ),
99 0x69,
100 ),
101 0x5a,
102 ),
103 0x4b,
104 );
105 }
106
107 #[cfg(feature = "no_unroll")]
108 pub fn permute_12(&mut self) {
110 self.x = [
111 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b,
112 ]
113 .into_iter()
114 .fold(self.x, round);
115 }
116
117 #[cfg(not(feature = "no_unroll"))]
118 pub fn permute_8(&mut self) {
120 self.x = round(
121 round(
122 round(
123 round(
124 round(round(round(round(self.x, 0xb4), 0xa5), 0x96), 0x87),
125 0x78,
126 ),
127 0x69,
128 ),
129 0x5a,
130 ),
131 0x4b,
132 );
133 }
134
135 #[cfg(feature = "no_unroll")]
136 pub fn permute_8(&mut self) {
138 self.x = [0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b]
139 .into_iter()
140 .fold(self.x, round);
141 }
142
143 #[cfg(not(feature = "no_unroll"))]
144 pub fn permute_6(&mut self) {
146 self.x = round(
147 round(
148 round(round(round(round(self.x, 0x96), 0x87), 0x78), 0x69),
149 0x5a,
150 ),
151 0x4b,
152 );
153 }
154
155 #[cfg(feature = "no_unroll")]
156 pub fn permute_6(&mut self) {
158 self.x = [0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b]
159 .into_iter()
160 .fold(self.x, round);
161 }
162
163 pub fn permute_1(&mut self) {
165 self.x = round(self.x, 0x4b);
166 }
167
168 pub fn permute_n(&mut self, rounds: usize) {
172 debug_assert!(rounds <= 12);
173
174 let start = 12 - rounds;
175 self.x = (start..12).fold(self.x, |x, round_index| {
176 round(x, round_constant(round_index as u64))
177 });
178 }
179
180 pub fn as_bytes(&self) -> [u8; 40] {
182 let mut bytes = [0u8; size_of::<u64>() * 5];
183 for (dst, src) in bytes
184 .chunks_exact_mut(size_of::<u64>())
185 .zip(self.x.into_iter())
186 {
187 dst.copy_from_slice(&u64::to_be_bytes(src));
188 }
189 bytes
190 }
191}
192
193impl core::ops::Index<usize> for State {
194 type Output = u64;
195
196 #[inline(always)]
197 fn index(&self, index: usize) -> &Self::Output {
198 &self.x[index]
199 }
200}
201
202impl core::ops::IndexMut<usize> for State {
203 #[inline(always)]
204 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
205 &mut self.x[index]
206 }
207}
208
209impl TryFrom<&[u64]> for State {
210 type Error = ();
211
212 fn try_from(value: &[u64]) -> Result<Self, Self::Error> {
213 match value.len() {
214 5 => Ok(Self::new(value[0], value[1], value[2], value[3], value[4])),
215 _ => Err(()),
216 }
217 }
218}
219
220impl From<&[u64; 5]> for State {
221 fn from(value: &[u64; 5]) -> Self {
222 Self { x: *value }
223 }
224}
225
226impl TryFrom<&[u8]> for State {
227 type Error = ();
228
229 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
230 if value.len() != core::mem::size_of::<u64>() * 5 {
231 return Err(());
232 }
233
234 let mut state = Self::default();
235 for (src, dst) in value
236 .chunks_exact(core::mem::size_of::<u64>())
237 .zip(state.x.iter_mut())
238 {
239 *dst = u64::from_be_bytes(src.try_into().unwrap());
240 }
241 Ok(state)
242 }
243}
244
245impl From<&[u8; size_of::<u64>() * 5]> for State {
246 fn from(value: &[u8; size_of::<u64>() * 5]) -> Self {
247 let mut state = Self::default();
248 for (src, dst) in value
249 .chunks_exact(core::mem::size_of::<u64>())
250 .zip(state.x.iter_mut())
251 {
252 *dst = u64::from_be_bytes(src.try_into().unwrap());
253 }
254 state
255 }
256}
257
258impl AsRef<[u64]> for State {
259 fn as_ref(&self) -> &[u64] {
260 &self.x
261 }
262}
263
264#[cfg(feature = "zeroize")]
265impl Drop for State {
266 fn drop(&mut self) {
267 self.x.zeroize();
268 }
269}
270
271#[cfg(feature = "zeroize")]
272impl ZeroizeOnDrop for State {}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 #[test]
279 fn pad_0to7() {
280 assert_eq!(pad(0), 0x8000000000000000);
281 assert_eq!(pad(1), 0x80000000000000);
282 assert_eq!(pad(2), 0x800000000000);
283 assert_eq!(pad(3), 0x8000000000);
284 assert_eq!(pad(4), 0x80000000);
285 assert_eq!(pad(5), 0x800000);
286 assert_eq!(pad(6), 0x8000);
287 assert_eq!(pad(7), 0x80);
288 }
289
290 #[test]
291 fn round_constants() {
292 assert_eq!(round_constant(0), 0xf0);
293 assert_eq!(round_constant(1), 0xe1);
294 assert_eq!(round_constant(2), 0xd2);
295 assert_eq!(round_constant(3), 0xc3);
296 assert_eq!(round_constant(4), 0xb4);
297 assert_eq!(round_constant(5), 0xa5);
298 assert_eq!(round_constant(6), 0x96);
299 assert_eq!(round_constant(7), 0x87);
300 assert_eq!(round_constant(8), 0x78);
301 assert_eq!(round_constant(9), 0x69);
302 assert_eq!(round_constant(10), 0x5a);
303 assert_eq!(round_constant(11), 0x4b);
304 }
305
306 #[test]
307 fn one_round() {
308 let state = round(
309 [
310 0x0123456789abcdef,
311 0x23456789abcdef01,
312 0x456789abcdef0123,
313 0x6789abcdef012345,
314 0x89abcde01234567f,
315 ],
316 0x1f,
317 );
318 assert_eq!(
319 state,
320 [
321 0x3c1748c9be2892ce,
322 0x5eafb305cd26164f,
323 0xf9470254bb3a4213,
324 0xf0428daf0c5d3948,
325 0x281375af0b294899
326 ]
327 );
328 }
329
330 #[test]
331 fn state_permute_12() {
332 let mut state = State::new(
333 0x0123456789abcdef,
334 0xef0123456789abcd,
335 0xcdef0123456789ab,
336 0xabcdef0123456789,
337 0x89abcdef01234567,
338 );
339 state.permute_12();
340 assert_eq!(state[0], 0x206416dfc624bb14);
341 assert_eq!(state[1], 0x1b0c47a601058aab);
342 assert_eq!(state[2], 0x8934cfc93814cddd);
343 assert_eq!(state[3], 0xa9738d287a748e4b);
344 assert_eq!(state[4], 0xddd934f058afc7e1);
345 }
346
347 #[test]
348 fn state_permute_6() {
349 let mut state = State::new(
350 0x0123456789abcdef,
351 0xef0123456789abcd,
352 0xcdef0123456789ab,
353 0xabcdef0123456789,
354 0x89abcdef01234567,
355 );
356 state.permute_6();
357 assert_eq!(state[0], 0xc27b505c635eb07f);
358 assert_eq!(state[1], 0xd388f5d2a72046fa);
359 assert_eq!(state[2], 0x9e415c204d7b15e7);
360 assert_eq!(state[3], 0xce0d71450fe44581);
361 assert_eq!(state[4], 0xdd7c5fef57befe48);
362 }
363
364 #[test]
365 fn state_permute_8() {
366 let mut state = State::new(
367 0x0123456789abcdef,
368 0xef0123456789abcd,
369 0xcdef0123456789ab,
370 0xabcdef0123456789,
371 0x89abcdef01234567,
372 );
373 state.permute_8();
374 assert_eq!(state[0], 0x67ed228272f46eee);
375 assert_eq!(state[1], 0x80bc0b097aad7944);
376 assert_eq!(state[2], 0x2fa599382c6db215);
377 assert_eq!(state[3], 0x368133fae2f7667a);
378 assert_eq!(state[4], 0x28cefb195a7c651c);
379 }
380
381 #[test]
382 fn state_permute_n() {
383 let mut state = State::new(
384 0x0123456789abcdef,
385 0xef0123456789abcd,
386 0xcdef0123456789ab,
387 0xabcdef0123456789,
388 0x89abcdef01234567,
389 );
390 let mut state2 = state.clone();
391
392 state.permute_6();
393 state2.permute_n(6);
394 assert_eq!(state.x, state2.x);
395
396 state.permute_8();
397 state2.permute_n(8);
398 assert_eq!(state.x, state2.x);
399
400 state.permute_12();
401 state2.permute_n(12);
402 assert_eq!(state.x, state2.x);
403 }
404
405 #[test]
406 fn state_convert_bytes() {
407 let state = State::new(
408 0x0123456789abcdef,
409 0xef0123456789abcd,
410 0xcdef0123456789ab,
411 0xabcdef0123456789,
412 0x89abcdef01234567,
413 );
414 let bytes = state.as_bytes();
415
416 let state2 = State::try_from(&bytes[..]);
418 assert_eq!(state2.expect("try_from bytes").x, state.x);
419
420 let state2 = State::from(&bytes);
421 assert_eq!(state2.x, state.x);
422 }
423}