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#[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}