openzeppelin_crypto/
hash.rs

1//! Generic hashing support.
2//!
3//! This module provides a generic way to compute the [hash] of a value. It is
4//! intended to be used as a replacement for [`core::hash`], which we can't use
5//! because [`core::hash::Hasher::finish`] returns a `u64`.
6//!
7//! [hash]: https://en.wikipedia.org/wiki/Hash_function
8
9/// A hashable type.
10///
11/// Types implementing `Hash` are able to be [`Hash::hash`]ed with an instance
12/// of [`Hasher`].
13pub trait Hash {
14    /// Feeds this value into the given [`Hasher`].
15    fn hash<H: Hasher>(&self, state: &mut H);
16}
17
18/// A trait for hashing an arbitrary stream of bytes.
19///
20/// Instances of `Hasher` usually represent state that is changed while hashing
21/// data.
22///
23/// `Hasher` provides a fairly basic interface for retrieving the generated hash
24/// (with [`Hasher::finalize`]), and absorbing an arbitrary number of bytes
25/// (with [`Hasher::update`]). Most of the time, [`Hasher`] instances are used
26/// in conjunction with the [`Hash`] trait.
27pub trait Hasher {
28    /// The output type of this hasher.
29    ///
30    /// For [`core::hash`] types, it's `u64`. For [`tiny_keccak`], it's `[u8]`.
31    /// For this crate, it's `[u8; 32]`.
32    type Output;
33
34    /// Absorb additional input. Can be called multiple times.
35    fn update(&mut self, input: impl AsRef<[u8]>);
36
37    /// Output the hashing algorithm state.
38    fn finalize(self) -> Self::Output;
39}
40
41/// A trait for creating instances of [`Hasher`].
42///
43/// A `BuildHasher` is typically used (e.g., by [`HashMap`]) to create
44/// [`Hasher`]s for each key such that they are hashed independently of one
45/// another, since [`Hasher`]s contain state.
46///
47/// For each instance of `BuildHasher`, the [`Hasher`]s created by
48/// [`build_hasher`] should be identical. That is, if the same stream of bytes
49/// is fed into each hasher, the same output will also be generated.
50///
51/// # Examples
52///
53/// ```rust
54/// use openzeppelin_crypto::KeccakBuilder;
55/// use openzeppelin_crypto::hash::{BuildHasher, Hash, Hasher};
56///
57/// let b = KeccakBuilder;
58/// let mut hasher_1 = b.build_hasher();
59/// let mut hasher_2 = b.build_hasher();
60///
61/// hasher_1.update([1]);
62/// hasher_2.update([1]);
63///
64/// assert_eq!(hasher_1.finalize(), hasher_2.finalize());
65/// ```
66///
67/// [`build_hasher`]: BuildHasher::build_hasher
68/// [`HashMap`]: ../../std/collections/struct.HashMap.html
69pub trait BuildHasher {
70    /// Type of the hasher that will be created.
71    type Hasher: Hasher;
72
73    /// Creates a new hasher.
74    ///
75    /// Each call to `build_hasher` on the same instance should produce
76    /// identical [`Hasher`]s.
77    ///
78    /// # Examples
79    ///
80    /// ```rust
81    /// use openzeppelin_crypto::KeccakBuilder;
82    /// use openzeppelin_crypto::hash::BuildHasher;
83    ///
84    /// let b = KeccakBuilder;
85    /// let hasher = b.build_hasher();
86    /// ```
87    fn build_hasher(&self) -> Self::Hasher;
88
89    /// Calculates the hash of a single value.
90    ///
91    /// This is intended as a convenience for code which *consumes* hashes, such
92    /// as the implementation of a hash table or in unit tests that check
93    /// whether a custom [`Hash`] implementation behaves as expected.
94    ///
95    /// This must not be used in any code which *creates* hashes, such as in an
96    /// implementation of [`Hash`].  The way to create a combined hash of
97    /// multiple values is to call [`Hash::hash`] multiple times using the same
98    /// [`Hasher`], not to call this method repeatedly and combine the results.
99    ///
100    /// # Examples
101    ///
102    /// ```rust
103    /// use openzeppelin_crypto::KeccakBuilder;
104    /// use openzeppelin_crypto::hash::{BuildHasher, Hash};
105    ///
106    /// let b = KeccakBuilder;
107    /// let hash_1 = b.hash_one([0u8; 32]);
108    /// let hash_2 = b.hash_one([0u8; 32]);
109    /// assert_eq!(hash_1, hash_2);
110    ///
111    /// let hash_1 = b.hash_one([1u8; 32]);
112    /// assert_ne!(hash_1, hash_2);
113    /// ```
114    fn hash_one<Hashable>(
115        &self,
116        h: Hashable,
117    ) -> <Self::Hasher as Hasher>::Output
118    where
119        Hashable: Hash,
120        Self: Sized,
121        Self::Hasher: Hasher,
122    {
123        let mut hasher = self.build_hasher();
124        h.hash(&mut hasher);
125        hasher.finalize()
126    }
127}
128
129/// Hash the pair `(a, b)` with `state`.
130///
131/// Returns the finalized hash output from the hasher.
132///
133/// # Arguments
134///
135/// * `a` - The first value to hash.
136/// * `b` - The second value to hash.
137/// * `state` - The hasher state to use.
138#[inline]
139pub fn hash_pair<S, H>(a: &H, b: &H, mut state: S) -> S::Output
140where
141    H: Hash + ?Sized,
142    S: Hasher,
143{
144    a.hash(&mut state);
145    b.hash(&mut state);
146    state.finalize()
147}
148
149/// Sort the pair `(a, b)` and hash the result with `state`. Frequently used
150/// when working with merkle proofs.
151#[inline]
152pub fn commutative_hash_pair<S, H>(a: &H, b: &H, state: S) -> S::Output
153where
154    H: Hash + PartialOrd,
155    S: Hasher,
156{
157    if a > b {
158        hash_pair(b, a, state)
159    } else {
160        hash_pair(a, b, state)
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use proptest::prelude::*;
167
168    use super::*;
169    use crate::{test_helpers::non_empty_u8_vec_strategy, KeccakBuilder};
170
171    // Helper impl for testing
172    impl Hash for Vec<u8> {
173        fn hash<H: Hasher>(&self, state: &mut H) {
174            state.update(self.as_slice());
175        }
176    }
177
178    #[test]
179    fn commutative_hash_is_order_independent() {
180        proptest!(|(a: Vec<u8>, b: Vec<u8>)| {
181            let builder = KeccakBuilder;
182            let hash1 = commutative_hash_pair(&a, &b, builder.build_hasher());
183            let hash2 = commutative_hash_pair(&b, &a, builder.build_hasher());
184            prop_assert_eq!(hash1, hash2);
185        });
186    }
187
188    #[test]
189    fn regular_hash_is_order_dependent() {
190        proptest!(|(a in non_empty_u8_vec_strategy(),
191                    b in non_empty_u8_vec_strategy())| {
192            prop_assume!(a != b);
193            let builder = KeccakBuilder;
194            let hash1 = hash_pair(&a, &b, builder.build_hasher());
195            let hash2 = hash_pair(&b, &a, builder.build_hasher());
196            prop_assert_ne!(hash1, hash2);
197        });
198    }
199
200    #[test]
201    fn hash_pair_deterministic() {
202        proptest!(|(a: Vec<u8>, b: Vec<u8>)| {
203            let builder = KeccakBuilder;
204            let hash1 = hash_pair(&a, &b, builder.build_hasher());
205            let hash2 = hash_pair(&a, &b, builder.build_hasher());
206            prop_assert_eq!(hash1, hash2);
207        });
208    }
209
210    #[test]
211    fn commutative_hash_pair_deterministic() {
212        proptest!(|(a: Vec<u8>, b: Vec<u8>)| {
213            let builder = KeccakBuilder;
214            let hash1 = commutative_hash_pair(&a, &b, builder.build_hasher());
215            let hash2 = commutative_hash_pair(&a, &b, builder.build_hasher());
216            prop_assert_eq!(hash1, hash2);
217        });
218    }
219
220    #[test]
221    fn identical_pairs_hash() {
222        proptest!(|(a: Vec<u8>)| {
223            let builder = KeccakBuilder;
224            let hash1 = hash_pair(&a, &a, builder.build_hasher());
225            let hash2 = commutative_hash_pair(&a, &a, builder.build_hasher());
226            assert_eq!(hash1, hash2);
227        });
228    }
229}