1use core::cmp;
6use core::marker::PhantomData;
7
8#[cfg(doc)]
9use crate::sha256::Midstate;
10use crate::{sha256, HashEngine as _};
11
12pub 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
24pub 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
40pub trait Tag {
42 const MIDSTATE: sha256::Midstate;
44}
45
46internals::transparent_newtype! {
47 pub struct Hash<T>(PhantomData<T>, [u8; 32]);
49
50 impl<T> Hash<T> {
51 pub fn from_bytes_ref(bytes: &_) -> &Self;
54
55 pub fn from_bytes_mut(bytes: &mut _) -> &mut Self;
58 }
59}
60
61impl<T> Hash<T>
62where
63 T: Tag,
64{
65 pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self(PhantomData, bytes) }
67
68 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 pub fn engine() -> HashEngine<T> { HashEngine::default() }
75
76 #[allow(clippy::self_named_constructors)] 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 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 pub const fn to_byte_array(self) -> [u8; 32] { self.1 }
101
102 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#[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; 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#[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 #[cfg(feature = "alloc")]
206 #[cfg(feature = "hex")]
207 const HASH_ZERO_BACKWARD: &str =
208 "29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed";
209 #[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 #[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 sha256t_tag! {
240 struct NewTypeTagBackward = raw(TEST_MIDSTATE, 64);
242 }
243 hash_newtype! {
244 #[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 assert_eq!(sha256t::Hash::<NewTypeTagBackward>::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
264 }
265
266 sha256t_tag! {
268 struct NewTypeTagForward = raw(TEST_MIDSTATE, 64);
270 }
271 hash_newtype! {
272 #[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 assert_eq!(sha256t::Hash::<NewTypeTagForward>::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
292 }
293}