xkcp_rs/
keccak.rs

1use crate::{Error, Result};
2use core::mem::MaybeUninit;
3use ffi::Keccak_HashInstance;
4
5/// Keccak hash function instance.
6#[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        // SAFETY: POD.
16        unsafe { core::ptr::read(self) }
17    }
18}
19
20impl KeccakHash {
21    /// Initialize the `Keccak[r, c]` sponge function instance used in sequential hashing mode.
22    #[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    /// Initializes a SHAKE128 instance as specified in the FIPS 202 standard.
40    #[inline]
41    pub fn shake128() -> Self {
42        unwrap_unreachable(Self::new(1344, 256, 0, 0x1F))
43    }
44
45    /// Initializes a SHAKE256 instance as specified in the FIPS 202 standard.
46    #[inline]
47    pub fn shake256() -> Self {
48        unwrap_unreachable(Self::new(1088, 512, 0, 0x1F))
49    }
50
51    /// Initializes a SHA3-224 instance as specified in the FIPS 202 standard.
52    #[inline]
53    pub fn sha3_224() -> Self {
54        unwrap_unreachable(Self::new(1152, 448, 224, 0x06))
55    }
56
57    /// Initializes a SHA3-256 instance as specified in the FIPS 202 standard.
58    #[inline]
59    pub fn sha3_256() -> Self {
60        unwrap_unreachable(Self::new(1088, 512, 256, 0x06))
61    }
62
63    /// Initializes a SHA3-384 instance as specified in the FIPS 202 standard.
64    #[inline]
65    pub fn sha3_384() -> Self {
66        unwrap_unreachable(Self::new(832, 768, 384, 0x06))
67    }
68
69    /// Initializes a SHA3-512 instance as specified in the FIPS 202 standard.
70    #[inline]
71    pub fn sha3_512() -> Self {
72        unwrap_unreachable(Self::new(576, 1024, 512, 0x06))
73    }
74
75    /// Initializes a Keccak-224 instance.
76    #[inline]
77    pub fn keccak224() -> Self {
78        unwrap_unreachable(Self::new(1152, 448, 224, 0x01))
79    }
80
81    /// Initializes a Keccak-256 instance.
82    #[inline]
83    pub fn keccak256() -> Self {
84        unwrap_unreachable(Self::new(1088, 512, 256, 0x01))
85    }
86
87    /// Initializes a Keccak-384 instance.
88    #[inline]
89    pub fn keccak384() -> Self {
90        unwrap_unreachable(Self::new(832, 768, 384, 0x01))
91    }
92
93    /// Initializes a Keccak-512 instance.
94    #[inline]
95    pub fn keccak512() -> Self {
96        unwrap_unreachable(Self::new(576, 1024, 512, 0x01))
97    }
98
99    /// Absorbs input data.
100    #[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    /// Function to call after all input blocks have been input and to get output bits if the length was specified.
108    #[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    /// Squeezes output data.
119    #[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}