bitcoin_hashes/sha256t/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! SHA256t implementation (tagged SHA256).
4
5use core::cmp;
6use core::marker::PhantomData;
7
8#[cfg(doc)]
9use crate::sha256::Midstate;
10use crate::{sha256, HashEngine as _};
11
12/// Hashes some bytes.
13pub fn hash<T>(data: &[u8]) -> Hash<T>
14where
15    T: Tag,
16{
17    use crate::HashEngine as _;
18
19    let mut engine = HashEngine::default();
20    engine.input(data);
21    engine.finalize()
22}
23
24/// Hashes all the byte slices retrieved from the iterator together.
25pub fn hash_byte_chunks<B, I, T>(byte_slices: I) -> Hash<T>
26where
27    B: AsRef<[u8]>,
28    I: IntoIterator<Item = B>,
29    T: Tag,
30{
31    use crate::HashEngine as _;
32
33    let mut engine = HashEngine::default();
34    for slice in byte_slices {
35        engine.input(slice.as_ref());
36    }
37    engine.finalize()
38}
39
40/// Trait representing a tag that can be used as a context for SHA256t hashes.
41pub trait Tag {
42    /// The [`Midstate`] after pre-tagging the hash engine.
43    const MIDSTATE: sha256::Midstate;
44}
45
46internals::transparent_newtype! {
47    /// Output of the SHA256t hash function.
48    pub struct Hash<T>(PhantomData<T>, [u8; 32]);
49
50    impl<T> Hash<T> {
51        /// Zero cost conversion between a fixed length byte array shared reference and
52        /// a shared reference to this Hash type.
53        pub fn from_bytes_ref(bytes: &_) -> &Self;
54
55        /// Zero cost conversion between a fixed length byte array exclusive reference and
56        /// an exclusive reference to this Hash type.
57        pub fn from_bytes_mut(bytes: &mut _) -> &mut Self;
58    }
59}
60
61impl<T> Hash<T>
62where
63    T: Tag,
64{
65    /// Constructs a new hash from the underlying byte array.
66    pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self(PhantomData, bytes) }
67
68    /// Produces a hash from the current state of a given engine.
69    pub fn from_engine(e: HashEngine<T>) -> Self {
70        Self::from_byte_array(sha256::Hash::from_engine(e.0).to_byte_array())
71    }
72
73    /// Constructs a new engine.
74    pub fn engine() -> HashEngine<T> { HashEngine::default() }
75
76    /// Hashes some bytes.
77    #[allow(clippy::self_named_constructors)] // Hash is a noun and a verb.
78    pub fn hash(data: &[u8]) -> Self {
79        use crate::HashEngine;
80
81        let mut engine = Self::engine();
82        engine.input(data);
83        Self::from_engine(engine)
84    }
85
86    /// Hashes all the byte slices retrieved from the iterator together.
87    pub fn hash_byte_chunks<B, I>(byte_slices: I) -> Self
88    where
89        B: AsRef<[u8]>,
90        I: IntoIterator<Item = B>,
91    {
92        let mut engine = Self::engine();
93        for slice in byte_slices {
94            engine.input(slice.as_ref());
95        }
96        Self::from_engine(engine)
97    }
98
99    /// Returns the underlying byte array.
100    pub const fn to_byte_array(self) -> [u8; 32] { self.1 }
101
102    /// Returns a reference to the underlying byte array.
103    pub const fn as_byte_array(&self) -> &[u8; 32] { &self.1 }
104}
105
106impl<T: Tag> Copy for Hash<T> {}
107impl<T: Tag> Clone for Hash<T> {
108    fn clone(&self) -> Self { *self }
109}
110impl<T: Tag> PartialEq for Hash<T> {
111    fn eq(&self, other: &Self) -> bool { self.as_byte_array() == other.as_byte_array() }
112}
113impl<T: Tag> Eq for Hash<T> {}
114impl<T: Tag> PartialOrd for Hash<T> {
115    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
116        Some(cmp::Ord::cmp(self, other))
117    }
118}
119impl<T: Tag> Ord for Hash<T> {
120    fn cmp(&self, other: &Self) -> cmp::Ordering {
121        cmp::Ord::cmp(&self.as_byte_array(), &other.as_byte_array())
122    }
123}
124impl<T: Tag> core::hash::Hash for Hash<T> {
125    fn hash<H: core::hash::Hasher>(&self, h: &mut H) { self.as_byte_array().hash(h) }
126}
127
128crate::internal_macros::hash_trait_impls!(256, false, T: Tag);
129
130/// Engine to compute SHA256t hash function.
131#[derive(Debug)]
132pub struct HashEngine<T>(sha256::HashEngine, PhantomData<T>);
133
134impl<T: Tag> Default for HashEngine<T> {
135    fn default() -> Self {
136        let tagged = sha256::HashEngine::from_midstate(T::MIDSTATE);
137        Self(tagged, PhantomData)
138    }
139}
140
141impl<T: Tag> Clone for HashEngine<T> {
142    fn clone(&self) -> Self { Self(self.0.clone(), PhantomData) }
143}
144
145impl<T: Tag> crate::HashEngine for HashEngine<T> {
146    type Hash = Hash<T>;
147    type Bytes = [u8; 32];
148    const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
149
150    fn input(&mut self, data: &[u8]) { self.0.input(data) }
151    fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
152    fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
153}
154
155crate::internal_macros::impl_write!(
156    HashEngine<T>,
157    |us: &mut HashEngine<T>, buf| {
158        us.input(buf);
159        Ok(buf.len())
160    },
161    |_us| { Ok(()) },
162    T: crate::sha256t::Tag
163);
164
165// Workaround macros being unavailable in attributes.
166#[doc(hidden)]
167#[macro_export]
168macro_rules! sha256t_tag_struct {
169    ($vis:vis, $tag:ident, $name:expr, $(#[$($attr:meta)*])*) => {
170        #[doc = "The tag used for [`"]
171        #[doc = $name]
172        #[doc = "`].\n\n"]
173        $(#[$($attr)*])*
174        #[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
175        $vis struct $tag;
176    };
177}
178
179#[doc(hidden)]
180#[macro_export]
181macro_rules! sha256t_tag_constructor {
182    (hash_str, $value:expr) => {
183        $crate::sha256::Midstate::hash_tag($value.as_bytes())
184    };
185    (hash_bytes, $value:expr) => {
186        $crate::sha256::Midstate::hash_tag($value)
187    };
188    (raw, $bytes:expr, $len:expr) => {
189        $crate::sha256::Midstate::new($bytes, $len)
190    };
191}
192
193#[cfg(test)]
194mod tests {
195    #[cfg(feature = "alloc")]
196    use crate::sha256;
197    use crate::sha256t;
198
199    const TEST_MIDSTATE: [u8; 32] = [
200        156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147,
201        108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201,
202    ];
203
204    // The digest created by sha256 hashing `&[0]` starting with `TEST_MIDSTATE`.
205    #[cfg(feature = "alloc")]
206    #[cfg(feature = "hex")]
207    const HASH_ZERO_BACKWARD: &str =
208        "29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed";
209    // And the same thing, forward.
210    #[cfg(feature = "alloc")]
211    #[cfg(feature = "hex")]
212    const HASH_ZERO_FORWARD: &str =
213        "ed1382037800c9dd938dd8854f1a8863bcdeb6705069b4b56a66ec22519d5829";
214
215    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
216    #[cfg(feature = "alloc")]
217    pub struct TestHashTag;
218
219    #[cfg(feature = "alloc")]
220    impl sha256t::Tag for TestHashTag {
221        const MIDSTATE: sha256::Midstate = sha256::Midstate::new(TEST_MIDSTATE, 64);
222    }
223
224    // We support manually implementing `Tag` and creating a tagged hash from it.
225    #[cfg(feature = "alloc")]
226    #[cfg(feature = "hex")]
227    pub type TestHash = sha256t::Hash<TestHashTag>;
228
229    #[test]
230    #[cfg(feature = "alloc")]
231    #[cfg(feature = "hex")]
232    fn manually_created_sha256t_hash_type() {
233        use alloc::string::ToString;
234
235        assert_eq!(TestHash::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
236    }
237
238    // We also provide macros to create the tag and the hash type.
239    sha256t_tag! {
240        /// Test detailed explanation.
241        struct NewTypeTagBackward = raw(TEST_MIDSTATE, 64);
242    }
243    hash_newtype! {
244        /// A test hash.
245        #[hash_newtype(backward)]
246        struct NewTypeHashBackward(sha256t::Hash<NewTypeTagBackward>);
247    }
248    #[cfg(feature = "hex")]
249    crate::impl_hex_for_newtype!(NewTypeHashBackward);
250    #[cfg(not(feature = "hex"))]
251    crate::impl_debug_only_for_newtype!(NewTypeHashBackward);
252
253    #[test]
254    #[cfg(feature = "alloc")]
255    #[cfg(feature = "hex")]
256    fn macro_created_sha256t_hash_type_backward() {
257        use alloc::string::ToString;
258
259        let inner = sha256t::Hash::<NewTypeTagBackward>::hash(&[0]);
260        let hash = NewTypeHashBackward::from_byte_array(inner.to_byte_array());
261        assert_eq!(hash.to_string(), HASH_ZERO_BACKWARD);
262        // Note one has to use the new wrapper type to get backwards formatting.
263        assert_eq!(sha256t::Hash::<NewTypeTagBackward>::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
264    }
265
266    // We also provide a macro to create the tag and the hash type.
267    sha256t_tag! {
268        /// Test detailed explanation.
269        struct NewTypeTagForward = raw(TEST_MIDSTATE, 64);
270    }
271    hash_newtype! {
272        /// A test hash.
273        #[hash_newtype(forward)]
274        struct NewTypeHashForward(sha256t::Hash<NewTypeTagForward>);
275    }
276    #[cfg(feature = "hex")]
277    crate::impl_hex_for_newtype!(NewTypeHashForward);
278    #[cfg(not(feature = "hex"))]
279    crate::impl_debug_only_for_newtype!(NewTypeHashForward);
280
281    #[test]
282    #[cfg(feature = "alloc")]
283    #[cfg(feature = "hex")]
284    fn macro_created_sha256t_hash_type_prints_forward() {
285        use alloc::string::ToString;
286
287        let inner = sha256t::Hash::<NewTypeTagForward>::hash(&[0]);
288        let hash = NewTypeHashForward::from_byte_array(inner.to_byte_array());
289        assert_eq!(hash.to_string(), HASH_ZERO_FORWARD);
290        // We can also just use the `sha256t::Hash` type directly.
291        assert_eq!(sha256t::Hash::<NewTypeTagForward>::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
292    }
293}