// Bitcoin Hashes Library // Written in 2019 by // The rust-bitcoin developers. // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to // the public domain worldwide. This software is distributed without // any warranty. // // You should have received a copy of the CC0 Public Domain Dedication // along with this software. // If not, see . // //! SHA256t implementation (tagged SHA256). //! use core::{cmp, str}; use core::marker::PhantomData; use core::ops::Index; use core::slice::SliceIndex; use crate::{Error, hex, sha256}; type HashEngine = sha256::HashEngine; /// Trait representing a tag that can be used as a context for SHA256t hashes. pub trait Tag { /// Returns a hash engine that is pre-tagged and is ready to be used for the data. fn engine() -> sha256::HashEngine; } /// Output of the SHA256t hash function. #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[repr(transparent)] pub struct Hash( #[cfg_attr(feature = "schemars", schemars(schema_with = "crate::util::json_hex_string::len_32"))] [u8; 32], #[cfg_attr(feature = "schemars", schemars(skip))] PhantomData ); impl Hash { fn internal_new(arr: [u8; 32]) -> Self { Hash(arr, Default::default()) } fn internal_engine() -> HashEngine { T::engine() } } impl Copy for Hash {} impl Clone for Hash { fn clone(&self) -> Self { Hash(self.0, self.1) } } impl PartialEq for Hash { fn eq(&self, other: &Hash) -> bool { self.0 == other.0 } } impl Eq for Hash {} impl Default for Hash { fn default() -> Self { Hash([0; 32], PhantomData) } } impl PartialOrd for Hash { fn partial_cmp(&self, other: &Hash) -> Option { Some(cmp::Ord::cmp(self, other)) } } impl Ord for Hash { fn cmp(&self, other: &Hash) -> cmp::Ordering { cmp::Ord::cmp(&self.0, &other.0) } } impl core::hash::Hash for Hash { fn hash(&self, h: &mut H) { self.0.hash(h) } } crate::internal_macros::hash_trait_impls!(256, true, T: Tag); fn from_engine(e: sha256::HashEngine) -> Hash { use crate::Hash as _; Hash::from_inner(sha256::Hash::from_engine(e).into_inner()) } /// Macro used to define a newtype tagged hash. /// It creates two public types: /// - a sha256t::Tag struct, /// - a sha256t::Hash type alias. #[macro_export] macro_rules! sha256t_hash_newtype { ($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $reverse: expr) => { sha256t_hash_newtype!($newtype, $tag, $midstate, $midstate_len, $docs, $reverse, stringify!($newtype)); }; ($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $reverse: expr, $sname:expr) => { #[doc = "The tag used for ["] #[doc = $sname] #[doc = "]"] #[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] pub struct $tag; impl $crate::sha256t::Tag for $tag { fn engine() -> $crate::sha256::HashEngine { let midstate = $crate::sha256::Midstate::from_inner($midstate); $crate::sha256::HashEngine::from_midstate(midstate, $midstate_len) } } $crate::hash_newtype!($newtype, $crate::sha256t::Hash<$tag>, 32, $docs, $reverse); }; } #[cfg(test)] mod tests { use crate::{sha256, sha256t}; #[cfg(any(feature = "std", feature = "alloc"))] use crate::Hash; const TEST_MIDSTATE: [u8; 32] = [ 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, 108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201, ]; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct TestHashTag; impl sha256t::Tag for TestHashTag { fn engine() -> sha256::HashEngine { // The TapRoot TapLeaf midstate. let midstate = sha256::Midstate::from_inner(TEST_MIDSTATE); sha256::HashEngine::from_midstate(midstate, 64) } } /// A hash tagged with `$name`. #[cfg(any(feature = "std", feature = "alloc"))] pub type TestHash = sha256t::Hash; sha256t_hash_newtype!(NewTypeHash, NewTypeTag, TEST_MIDSTATE, 64, doc="test hash", true); #[test] #[cfg(any(feature = "std", feature = "alloc"))] fn test_sha256t() { assert_eq!( TestHash::hash(&[0]).to_string(), "29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed" ); assert_eq!( NewTypeHash::hash(&[0]).to_string(), "29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed" ); } }