Skip to main content

crypto/sha3/
sha3_256.rs

1use super::keccak::KeccakSponge;
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: KeccakSponge<24>,
33}
34
35impl Hasher for Sha3_256 {
36    const BLOCK_SIZE: usize = SHA3_256_RATE;
37    const OUTPUT_SIZE: usize = 32;
38
39    #[inline]
40    fn new() -> Self {
41        Sha3_256 {
42            keccak: KeccakSponge::new(SHA3_256_RATE, SHA3_256_DOMAIN_SEPARATOR),
43        }
44    }
45
46    #[inline]
47    fn update(&mut self, data: &[u8]) {
48        self.keccak.absorb(data);
49    }
50
51    #[inline]
52    fn sum(mut self) -> Hash {
53        let mut hash = Bytes::<64>::with_length(Self::OUTPUT_SIZE);
54        self.keccak.squeeze(hash.as_mut());
55        return Hash(hash);
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::Sha3_256;
62    use crate::Hasher;
63
64    fn vectors_sha3_256() -> Vec<(Vec<u8>, &'static str)> {
65        vec![
66            (b"".to_vec(), "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"),
67            (
68                b"abc".to_vec(),
69                "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532",
70            ),
71            (
72                b"hello world".to_vec(),
73                "644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938",
74            ),
75            (
76                b"The quick brown fox jumps over the lazy dog".to_vec(),
77                "69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04",
78            ),
79            (
80                b"The quick brown fox jumps over the lazy dog.".to_vec(),
81                "a80f839cd4f83f6c3dafc87feae470045e4eb0d366397d5c6ce34ba1739f734d",
82            ),
83            (
84                vec![b'a'; 1_000_000],
85                "5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1",
86            ),
87        ]
88    }
89
90    #[test]
91    fn known_vectors_single_update() {
92        for (input, expected) in vectors_sha3_256() {
93            assert_eq!(hex::encode(<Sha3_256 as Hasher>::hash(&input)), expected);
94        }
95    }
96
97    #[test]
98    fn known_vectors_incremental() {
99        for (input, expected) in vectors_sha3_256() {
100            let mut sha3_256 = <Sha3_256 as Hasher>::new();
101            for chunk in input.chunks(7) {
102                sha3_256.update(chunk);
103            }
104            assert_eq!(hex::encode(&sha3_256.sum()), expected);
105        }
106    }
107
108    #[test]
109    fn hasher_trait_impl() {
110        for (input, expected) in vectors_sha3_256() {
111            let digest = <Sha3_256 as Hasher>::hash(&input);
112            assert_eq!(hex::encode(&digest), expected);
113        }
114    }
115}