diff --git a/contrib/crates.sh b/contrib/crates.sh index b3bb34178..c3d605eee 100644 --- a/contrib/crates.sh +++ b/contrib/crates.sh @@ -5,4 +5,4 @@ # shellcheck disable=SC2034 # Crates in this workspace to test (note "fuzz" is only built not tested). -CRATES=("addresses" "base58" "bitcoin" "fuzz" "hashes" "internals" "io" "units") +CRATES=("addresses" "base58" "bitcoin" "hashes" "internals" "io" "units" "fuzz") diff --git a/hashes/contrib/extra_tests.sh b/hashes/contrib/extra_tests.sh index deea345b6..4a39a1f1b 100755 --- a/hashes/contrib/extra_tests.sh +++ b/hashes/contrib/extra_tests.sh @@ -5,5 +5,12 @@ set -euox pipefail REPO_DIR=$(git rev-parse --show-toplevel) pushd "$REPO_DIR/hashes/extended_tests/schemars" > /dev/null + +# This comment mentions Rust 1.63 to assist grepping when doing MSRV update. +# +if cargo --version | grep -q '1\.63'; then + cargo update -p regex --precise 1.7.3 +fi + cargo test popd > /dev/null diff --git a/hashes/extended_tests/schemars/README.md b/hashes/extended_tests/schemars/README.md index 51dc97c42..e93cd0b0a 100644 --- a/hashes/extended_tests/schemars/README.md +++ b/hashes/extended_tests/schemars/README.md @@ -4,10 +4,6 @@ Run as usual with `cargo test`. ## Minimum Supported Rust Version (MSRV) -To run the tests with the MSRV you will need to pin `serde`: - -```bash -cargo update -p serde --precise 1.0.156 -cargo update -p regex --precise 1.7.3 -cargo update -p chrono --precise 0.4.24 -``` +To run the tests with the current MSRV you will need to pin some +dependencies. See the `hashes/contrib/extra_tests.sh` script for the +current list of pins. diff --git a/hashes/extended_tests/schemars/src/main.rs b/hashes/extended_tests/schemars/src/main.rs index 2af4690ed..c9f73d40a 100644 --- a/hashes/extended_tests/schemars/src/main.rs +++ b/hashes/extended_tests/schemars/src/main.rs @@ -2,6 +2,7 @@ fn main() {} #[cfg(test)] mod tests { use bitcoin_hashes::*; + use bitcoin_hashes::sha256::Midstate; #[test] fn hash160() { @@ -117,6 +118,9 @@ mod tests { 147, 108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201, ]; + // The midstate of an empty hash engine tagged with "TapLeaf". + const TAP_LEAF_MIDSTATE: Midstate = Midstate::new(TEST_MIDSTATE, 64); + #[derive( Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash, schemars::JsonSchema, )] @@ -124,9 +128,7 @@ mod tests { impl sha256t::Tag for TestHashTag { fn engine() -> sha256::HashEngine { - // The TapRoot TapLeaf midstate. - let midstate = sha256::Midstate::from_byte_array(TEST_MIDSTATE); - sha256::HashEngine::from_midstate(midstate, 64) + sha256::HashEngine::from_midstate(TAP_LEAF_MIDSTATE) } } diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index fb78fdbd7..897f97b8f 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -324,7 +324,7 @@ impl std::error::Error for FromSliceError {} #[cfg(test)] mod tests { use super::*; - use crate::{sha256, sha256d}; + use crate::sha256d; hash_newtype! { /// A test newtype @@ -351,7 +351,10 @@ mod tests { } #[test] + #[cfg(feature = "bitcoin-io")] fn hash_reader() { + use crate::sha256; + let mut reader: &[u8] = b"hello"; assert_eq!(sha256::Hash::hash_reader(&mut reader).unwrap(), sha256::Hash::hash(b"hello"),) } diff --git a/hashes/src/sha256t.rs b/hashes/src/sha256t.rs index 2a0a24870..bb31d466d 100644 --- a/hashes/src/sha256t.rs +++ b/hashes/src/sha256t.rs @@ -240,13 +240,6 @@ macro_rules! sha256t_hash_newtype { { <$hash_name as $crate::GeneralHash>::hash_byte_chunks(byte_slices) } - - /// Hashes the entire contents of the `reader`. - #[cfg(feature = "bitcoin-io")] - #[allow(unused)] // the user of macro may not need this - fn hash_reader(reader: &mut R) -> Result { - <$hash_name as $crate::GeneralHash>::hash_reader(reader) - } } impl $crate::GeneralHash for $hash_name { diff --git a/hashes/src/siphash24.rs b/hashes/src/siphash24.rs index 2e57adcdd..6aaed346a 100644 --- a/hashes/src/siphash24.rs +++ b/hashes/src/siphash24.rs @@ -4,8 +4,11 @@ use core::ops::Index; use core::slice::SliceIndex; +use core::str::FromStr; use core::{cmp, mem, ptr}; +use hex::FromHex; + use crate::internal_macros::arr_newtype_fmt_impl; use crate::HashEngine as _; @@ -14,6 +17,21 @@ use crate::HashEngine as _; #[repr(transparent)] pub struct Hash([u8; 8]); +#[cfg(feature = "schemars")] +impl schemars::JsonSchema for Hash { + fn schema_name() -> String { "Hash".to_owned() } + + fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { + let mut schema: schemars::schema::SchemaObject = ::json_schema(gen).into(); + schema.string = Some(Box::new(schemars::schema::StringValidation { + max_length: Some(8 * 2), + min_length: Some(8 * 2), + pattern: Some("[0-9a-fA-F]+".to_owned()), + })); + schema.into() + } +} + #[cfg(not(hashes_fuzz))] fn from_engine(e: HashEngine) -> Hash { Hash::from_u64(Hash::from_engine_to_u64(e)) } @@ -211,6 +229,15 @@ impl Hash { /// Creates a hash from its (little endian) 64-bit integer representation. pub fn from_u64(hash: u64) -> Hash { Hash(hash.to_le_bytes()) } + /// Returns the underlying byte array. + pub const fn to_byte_array(self) -> [u8; 8] { self.0 } + + /// Returns a reference to the underlying byte array. + pub const fn as_byte_array(&self) -> &[u8; 8] { &self.0 } + + /// Constructs a hash from the underlying byte array. + pub const fn from_byte_array(bytes: [u8; 8]) -> Self { Self(bytes) } + fn from_slice(sl: &[u8]) -> Result { let mut ret = [0; 8]; ret.copy_from_slice(sl); @@ -226,11 +253,11 @@ impl crate::Hash for Hash { fn from_slice(sl: &[u8]) -> Result { Self::from_slice(sl) } - fn to_byte_array(self) -> Self::Bytes { self.0 } + fn to_byte_array(self) -> Self::Bytes { self.to_byte_array() } - fn as_byte_array(&self) -> &Self::Bytes { &self.0 } + fn as_byte_array(&self) -> &Self::Bytes { self.as_byte_array() } - fn from_byte_array(bytes: Self::Bytes) -> Self { Hash(bytes) } + fn from_byte_array(bytes: Self::Bytes) -> Self { Self::from_byte_array(bytes) } } impl> Index for Hash { @@ -240,7 +267,16 @@ impl> Index for Hash { fn index(&self, index: I) -> &Self::Output { &self.0[index] } } +impl FromStr for Hash { + type Err = hex::HexToArrayError; + fn from_str(s: &str) -> Result { + let bytes = <[u8; 8]>::from_hex(s)?; + Ok(Self::from_byte_array(bytes)) + } +} + arr_newtype_fmt_impl!(Hash, 8); +serde_impl!(Hash, 8); borrow_slice_impl!(Hash); /// Load an u64 using up to 7 bytes of a byte slice.