Skip to main content

dryoc/classic/
crypto_hash.rs

1//! # SHA-2 and SHA-3 hashing
2//!
3//! Implements libsodium's `crypto_hash_sha256_*`, `crypto_hash_sha512_*`,
4//! `crypto_hash_sha3256_*`, and `crypto_hash_sha3512_*` functions.
5//!
6//! SHA-2 and SHA-3 are unkeyed hash functions. They produce fixed-size digests
7//! that identify input bytes, but they do not prove who created the input. Use
8//! [`crate::classic::crypto_auth`] or the direct HMAC modules when a shared
9//! secret key is required.
10//!
11//! ```
12//! use dryoc::classic::crypto_hash::*;
13//!
14//! let message = b"The empty vessel makes the loudest sound.";
15//!
16//! let mut default_digest: Digest = [0u8; 64];
17//! crypto_hash(&mut default_digest, message);
18//! assert_eq!(default_digest.len(), 64);
19//!
20//! let mut sha256 = Sha256Digest::default();
21//! crypto_hash_sha256(&mut sha256, message);
22//! assert_eq!(sha256.len(), 32);
23//!
24//! let mut sha512: Sha512Digest = [0u8; 64];
25//! crypto_hash_sha512(&mut sha512, message);
26//! assert_eq!(sha512.len(), 64);
27//!
28//! let mut sha3256 = Sha3256Digest::default();
29//! crypto_hash_sha3256(&mut sha3256, message);
30//! assert_eq!(sha3256.len(), 32);
31//!
32//! let mut sha3512: Sha3512Digest = [0u8; 64];
33//! crypto_hash_sha3512(&mut sha3512, message);
34//! assert_eq!(sha3512.len(), 64);
35//! ```
36
37use crate::constants::{
38    CRYPTO_HASH_SHA256_BYTES, CRYPTO_HASH_SHA512_BYTES, CRYPTO_HASH_SHA3256_BYTES,
39    CRYPTO_HASH_SHA3512_BYTES,
40};
41use crate::sha3::{Sha3256, Sha3512};
42use crate::sha256::Sha256;
43use crate::sha512::*;
44
45/// Type alias for SHA512 digest output.
46pub type Digest = Sha512Digest;
47/// Type alias for SHA256 digest output.
48pub type Sha256Digest = [u8; CRYPTO_HASH_SHA256_BYTES];
49/// Type alias for SHA512 digest output.
50pub type Sha512Digest = [u8; CRYPTO_HASH_SHA512_BYTES];
51/// Type alias for SHA3-256 digest output.
52pub type Sha3256Digest = [u8; CRYPTO_HASH_SHA3256_BYTES];
53/// Type alias for SHA3-512 digest output.
54pub type Sha3512Digest = [u8; CRYPTO_HASH_SHA3512_BYTES];
55
56/// Computes a SHA-512 hash from `input` using libsodium's default
57/// `crypto_hash` primitive.
58pub fn crypto_hash(output: &mut Digest, input: &[u8]) {
59    crypto_hash_sha512(output, input);
60}
61
62/// Computes a SHA-256 hash from `input`.
63pub fn crypto_hash_sha256(output: &mut Sha256Digest, input: &[u8]) {
64    let mut state = crypto_hash_sha256_init();
65    crypto_hash_sha256_update(&mut state, input);
66    crypto_hash_sha256_final(state, output);
67}
68
69/// Internal state for SHA-256 functions.
70#[derive(Default)]
71pub struct Sha256State {
72    pub(super) hasher: Sha256,
73}
74
75/// Initializes a SHA-256 hasher.
76pub fn crypto_hash_sha256_init() -> Sha256State {
77    Sha256State::default()
78}
79
80/// Updates `state` of SHA-256 hasher with `input`.
81pub fn crypto_hash_sha256_update(state: &mut Sha256State, input: &[u8]) {
82    state.hasher.update(input);
83}
84
85/// Finalizes `state` of SHA-256, and writes the digest to `output` consuming
86/// `state`.
87pub fn crypto_hash_sha256_final(state: Sha256State, output: &mut Sha256Digest) {
88    state.hasher.finalize_into_bytes(output)
89}
90
91/// Computes a SHA-512 hash from `input`.
92pub fn crypto_hash_sha512(output: &mut Digest, input: &[u8]) {
93    let mut state = crypto_hash_sha512_init();
94    crypto_hash_sha512_update(&mut state, input);
95    crypto_hash_sha512_final(state, output);
96}
97
98/// Internal state for SHA-512 functions.
99#[derive(Default)]
100pub struct Sha512State {
101    pub(super) hasher: Sha512,
102}
103
104/// Initializes a SHA-512 hasher.
105pub fn crypto_hash_sha512_init() -> Sha512State {
106    Sha512State::default()
107}
108
109/// Updates `state` of SHA-512 hasher with `input`.
110pub fn crypto_hash_sha512_update(state: &mut Sha512State, input: &[u8]) {
111    state.hasher.update(input);
112}
113
114/// Finalizes `state` of SHA-512, and writes the digest to `output` consuming
115/// `state`.
116pub fn crypto_hash_sha512_final(state: Sha512State, output: &mut Digest) {
117    state.hasher.finalize_into_bytes(output)
118}
119
120/// Computes a SHA3-256 hash from `input`.
121pub fn crypto_hash_sha3256(output: &mut Sha3256Digest, input: &[u8]) {
122    let mut state = crypto_hash_sha3256_init();
123    crypto_hash_sha3256_update(&mut state, input);
124    crypto_hash_sha3256_final(state, output);
125}
126
127/// Internal state for SHA3-256 functions.
128#[derive(Default)]
129pub struct Sha3256State {
130    pub(super) hasher: Sha3256,
131}
132
133/// Initializes a SHA3-256 hasher.
134pub fn crypto_hash_sha3256_init() -> Sha3256State {
135    Sha3256State::default()
136}
137
138/// Updates `state` of SHA3-256 hasher with `input`.
139pub fn crypto_hash_sha3256_update(state: &mut Sha3256State, input: &[u8]) {
140    state.hasher.update(input);
141}
142
143/// Finalizes `state` of SHA3-256, and writes the digest to `output` consuming
144/// `state`.
145pub fn crypto_hash_sha3256_final(state: Sha3256State, output: &mut Sha3256Digest) {
146    state.hasher.finalize_into_bytes(output)
147}
148
149/// Computes a SHA3-512 hash from `input`.
150pub fn crypto_hash_sha3512(output: &mut Sha3512Digest, input: &[u8]) {
151    let mut state = crypto_hash_sha3512_init();
152    crypto_hash_sha3512_update(&mut state, input);
153    crypto_hash_sha3512_final(state, output);
154}
155
156/// Internal state for SHA3-512 functions.
157#[derive(Default)]
158pub struct Sha3512State {
159    pub(super) hasher: Sha3512,
160}
161
162/// Initializes a SHA3-512 hasher.
163pub fn crypto_hash_sha3512_init() -> Sha3512State {
164    Sha3512State::default()
165}
166
167/// Updates `state` of SHA3-512 hasher with `input`.
168pub fn crypto_hash_sha3512_update(state: &mut Sha3512State, input: &[u8]) {
169    state.hasher.update(input);
170}
171
172/// Finalizes `state` of SHA3-512, and writes the digest to `output` consuming
173/// `state`.
174pub fn crypto_hash_sha3512_final(state: Sha3512State, output: &mut Sha3512Digest) {
175    state.hasher.finalize_into_bytes(output)
176}
177
178#[cfg(test)]
179mod tests {
180    use super::*;
181
182    #[test]
183    fn test_crypto_hash_sha256() {
184        let mut our_digest = [0u8; CRYPTO_HASH_SHA256_BYTES];
185        crypto_hash_sha256(&mut our_digest, b"abc");
186
187        let expected =
188            hex::decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
189                .expect("hex failed");
190        assert_eq!(our_digest.as_slice(), expected.as_slice());
191    }
192
193    #[test]
194    fn test_crypto_hash_uses_sha512() {
195        let mut generic = [0u8; CRYPTO_HASH_SHA512_BYTES];
196        let mut sha512 = [0u8; CRYPTO_HASH_SHA512_BYTES];
197
198        crypto_hash(&mut generic, b"abc");
199        crypto_hash_sha512(&mut sha512, b"abc");
200
201        assert_eq!(generic, sha512);
202    }
203
204    #[test]
205    fn test_crypto_hash_sha3256() {
206        let mut our_digest = [0u8; CRYPTO_HASH_SHA3256_BYTES];
207        crypto_hash_sha3256(&mut our_digest, b"abc");
208
209        let expected =
210            hex::decode("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532")
211                .expect("hex failed");
212        assert_eq!(our_digest.as_slice(), expected.as_slice());
213    }
214
215    #[test]
216    fn test_crypto_hash_sha3256_update() {
217        let mut state = crypto_hash_sha3256_init();
218        crypto_hash_sha3256_update(&mut state, b"a");
219        crypto_hash_sha3256_update(&mut state, b"b");
220        crypto_hash_sha3256_update(&mut state, b"c");
221
222        let mut our_digest = [0u8; CRYPTO_HASH_SHA3256_BYTES];
223        crypto_hash_sha3256_final(state, &mut our_digest);
224
225        let expected =
226            hex::decode("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532")
227                .expect("hex failed");
228        assert_eq!(our_digest.as_slice(), expected.as_slice());
229    }
230
231    #[test]
232    fn test_crypto_hash_sha3512() {
233        let mut our_digest = [0u8; CRYPTO_HASH_SHA3512_BYTES];
234        crypto_hash_sha3512(&mut our_digest, b"abc");
235
236        let expected = hex::decode(concat!(
237            "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e",
238            "10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"
239        ))
240        .expect("hex failed");
241        assert_eq!(our_digest.as_slice(), expected.as_slice());
242    }
243
244    #[test]
245    fn test_crypto_hash_sha3512_update() {
246        let mut state = crypto_hash_sha3512_init();
247        crypto_hash_sha3512_update(&mut state, b"a");
248        crypto_hash_sha3512_update(&mut state, b"b");
249        crypto_hash_sha3512_update(&mut state, b"c");
250
251        let mut our_digest = [0u8; CRYPTO_HASH_SHA3512_BYTES];
252        crypto_hash_sha3512_final(state, &mut our_digest);
253
254        let expected = hex::decode(concat!(
255            "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e",
256            "10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"
257        ))
258        .expect("hex failed");
259        assert_eq!(our_digest.as_slice(), expected.as_slice());
260    }
261
262    #[cfg(dryoc_native_tests)]
263    #[test]
264    fn test_crypto_hash_sha512() {
265        use sodiumoxide::crypto::hash;
266
267        use crate::rng::randombytes_buf;
268
269        let r = randombytes_buf(64);
270
271        let their_digest = hash::hash(&r);
272        let mut our_digest = [0u8; CRYPTO_HASH_SHA512_BYTES];
273        crypto_hash_sha512(&mut our_digest, &r);
274
275        assert_eq!(their_digest.as_ref(), our_digest);
276    }
277
278    #[cfg(dryoc_native_tests)]
279    #[test]
280    fn test_crypto_hash_sha512_update() {
281        use sodiumoxide::crypto::hash;
282
283        use crate::rng::randombytes_buf;
284
285        let mut their_state = hash::State::new();
286        let mut our_state = crypto_hash_sha512_init();
287
288        for _ in 0..10 {
289            let r = randombytes_buf(64);
290            their_state.update(&r);
291            crypto_hash_sha512_update(&mut our_state, &r);
292        }
293
294        let their_digest = their_state.finalize();
295        let mut our_digest = [0u8; CRYPTO_HASH_SHA512_BYTES];
296        crypto_hash_sha512_final(our_state, &mut our_digest);
297
298        assert_eq!(their_digest.as_ref(), our_digest);
299    }
300}