Skip to main content

miden_crypto/hash/sha2/
mod.rs

1//! SHA2 hash function wrappers (SHA-256 and SHA-512).
2
3use core::mem::size_of;
4
5use sha2::Digest as Sha2Digest;
6
7use super::{
8    Felt, HasherExt,
9    digest::{DIGEST256_BYTES, DIGEST512_BYTES, Digest256, Digest512},
10};
11use crate::field::BasedVectorSpace;
12
13#[cfg(test)]
14mod tests;
15
16// SHA256 DIGEST
17// ================================================================================================
18
19/// SHA-256 digest (32 bytes).
20///
21/// This is a type alias to the generic `Digest256` type.
22pub type Sha256Digest = Digest256;
23
24// SHA256 HASHER
25// ================================================================================================
26
27/// SHA-256 hash function.
28#[derive(Debug, Copy, Clone, Eq, PartialEq)]
29pub struct Sha256;
30
31impl HasherExt for Sha256 {
32    type Digest = Sha256Digest;
33
34    fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
35        let mut hasher = sha2::Sha256::new();
36        for slice in slices {
37            hasher.update(slice);
38        }
39        Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
40    }
41}
42
43impl Sha256 {
44    /// SHA-256 collision resistance is 128-bits for 32-bytes output.
45    pub const COLLISION_RESISTANCE: u32 = 128;
46
47    pub fn hash(bytes: &[u8]) -> Sha256Digest {
48        let mut hasher = sha2::Sha256::new();
49        hasher.update(bytes);
50        Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
51    }
52
53    pub fn merge(values: &[Sha256Digest; 2]) -> Sha256Digest {
54        Self::hash(Sha256Digest::digests_as_bytes(values))
55    }
56
57    pub fn merge_many(values: &[Sha256Digest]) -> Sha256Digest {
58        let data = Sha256Digest::digests_as_bytes(values);
59        let mut hasher = sha2::Sha256::new();
60        hasher.update(data);
61        Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
62    }
63
64    /// Returns a hash of the provided field elements.
65    #[inline(always)]
66    pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Sha256Digest {
67        Sha256Digest::from(hash_elements_256(elements))
68    }
69
70    /// Hashes an iterator of byte slices.
71    #[inline(always)]
72    pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha256Digest {
73        <Self as HasherExt>::hash_iter(slices)
74    }
75}
76
77// SHA512 DIGEST
78// ================================================================================================
79
80/// SHA-512 digest (64 bytes).
81///
82/// This is a type alias to the generic `Digest512` type.
83pub type Sha512Digest = Digest512;
84
85// SHA512 HASHER
86// ================================================================================================
87
88/// SHA-512 hash function.
89#[derive(Debug, Copy, Clone, Eq, PartialEq)]
90pub struct Sha512;
91
92impl HasherExt for Sha512 {
93    type Digest = Sha512Digest;
94
95    fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
96        let mut hasher = sha2::Sha512::new();
97        for slice in slices {
98            hasher.update(slice);
99        }
100        Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
101    }
102}
103
104impl Sha512 {
105    /// Returns a hash of the provided sequence of bytes.
106    #[inline(always)]
107    pub fn hash(bytes: &[u8]) -> Sha512Digest {
108        let mut hasher = sha2::Sha512::new();
109        hasher.update(bytes);
110        Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
111    }
112
113    /// Returns a hash of two digests. This method is intended for use in construction of
114    /// Merkle trees and verification of Merkle paths.
115    #[inline(always)]
116    pub fn merge(values: &[Sha512Digest; 2]) -> Sha512Digest {
117        Self::hash(Sha512Digest::digests_as_bytes(values))
118    }
119
120    /// Returns a hash of the provided digests.
121    #[inline(always)]
122    pub fn merge_many(values: &[Sha512Digest]) -> Sha512Digest {
123        let data = Sha512Digest::digests_as_bytes(values);
124        let mut hasher = sha2::Sha512::new();
125        hasher.update(data);
126        Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
127    }
128
129    /// Returns a hash of the provided field elements.
130    #[inline(always)]
131    pub fn hash_elements<E>(elements: &[E]) -> Sha512Digest
132    where
133        E: BasedVectorSpace<Felt>,
134    {
135        Sha512Digest::from(hash_elements_512(elements))
136    }
137
138    /// Hashes an iterator of byte slices.
139    #[inline(always)]
140    pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha512Digest {
141        <Self as HasherExt>::hash_iter(slices)
142    }
143}
144
145// HELPER FUNCTIONS
146// ================================================================================================
147
148/// Hash the elements into bytes for SHA-256.
149fn hash_elements_256<E>(elements: &[E]) -> [u8; DIGEST256_BYTES]
150where
151    E: BasedVectorSpace<Felt>,
152{
153    let digest = {
154        const FELT_BYTES: usize = size_of::<u64>();
155        const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
156
157        let mut hasher = sha2::Sha256::new();
158
159        for elem in elements.iter() {
160            for &felt in E::as_basis_coefficients_slice(elem) {
161                let felt_bytes = felt.as_canonical_u64().to_le_bytes();
162                hasher.update(felt_bytes);
163            }
164        }
165
166        hasher.finalize()
167    };
168    digest.into()
169}
170
171/// Hash the elements into bytes for SHA-512.
172fn hash_elements_512<E>(elements: &[E]) -> [u8; DIGEST512_BYTES]
173where
174    E: BasedVectorSpace<Felt>,
175{
176    let digest = {
177        const FELT_BYTES: usize = size_of::<u64>();
178        const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
179
180        let mut hasher = sha2::Sha512::new();
181
182        for elem in elements.iter() {
183            for &felt in E::as_basis_coefficients_slice(elem) {
184                let felt_bytes = felt.as_canonical_u64().to_le_bytes();
185                hasher.update(felt_bytes);
186            }
187        }
188
189        hasher.finalize()
190    };
191    digest.into()
192}