1use core::ops::{Add, BitXor, Shl, Shr};
2
3#[cfg(feature = "zeroize")]
4use digest::zeroize::Zeroize;
5
6macro_rules! impl_vector4 {
7 ($vec:ident, $word:ident) => {
8 #[derive(Clone, Copy, Debug)]
9 #[repr(C)]
10 pub(crate) struct $vec(
11 pub(crate) $word,
12 pub(crate) $word,
13 pub(crate) $word,
14 pub(crate) $word,
15 );
16
17 impl $vec {
18 #[inline(always)]
19 pub(crate) fn new(e0: $word, e1: $word, e2: $word, e3: $word) -> Self {
20 Self(e0, e1, e2, e3)
21 }
22
23 #[inline(always)]
24 pub(crate) fn gather(
25 src: &[$word],
26 i0: usize,
27 i1: usize,
28 i2: usize,
29 i3: usize,
30 ) -> Self {
31 $vec::new(src[i0], src[i1], src[i2], src[i3])
32 }
33
34 #[cfg(target_endian = "little")]
35 #[inline(always)]
36 #[allow(clippy::wrong_self_convention)]
37 pub(crate) fn from_le(self) -> Self {
38 self
39 }
40
41 #[cfg(not(target_endian = "little"))]
42 #[inline(always)]
43 pub(crate) fn from_le(self) -> Self {
44 $vec::new(
45 $word::from_le(self.0),
46 $word::from_le(self.1),
47 $word::from_le(self.2),
48 $word::from_le(self.3),
49 )
50 }
51
52 #[cfg(target_endian = "little")]
53 #[inline(always)]
54 pub(crate) fn to_le(self) -> Self {
55 self
56 }
57
58 #[cfg(not(target_endian = "little"))]
59 #[inline(always)]
60 pub(crate) fn to_le(self) -> Self {
61 $vec::new(
62 self.0.to_le(),
63 self.1.to_le(),
64 self.2.to_le(),
65 self.3.to_le(),
66 )
67 }
68
69 #[inline(always)]
70 pub(crate) fn wrapping_add(self, rhs: Self) -> Self {
71 self + rhs
72 }
73
74 #[inline(always)]
75 pub(crate) fn rotate_right_const(self, n: u32) -> Self {
76 $vec::new(
77 self.0.rotate_right(n),
78 self.1.rotate_right(n),
79 self.2.rotate_right(n),
80 self.3.rotate_right(n),
81 )
82 }
83
84 #[inline(always)]
85 pub(crate) fn shuffle_left_1(self) -> Self {
86 $vec::new(self.1, self.2, self.3, self.0)
87 }
88
89 #[inline(always)]
90 pub(crate) fn shuffle_left_2(self) -> Self {
91 $vec::new(self.2, self.3, self.0, self.1)
92 }
93
94 #[inline(always)]
95 pub(crate) fn shuffle_left_3(self) -> Self {
96 $vec::new(self.3, self.0, self.1, self.2)
97 }
98
99 #[inline(always)]
100 pub(crate) fn shuffle_right_1(self) -> Self {
101 self.shuffle_left_3()
102 }
103 #[inline(always)]
104 pub(crate) fn shuffle_right_2(self) -> Self {
105 self.shuffle_left_2()
106 }
107 #[inline(always)]
108 pub(crate) fn shuffle_right_3(self) -> Self {
109 self.shuffle_left_1()
110 }
111
112 #[inline(always)]
113 pub(crate) fn as_bytes(&self) -> &[u8] {
114 let p = self as *const Self as *const u8;
115 unsafe { core::slice::from_raw_parts(p, core::mem::size_of::<Self>()) }
116 }
117 }
118
119 impl Add for $vec {
120 type Output = Self;
121
122 #[inline(always)]
123 fn add(self, rhs: Self) -> Self::Output {
124 $vec::new(
125 self.0.wrapping_add(rhs.0),
126 self.1.wrapping_add(rhs.1),
127 self.2.wrapping_add(rhs.2),
128 self.3.wrapping_add(rhs.3),
129 )
130 }
131 }
132
133 impl BitXor for $vec {
134 type Output = Self;
135
136 #[inline(always)]
137 fn bitxor(self, rhs: Self) -> Self::Output {
138 $vec::new(
139 self.0 ^ rhs.0,
140 self.1 ^ rhs.1,
141 self.2 ^ rhs.2,
142 self.3 ^ rhs.3,
143 )
144 }
145 }
146
147 impl Shl<$vec> for $vec {
148 type Output = Self;
149
150 #[inline(always)]
151 fn shl(self, rhs: Self) -> Self::Output {
152 $vec::new(
153 self.0 << rhs.0,
154 self.1 << rhs.1,
155 self.2 << rhs.2,
156 self.3 << rhs.3,
157 )
158 }
159 }
160
161 impl Shr<$vec> for $vec {
162 type Output = Self;
163
164 #[inline(always)]
165 fn shr(self, rhs: Self) -> Self::Output {
166 $vec::new(
167 self.0 >> rhs.0,
168 self.1 >> rhs.1,
169 self.2 >> rhs.2,
170 self.3 >> rhs.3,
171 )
172 }
173 }
174
175 #[cfg(feature = "zeroize")]
176 impl Zeroize for $vec {
177 fn zeroize(&mut self) {
178 self.0.zeroize();
179 self.1.zeroize();
180 self.2.zeroize();
181 self.3.zeroize();
182 }
183 }
184 };
185}
186
187impl_vector4!(u32x4, u32);
188impl_vector4!(u64x4, u64);