1use core::{
4 convert::{AsMut, AsRef},
5 num::Wrapping,
6 ops::{BitXor, BitXorAssign},
7 slice,
8};
9
10#[cfg(feature = "zeroize")]
11use zeroize::Zeroize;
12
13const TRUNC: u64 = u32::MAX as u64;
14
15#[rustfmt::skip]
16macro_rules! permute_step {
17 ($a:expr, $b:expr, $c:expr, $d:expr) => {
18 $a = (Wrapping($a) + Wrapping($b) + (Wrapping(2) * Wrapping(($a & TRUNC) * ($b & TRUNC)))).0;
19 $d = ($d ^ $a).rotate_right(32);
20 $c = (Wrapping($c) + Wrapping($d) + (Wrapping(2) * Wrapping(($c & TRUNC) * ($d & TRUNC)))).0;
21 $b = ($b ^ $c).rotate_right(24);
22
23 $a = (Wrapping($a) + Wrapping($b) + (Wrapping(2) * Wrapping(($a & TRUNC) * ($b & TRUNC)))).0;
24 $d = ($d ^ $a).rotate_right(16);
25 $c = (Wrapping($c) + Wrapping($d) + (Wrapping(2) * Wrapping(($c & TRUNC) * ($d & TRUNC)))).0;
26 $b = ($b ^ $c).rotate_right(63);
27 };
28}
29
30macro_rules! permute {
31 (
32 $v0:expr, $v1:expr, $v2:expr, $v3:expr,
33 $v4:expr, $v5:expr, $v6:expr, $v7:expr,
34 $v8:expr, $v9:expr, $v10:expr, $v11:expr,
35 $v12:expr, $v13:expr, $v14:expr, $v15:expr,
36 ) => {
37 permute_step!($v0, $v4, $v8, $v12);
38 permute_step!($v1, $v5, $v9, $v13);
39 permute_step!($v2, $v6, $v10, $v14);
40 permute_step!($v3, $v7, $v11, $v15);
41 permute_step!($v0, $v5, $v10, $v15);
42 permute_step!($v1, $v6, $v11, $v12);
43 permute_step!($v2, $v7, $v8, $v13);
44 permute_step!($v3, $v4, $v9, $v14);
45 };
46}
47
48#[derive(Copy, Clone, Debug)]
50#[repr(align(64))]
51pub struct Block([u64; Self::SIZE / 8]);
52
53impl Block {
54 pub const SIZE: usize = 1024;
56
57 #[must_use]
59 pub const fn new() -> Self {
60 Self([0u64; Self::SIZE / 8])
61 }
62
63 #[inline(always)]
65 pub(crate) fn load(&mut self, input: &[u8; Block::SIZE]) {
66 for (i, chunk) in input.chunks(8).enumerate() {
67 self.0[i] = u64::from_le_bytes(chunk.try_into().expect("should be 8 bytes"));
68 }
69 }
70
71 #[inline(always)]
73 pub(crate) fn iter(&self) -> slice::Iter<'_, u64> {
74 self.0.iter()
75 }
76
77 #[inline(always)]
80 pub(crate) fn compress(rhs: &Self, lhs: &Self) -> Self {
81 let r = *rhs ^ lhs;
82
83 let mut q = r;
85 for chunk in q.0.chunks_exact_mut(16) {
86 #[rustfmt::skip]
87 permute!(
88 chunk[0], chunk[1], chunk[2], chunk[3],
89 chunk[4], chunk[5], chunk[6], chunk[7],
90 chunk[8], chunk[9], chunk[10], chunk[11],
91 chunk[12], chunk[13], chunk[14], chunk[15],
92 );
93 }
94
95 for i in 0..8 {
97 let b = i * 2;
98
99 #[rustfmt::skip]
100 permute!(
101 q.0[b], q.0[b + 1],
102 q.0[b + 16], q.0[b + 17],
103 q.0[b + 32], q.0[b + 33],
104 q.0[b + 48], q.0[b + 49],
105 q.0[b + 64], q.0[b + 65],
106 q.0[b + 80], q.0[b + 81],
107 q.0[b + 96], q.0[b + 97],
108 q.0[b + 112], q.0[b + 113],
109 );
110 }
111
112 q ^= &r;
113 q
114 }
115}
116
117impl Default for Block {
118 fn default() -> Self {
119 Self([0u64; Self::SIZE / 8])
120 }
121}
122
123impl AsRef<[u64]> for Block {
124 fn as_ref(&self) -> &[u64] {
125 &self.0
126 }
127}
128
129impl AsMut<[u64]> for Block {
130 fn as_mut(&mut self) -> &mut [u64] {
131 &mut self.0
132 }
133}
134
135impl BitXor<&Block> for Block {
136 type Output = Block;
137
138 fn bitxor(mut self, rhs: &Block) -> Self::Output {
139 self ^= rhs;
140 self
141 }
142}
143
144impl BitXorAssign<&Block> for Block {
145 fn bitxor_assign(&mut self, rhs: &Block) {
146 for (dst, src) in self.0.iter_mut().zip(rhs.0.iter()) {
147 *dst ^= src;
148 }
149 }
150}
151
152#[cfg(feature = "zeroize")]
153impl Zeroize for Block {
154 fn zeroize(&mut self) {
155 self.0.zeroize();
156 }
157}
158
159#[cfg(feature = "alloc")]
161pub(crate) struct Blocks {
162 p: core::ptr::NonNull<Block>,
163 len: usize,
164}
165
166#[cfg(feature = "alloc")]
167impl Blocks {
168 pub fn new(len: usize) -> Option<Self> {
169 use alloc::alloc::{Layout, alloc_zeroed};
170 use core::ptr::NonNull;
171
172 if len == 0 {
173 return None;
174 }
175
176 let layout = Layout::array::<Block>(len).ok()?;
177 let p = unsafe { alloc_zeroed(layout) };
179
180 let p = NonNull::new(p.cast())?;
181 Some(Self { p, len })
182 }
183
184 pub fn as_slice(&mut self) -> &mut [Block] {
185 unsafe { slice::from_raw_parts_mut(self.p.as_ptr(), self.len) }
187 }
188}
189
190#[cfg(feature = "alloc")]
191impl Drop for Blocks {
192 fn drop(&mut self) {
193 use alloc::alloc::{Layout, dealloc};
194 let layout = unsafe { Layout::array::<Block>(self.len).unwrap_unchecked() };
196 unsafe {
198 dealloc(self.p.as_ptr().cast(), layout);
199 }
200 }
201}