Skip to main content

crypto/sha3/
sha3_256.rs

1use super::keccak::Keccak;
2use crate::{Bytes, Hash, Hasher};
3
4const SHA3_256_RATE: usize = 136;
5const SHA3_256_DOMAIN_SEPARATOR: u8 = 0x06;
6
7/// SHA3-256 hash function (FIPS 202).
8///
9/// Implements the [`Hasher`] trait.
10///
11/// # One-shot API
12///
13/// ```ignore
14/// use crypto::{Hasher, sha3::Sha3_256};
15///
16/// let hash = Sha3_256::hash(b"hello world");
17/// ```
18///
19/// # Incremental API
20///
21/// ```ignore
22/// use crypto::{Hasher, sha3::Sha3_256};
23///
24/// let mut hasher = Sha3_256::new();
25/// hasher.update(b"hello ");
26/// hasher.update(b"world");
27/// let hash = hasher.sum();
28/// ```
29#[derive(Clone)]
30#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
31pub struct Sha3_256 {
32    keccak: Keccak<24>,
33}
34
35impl Sha3_256 {
36    #[inline]
37    pub fn new() -> Self {
38        return Sha3_256 {
39            keccak: Keccak::new(SHA3_256_RATE, SHA3_256_DOMAIN_SEPARATOR),
40        };
41    }
42}
43
44impl Hasher for Sha3_256 {
45    const BLOCK_SIZE: usize = SHA3_256_RATE;
46    const OUTPUT_SIZE: usize = 32;
47
48    #[inline]
49    fn new() -> Self {
50        return Sha3_256::new();
51    }
52
53    #[inline]
54    fn update(&mut self, data: &[u8]) {
55        self.keccak.absorb(data);
56    }
57
58    #[inline]
59    fn sum(mut self) -> Hash {
60        let mut hash = Bytes::<64>::with_length(Self::OUTPUT_SIZE);
61        self.keccak.squeeze(hash.as_mut());
62        return Hash(hash);
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::Sha3_256;
69    use crate::Hasher;
70
71    fn vectors_sha3_256() -> Vec<(Vec<u8>, &'static str)> {
72        vec![
73            (b"".to_vec(), "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"),
74            (
75                b"abc".to_vec(),
76                "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532",
77            ),
78            (
79                b"hello world".to_vec(),
80                "644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938",
81            ),
82            (
83                b"The quick brown fox jumps over the lazy dog".to_vec(),
84                "69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04",
85            ),
86            (
87                b"The quick brown fox jumps over the lazy dog.".to_vec(),
88                "a80f839cd4f83f6c3dafc87feae470045e4eb0d366397d5c6ce34ba1739f734d",
89            ),
90            (
91                vec![b'a'; 1_000_000],
92                "5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1",
93            ),
94        ]
95    }
96
97    #[test]
98    fn known_vectors_single_update() {
99        for (input, expected) in vectors_sha3_256() {
100            assert_eq!(hex::encode(<Sha3_256 as Hasher>::hash(&input)), expected);
101        }
102    }
103
104    #[test]
105    fn known_vectors_incremental() {
106        for (input, expected) in vectors_sha3_256() {
107            let mut sha3_256 = <Sha3_256 as Hasher>::new();
108            for chunk in input.chunks(7) {
109                sha3_256.update(chunk);
110            }
111            assert_eq!(hex::encode(sha3_256.sum().as_ref()), expected);
112        }
113    }
114
115    #[test]
116    fn hasher_trait_impl() {
117        for (input, expected) in vectors_sha3_256() {
118            let digest = <Sha3_256 as Hasher>::hash(&input);
119            assert_eq!(hex::encode(digest.as_ref()), expected);
120        }
121    }
122}