1use crate::{Error, Result};
2use core::mem::MaybeUninit;
3use ffi::Keccak_HashInstance;
4
5#[derive(Debug)]
7#[repr(align(8))]
8pub struct KeccakHash {
9 inner: Keccak_HashInstance,
10}
11
12impl Clone for KeccakHash {
13 #[inline]
14 fn clone(&self) -> Self {
15 unsafe { core::ptr::read(self) }
17 }
18}
19
20impl KeccakHash {
21 #[inline]
23 pub fn new(rate: u32, capacity: u32, hash_bit_length: u32, suffix: u8) -> Result<Self> {
24 let mut instance = MaybeUninit::uninit();
25 Error::from_raw(unsafe {
26 ffi::Keccak_HashInitialize(
27 instance.as_mut_ptr(),
28 rate,
29 capacity,
30 hash_bit_length,
31 suffix,
32 )
33 })?;
34 Ok(Self {
35 inner: unsafe { instance.assume_init() },
36 })
37 }
38
39 #[inline]
41 pub fn shake128() -> Self {
42 unwrap_unreachable(Self::new(1344, 256, 0, 0x1F))
43 }
44
45 #[inline]
47 pub fn shake256() -> Self {
48 unwrap_unreachable(Self::new(1088, 512, 0, 0x1F))
49 }
50
51 #[inline]
53 pub fn sha3_224() -> Self {
54 unwrap_unreachable(Self::new(1152, 448, 224, 0x06))
55 }
56
57 #[inline]
59 pub fn sha3_256() -> Self {
60 unwrap_unreachable(Self::new(1088, 512, 256, 0x06))
61 }
62
63 #[inline]
65 pub fn sha3_384() -> Self {
66 unwrap_unreachable(Self::new(832, 768, 384, 0x06))
67 }
68
69 #[inline]
71 pub fn sha3_512() -> Self {
72 unwrap_unreachable(Self::new(576, 1024, 512, 0x06))
73 }
74
75 #[inline]
77 pub fn keccak224() -> Self {
78 unwrap_unreachable(Self::new(1152, 448, 224, 0x01))
79 }
80
81 #[inline]
83 pub fn keccak256() -> Self {
84 unwrap_unreachable(Self::new(1088, 512, 256, 0x01))
85 }
86
87 #[inline]
89 pub fn keccak384() -> Self {
90 unwrap_unreachable(Self::new(832, 768, 384, 0x01))
91 }
92
93 #[inline]
95 pub fn keccak512() -> Self {
96 unwrap_unreachable(Self::new(576, 1024, 512, 0x01))
97 }
98
99 #[inline]
101 pub fn update(&mut self, data: &[u8]) -> Result<()> {
102 Error::from_raw(unsafe {
103 ffi::Keccak_HashUpdate(&mut self.inner, data.as_ptr(), data.len() * 8)
104 })
105 }
106
107 #[inline]
109 pub fn finalize(&mut self, out: &mut [u8]) -> Result<()> {
110 if self.inner.fixedOutputLength > 0
111 && out.len() * 8 != self.inner.fixedOutputLength as usize
112 {
113 return Err(Error::OutputTooSmall);
114 }
115 Error::from_raw(unsafe { ffi::Keccak_HashFinal(&mut self.inner, out.as_mut_ptr()) })
116 }
117
118 #[inline]
120 pub fn squeeze(&mut self, data: &mut [u8]) -> Result<()> {
121 Error::from_raw(unsafe {
122 ffi::Keccak_HashSqueeze(&mut self.inner, data.as_mut_ptr(), data.len() * 8)
123 })
124 }
125}
126
127#[inline(always)]
128fn unwrap_unreachable<T, E>(x: Result<T, E>) -> T {
129 #[inline(never)]
130 #[cold]
131 fn unreachable() -> ! {
132 unreachable!()
133 }
134
135 match x {
136 Ok(x) => x,
137 Err(_) => unreachable(),
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use hex_literal::hex;
145
146 #[test]
147 fn sha3_256() {
148 fn run(x: &[u8]) -> [u8; 32] {
149 let mut hash = KeccakHash::sha3_256();
150 hash.update(x).unwrap();
151 let mut out = [0u8; 32];
152 hash.finalize(&mut out).unwrap();
153
154 let mut out2 = [0u8; 32];
155 crate::sha3_256(x, &mut out2);
156 assert_eq!(out2, out);
157
158 out
159 }
160
161 assert_eq!(
162 run(b""),
163 hex!("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a")
164 );
165 assert_eq!(
166 run(b"a"),
167 hex!("80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b")
168 );
169 assert_eq!(
170 run(b"Hello, World!"),
171 hex!("1af17a664e3fa8e419b8ba05c2a173169df76162a5a286e0c405b460d478f7ef")
172 );
173 }
174
175 #[test]
176 fn keccak256() {
177 fn run(x: &[u8]) -> [u8; 32] {
178 let mut hash = KeccakHash::keccak256();
179 hash.update(x).unwrap();
180 let mut out = [0u8; 32];
181 hash.finalize(&mut out).unwrap();
182
183 let mut out2 = [0u8; 32];
184 crate::keccak256(x, &mut out2);
185 assert_eq!(out2, out);
186
187 out
188 }
189
190 assert_eq!(
191 run(b""),
192 hex!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
193 );
194 assert_eq!(
195 run(b"a"),
196 hex!("3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb")
197 );
198 assert_eq!(
199 run(b"Hello, World!"),
200 hex!("acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f")
201 );
202 }
203}