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}