Skip to main content

dryoc/
sha3.rs

1//! # SHA-3 hash algorithms
2//!
3//! Provides implementations of the SHA3-256 and SHA3-512 hash algorithms.
4//!
5//! SHA-3 hashes are unkeyed cryptographic hash functions. They turn arbitrary
6//! input bytes into fixed-size digests. Hashes are useful for fingerprints and
7//! compatibility with protocols that require SHA-3, but they do not
8//! authenticate messages by themselves. Use [`crate::auth`] or [`crate::hmac`]
9//! when a secret key must be involved.
10//!
11//! ## Example
12//!
13//! ```
14//! use dryoc::sha3::Sha3256;
15//!
16//! let mut state = Sha3256::new();
17//! state.update(b"The web of our life is of a mingled yarn.");
18//! let hash = state.finalize_to_vec();
19//! assert_eq!(hash.len(), 32);
20//! ```
21use sha3_impl::{Digest as DigestImpl, Sha3_256 as Sha3256Impl, Sha3_512 as Sha3512Impl};
22
23use crate::constants::{CRYPTO_HASH_SHA3256_BYTES, CRYPTO_HASH_SHA3512_BYTES};
24use crate::types::*;
25
26/// Type alias for SHA3-256 digest, provided for convenience.
27pub type Sha3256Digest = StackByteArray<CRYPTO_HASH_SHA3256_BYTES>;
28/// Type alias for SHA3-512 digest, provided for convenience.
29pub type Sha3512Digest = StackByteArray<CRYPTO_HASH_SHA3512_BYTES>;
30
31/// SHA3-256 wrapper, provided for convenience.
32pub struct Sha3256 {
33    hasher: Sha3256Impl,
34}
35
36impl Sha3256 {
37    /// Returns a new SHA3-256 hasher instance.
38    pub fn new() -> Self {
39        Self {
40            hasher: Sha3256Impl::new(),
41        }
42    }
43
44    /// One-time interface to compute SHA3-256 digest for `input`, copying
45    /// result into `output`.
46    pub fn compute_into_bytes<
47        Input: Bytes + ?Sized,
48        Output: MutByteArray<CRYPTO_HASH_SHA3256_BYTES>,
49    >(
50        output: &mut Output,
51        input: &Input,
52    ) {
53        let mut hasher = Self::new();
54        hasher.update(input);
55        hasher.finalize_into_bytes(output)
56    }
57
58    /// One-time interface to compute SHA3-256 digest for `input`.
59    pub fn compute<Input: Bytes + ?Sized, Output: NewByteArray<CRYPTO_HASH_SHA3256_BYTES>>(
60        input: &Input,
61    ) -> Output {
62        let mut hasher = Self::new();
63        hasher.update(input);
64        hasher.finalize()
65    }
66
67    /// Wrapper around [`Sha3256::compute`], returning a [`Vec`]. Provided for
68    /// convenience.
69    pub fn compute_to_vec<Input: Bytes + ?Sized>(input: &Input) -> Vec<u8> {
70        Self::compute(input)
71    }
72
73    /// Updates SHA3-256 hash state with `input`.
74    pub fn update<Input: Bytes + ?Sized>(&mut self, input: &Input) {
75        self.hasher.update(input.as_slice())
76    }
77
78    /// Consumes hasher and return final computed hash.
79    pub fn finalize<Output: NewByteArray<CRYPTO_HASH_SHA3256_BYTES>>(self) -> Output {
80        let mut hash = Output::new_byte_array();
81        self.finalize_into_bytes(&mut hash);
82        hash
83    }
84
85    /// Consumes hasher and writes final computed hash into `output`.
86    pub fn finalize_into_bytes<Output: MutByteArray<CRYPTO_HASH_SHA3256_BYTES>>(
87        self,
88        output: &mut Output,
89    ) {
90        let digest = self.hasher.finalize();
91        output.as_mut_slice().copy_from_slice(&digest);
92    }
93
94    /// Consumes hasher and returns final computed hash as a [`Vec`].
95    pub fn finalize_to_vec(self) -> Vec<u8> {
96        self.finalize()
97    }
98}
99
100impl Default for Sha3256 {
101    fn default() -> Self {
102        Self::new()
103    }
104}
105
106/// SHA3-512 wrapper, provided for convenience.
107pub struct Sha3512 {
108    hasher: Sha3512Impl,
109}
110
111impl Sha3512 {
112    /// Returns a new SHA3-512 hasher instance.
113    pub fn new() -> Self {
114        Self {
115            hasher: Sha3512Impl::new(),
116        }
117    }
118
119    /// One-time interface to compute SHA3-512 digest for `input`, copying
120    /// result into `output`.
121    pub fn compute_into_bytes<
122        Input: Bytes + ?Sized,
123        Output: MutByteArray<CRYPTO_HASH_SHA3512_BYTES>,
124    >(
125        output: &mut Output,
126        input: &Input,
127    ) {
128        let mut hasher = Self::new();
129        hasher.update(input);
130        hasher.finalize_into_bytes(output)
131    }
132
133    /// One-time interface to compute SHA3-512 digest for `input`.
134    pub fn compute<Input: Bytes + ?Sized, Output: NewByteArray<CRYPTO_HASH_SHA3512_BYTES>>(
135        input: &Input,
136    ) -> Output {
137        let mut hasher = Self::new();
138        hasher.update(input);
139        hasher.finalize()
140    }
141
142    /// Wrapper around [`Sha3512::compute`], returning a [`Vec`]. Provided for
143    /// convenience.
144    pub fn compute_to_vec<Input: Bytes + ?Sized>(input: &Input) -> Vec<u8> {
145        Self::compute(input)
146    }
147
148    /// Updates SHA3-512 hash state with `input`.
149    pub fn update<Input: Bytes + ?Sized>(&mut self, input: &Input) {
150        self.hasher.update(input.as_slice())
151    }
152
153    /// Consumes hasher and return final computed hash.
154    pub fn finalize<Output: NewByteArray<CRYPTO_HASH_SHA3512_BYTES>>(self) -> Output {
155        let mut hash = Output::new_byte_array();
156        self.finalize_into_bytes(&mut hash);
157        hash
158    }
159
160    /// Consumes hasher and writes final computed hash into `output`.
161    pub fn finalize_into_bytes<Output: MutByteArray<CRYPTO_HASH_SHA3512_BYTES>>(
162        self,
163        output: &mut Output,
164    ) {
165        let digest = self.hasher.finalize();
166        output.as_mut_slice().copy_from_slice(&digest);
167    }
168
169    /// Consumes hasher and returns final computed hash as a [`Vec`].
170    pub fn finalize_to_vec(self) -> Vec<u8> {
171        self.finalize()
172    }
173}
174
175impl Default for Sha3512 {
176    fn default() -> Self {
177        Self::new()
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    fn assert_sha3256(input: &[u8], expected_hex: &str) {
186        let expected = hex::decode(expected_hex).expect("hex failed");
187        assert_eq!(Sha3256::compute_to_vec(input), expected);
188
189        let mut state = Sha3256::new();
190        for chunk in input.chunks(1) {
191            state.update(chunk);
192        }
193        assert_eq!(state.finalize_to_vec(), expected);
194    }
195
196    fn assert_sha3512(input: &[u8], expected_hex: &str) {
197        let expected = hex::decode(expected_hex).expect("hex failed");
198        assert_eq!(Sha3512::compute_to_vec(input), expected);
199
200        let mut state = Sha3512::new();
201        for chunk in input.chunks(1) {
202            state.update(chunk);
203        }
204        assert_eq!(state.finalize_to_vec(), expected);
205    }
206
207    #[test]
208    fn test_sha3256_known_answers() {
209        assert_sha3256(
210            b"",
211            "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a",
212        );
213        assert_sha3256(
214            b"abc",
215            "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532",
216        );
217    }
218
219    #[test]
220    fn test_sha3512_known_answers() {
221        assert_sha3512(
222            b"",
223            concat!(
224                "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a",
225                "615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"
226            ),
227        );
228        assert_sha3512(
229            b"abc",
230            concat!(
231                "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e",
232                "10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"
233            ),
234        );
235    }
236}