Merge rust-bitcoin/rust-bitcoin#3611: Hashes: Make `hex` dependency optional

ec06028f63 hashes: Make hex dependency optional (Tobin C. Harding)
9dce0b4b8c Remove hex string trait bounds from GeneralHash (Tobin C. Harding)
766f498b33 Pull serde stuff out of impl_bytelike_traits macro (Tobin C. Harding)

Pull request description:

  This is done in 3 parts:

  1. Pull the `serde` stuff out of `impl_bytelike_traits` to fix the bug described here: https://github.com/rust-bitcoin/rust-bitcoin/issues/2654#issuecomment-2470716693
  2. Prepare the `hashes` trait by removing string/hex trait bounds from `GeneralHash` and also pull the hex/string stuff out of `impl_bytelike_traits`
  3. Make hex optional, including adding custom debug logic when `hex` feature is not enabled

  Patch 3 is tested in `hashes/embedded`, by the new `debug` unit test, and there is a `Midstate` unit test as well that covers the `Debug` impl.

  Close: #2654 - BOOM!

ACKs for top commit:
  apoelstra:
    ACK ec06028f63ba591a14c3a15cdfd410bb5ff1c09b; successfully ran local tests; nice!

Tree-SHA512: 85eb10d36a4581af6cd700f7ff876585bcc114c60e9864906e65659f3b3ee550fe6d9f40ca4230d870a9e23f0720723e11443ec329f16e40259a259b9be57466
This commit is contained in:
merge-script 2024-11-15 18:31:42 +00:00
commit d32422cdb7
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
23 changed files with 241 additions and 51 deletions

View File

@ -253,8 +253,10 @@ jobs:
run: cd bitcoin/embedded && cargo run --target thumbv7m-none-eabi
- name: "Run hashes/embedded no alloc"
run: cd hashes/embedded && cargo run --target thumbv7m-none-eabi
- name: "Run hashes/embedded with alloc"
- name: "Run hashes/embedded with alloc and no hex"
run: cd hashes/embedded && cargo run --target thumbv7m-none-eabi --features=alloc
- name: "Run hashes/embedded with alloc and hex"
run: cd hashes/embedded && cargo run --target thumbv7m-none-eabi --features=alloc,hex
ASAN: # hashes crate only.
name: ASAN - nightly toolchain

View File

@ -27,7 +27,7 @@ arbitrary = ["dep:arbitrary", "units/arbitrary", "primitives/arbitrary"]
[dependencies]
base58 = { package = "base58ck", version = "0.1.0", default-features = false, features = ["alloc"] }
bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] }
hashes = { package = "bitcoin_hashes", version = "0.15.0", default-features = false, features = ["alloc", "bitcoin-io"] }
hashes = { package = "bitcoin_hashes", version = "0.15.0", default-features = false, features = ["alloc", "bitcoin-io", "hex"] }
hex = { package = "hex-conservative", version = "0.3.0", default-features = false, features = ["alloc"] }
internals = { package = "bitcoin-internals", version = "0.4.0", features = ["alloc"] }
io = { package = "bitcoin-io", version = "0.2.0", default-features = false, features = ["alloc"] }

View File

@ -62,6 +62,10 @@ hashes::hash_newtype! {
pub struct FilterHeader(sha256d::Hash);
}
hashes::impl_hex_for_newtype!(FilterHash, FilterHeader);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(FilterHash, FilterHeader);
impl_hashencode!(FilterHash);
impl_hashencode!(FilterHeader);

View File

@ -58,6 +58,10 @@ hash_newtype! {
pub struct XKeyIdentifier(hash160::Hash);
}
hashes::impl_hex_for_newtype!(XKeyIdentifier);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(XKeyIdentifier);
/// Extended private key
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]

View File

@ -92,6 +92,11 @@ hashes::hash_newtype! {
/// SegWit version of a Bitcoin Script bytecode hash.
pub struct WScriptHash(sha256::Hash);
}
hashes::impl_hex_for_newtype!(ScriptHash, WScriptHash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(ScriptHash, WScriptHash);
impl_asref_push_bytes!(ScriptHash, WScriptHash);
impl ScriptHash {

View File

@ -264,6 +264,11 @@ hashes::hash_newtype! {
/// SegWit version of a public key hash.
pub struct WPubkeyHash(hash160::Hash);
}
hashes::impl_hex_for_newtype!(PubkeyHash, WPubkeyHash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(PubkeyHash, WPubkeyHash);
impl_asref_push_bytes!(PubkeyHash, WPubkeyHash);
impl From<PublicKey> for PubkeyHash {

View File

@ -56,6 +56,10 @@ hash_newtype! {
pub struct SegwitV0Sighash(sha256d::Hash);
}
hashes::impl_hex_for_newtype!(LegacySighash, SegwitV0Sighash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(LegacySighash, SegwitV0Sighash);
impl_message_from_hash!(LegacySighash);
impl_message_from_hash!(SegwitV0Sighash);
@ -82,6 +86,10 @@ hash_newtype! {
pub struct TapSighash(sha256t::Hash<TapSighashTag>);
}
hashes::impl_hex_for_newtype!(TapSighash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapSighash);
impl_message_from_hash!(TapSighash);
/// Efficiently calculates signature hash message for legacy, segwit and Taproot inputs.

View File

@ -17,12 +17,13 @@ exclude = ["tests", "contrib"]
default = ["std"]
std = ["alloc", "bitcoin-io?/std", "hex/std"]
alloc = ["bitcoin-io?/alloc", "hex/alloc"]
serde = ["dep:serde", "hex"]
# Smaller (but slower) implementation of sha256, sha512 and ripemd160
small-hash = []
[dependencies]
hex = { package = "hex-conservative", version = "0.3.0", default-features = false }
hex = { package = "hex-conservative", version = "0.3.0", default-features = false, optional = true }
bitcoin-io = { version = "0.2.0", default-features = false, optional = true }
serde = { version = "1.0", default-features = false, optional = true }

View File

@ -11,6 +11,7 @@ members = ["."]
[features]
alloc = ["alloc-cortex-m", "bitcoin_hashes/alloc"]
hex = ["bitcoin_hashes/hex"]
[dependencies]
cortex-m = "0.6.0"

View File

@ -12,13 +12,20 @@ extern crate bitcoin_hashes;
use bitcoin_hashes::{sha256, HashEngine};
use bitcoin_io::Write;
use cortex_m_rt::entry;
use cortex_m_semihosting::{debug, hprintln};
use cortex_m_semihosting::debug;
#[cfg(feature = "hex")]
use cortex_m_semihosting::hprintln;
use panic_halt as _;
hash_newtype! {
struct TestType(sha256::Hash);
}
#[cfg(feature = "hex")]
bitcoin_hashes::impl_hex_for_newtype!(TestType);
#[cfg(not(feature = "hex"))]
bitcoin_hashes::impl_debug_only_for_newtype!(TestType);
// this is the allocator the application will use
#[cfg(feature = "alloc")]
#[global_allocator]
@ -34,16 +41,19 @@ fn main() -> ! {
let mut engine = sha256::Hash::engine();
engine.write_all(b"abc").unwrap();
#[cfg(feature = "hex")]
check_result(engine);
let mut engine = sha256::Hash::engine();
engine.input(b"abc");
#[cfg(feature = "hex")]
check_result(engine);
debug::exit(debug::EXIT_SUCCESS);
loop {}
}
#[cfg(feature = "hex")]
fn check_result(engine: sha256::HashEngine) {
let hash = TestType(sha256::Hash::from_engine(engine));

View File

@ -96,15 +96,15 @@ impl<T: GeneralHash> HashEngine for HmacEngine<T> {
fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) }
}
impl<T: GeneralHash> fmt::Debug for Hmac<T> {
impl<T: GeneralHash + fmt::Debug> fmt::Debug for Hmac<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) }
}
impl<T: GeneralHash> fmt::Display for Hmac<T> {
impl<T: GeneralHash + fmt::Display> fmt::Display for Hmac<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}
impl<T: GeneralHash> fmt::LowerHex for Hmac<T> {
impl<T: GeneralHash + fmt::LowerHex> fmt::LowerHex for Hmac<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
}

View File

@ -20,7 +20,11 @@
/// `from_engine` obviously implements the finalization algorithm.
macro_rules! hash_trait_impls {
($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
$crate::impl_bytelike_traits!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);
$crate::impl_bytelike_traits!(Hash, { $bits / 8 } $(, $gen: $gent)*);
#[cfg(feature = "hex")]
$crate::impl_hex_string_traits!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);
#[cfg(not(feature = "hex"))]
$crate::impl_debug_only!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::GeneralHash for Hash<$($gen),*> {
type Engine = HashEngine;
@ -28,6 +32,9 @@ macro_rules! hash_trait_impls {
fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) }
}
#[cfg(feature = "serde")]
$crate::serde_impl!(Hash, { $bits / 8} $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::Hash for Hash<$($gen),*> {
type Bytes = [u8; $bits / 8];

View File

@ -86,6 +86,7 @@ extern crate serde_test;
extern crate test;
/// Re-export the `hex-conservative` crate.
#[cfg(feature = "hex")]
pub extern crate hex;
#[doc(hidden)]
@ -126,7 +127,8 @@ pub mod serde_macros {
}
}
use core::{convert, fmt, hash};
use core::fmt::{self, Write as _};
use core::{convert, hash};
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
@ -261,20 +263,10 @@ pub trait GeneralHash: Hash {
/// Trait which applies to hashes of all types.
pub trait Hash:
Copy
+ Clone
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ hash::Hash
+ fmt::Debug
+ fmt::Display
+ fmt::LowerHex
+ convert::AsRef<[u8]>
Copy + Clone + PartialEq + Eq + PartialOrd + Ord + hash::Hash + convert::AsRef<[u8]>
{
/// The byte array that represents the hash internally.
type Bytes: hex::FromHex + Copy + IsByteArray;
type Bytes: Copy + IsByteArray;
/// Length of the hash, in bytes.
const LEN: usize = Self::Bytes::LEN;
@ -322,6 +314,22 @@ fn incomplete_block_len<H: HashEngine>(eng: &H) -> usize {
(eng.n_bytes_hashed() % block_size) as usize
}
/// Writes `bytes` as a `hex` string to the formatter.
///
/// For when we cannot rely on having the `hex` feature enabled. Ignores formatter options and just
/// writes with plain old `f.write_char()`.
pub fn debug_hex(bytes: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
for &b in bytes {
let lower = HEX_TABLE[usize::from(b >> 4)];
let upper = HEX_TABLE[usize::from(b & 0b00001111)];
f.write_char(char::from(lower))?;
f.write_char(char::from(upper))?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
@ -335,6 +343,11 @@ mod tests {
struct TestNewtype2(sha256d::Hash);
}
#[cfg(feature = "hex")]
crate::impl_hex_for_newtype!(TestNewtype, TestNewtype2);
#[cfg(not(feature = "hex"))]
crate::impl_debug_only_for_newtype!(TestNewtype, TestNewtype2);
#[test]
#[cfg(feature = "alloc")]
fn newtype_fmt_roundtrip() {

View File

@ -4,6 +4,8 @@
//!
//! - [`sha256t_tag`](crate::sha256t_tag)
//! - [`hash_newtype`](crate::hash_newtype)
//! - [`impl_hex_for_newtype`](crate::impl_hex_for_newtype)
//! - [`impl_serde_for_newtype`](crate::impl_serde_for_newtype)
/// Macro used to define a tag.
///
@ -71,8 +73,7 @@ macro_rules! sha256t_tag {
///
/// You can add arbitrary doc comments or other attributes to the struct or it's field. Note that
/// the macro already derives [`Copy`], [`Clone`], [`Eq`], [`PartialEq`],
/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`]. With the `serde` feature on, this also adds
/// `Serialize` and `Deserialize` implementations.
/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`].
///
/// You can also define multiple newtypes within one macro call:
///
@ -133,7 +134,7 @@ macro_rules! hash_newtype {
$({ $($type_attrs)* })*
}
$crate::impl_bytelike_traits!($newtype, { <$newtype as $crate::Hash>::LEN }, <$newtype as $crate::Hash>::DISPLAY_BACKWARD);
$crate::impl_bytelike_traits!($newtype, { <$newtype as $crate::Hash>::LEN });
#[allow(unused)] // Private wrapper types may not need all functions.
impl $newtype {
@ -194,18 +195,80 @@ macro_rules! hash_newtype {
};
}
/// Implements string functions using hex for a new type crated with [`crate::hash_newtype`] macro.
///
/// Implements:
///
/// * `str::FromStr`
/// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`
/// * `fmt::{Display, Debug}` by calling `LowerHex`
#[macro_export]
#[cfg(feature = "hex")]
macro_rules! impl_hex_for_newtype {
($($newtype:ident),*) => {
$(
$crate::impl_hex_string_traits!($newtype, { <$newtype as $crate::Hash>::LEN }, { <$newtype as $crate::Hash>::DISPLAY_BACKWARD });
)*
}
}
/// Implements `fmt::Debug` using hex for a new type crated with [`crate::hash_newtype`] macro.
///
/// This is provided in case you do not want to use the `hex` feature.
#[macro_export]
macro_rules! impl_debug_only_for_newtype {
($($newtype:ident),*) => {
$(
$crate::impl_debug_only!($newtype, { <$newtype as $crate::Hash>::LEN }, { <$newtype as $crate::Hash>::DISPLAY_BACKWARD });
)*
}
}
/// Adds trait impls to a bytelike type.
///
/// Implements:
///
/// * `AsRef[u8; $len]`
/// * `AsRef[u8]`
/// * `Borrow<[u8; $len]>`
/// * `Borrow<[u8]>`
///
/// ## Parameters
///
/// * `ty` - The bytelike type to implement the traits on.
/// * `$len` - The number of bytes this type has.
/// * `$gen: $gent` - generic type(s) and trait bound(s).
#[doc(hidden)]
#[macro_export]
macro_rules! impl_bytelike_traits {
($ty:ident, $len:expr $(, $gen:ident: $gent:ident)*) => {
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> {
#[inline]
fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> {
#[inline]
fn as_ref(&self) -> &[u8] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8; { $len }]> for $ty<$($gen),*> {
fn borrow(&self) -> &[u8; { $len }] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> {
fn borrow(&self) -> &[u8] { self.as_byte_array() }
}
}
}
/// Adds hex string trait impls to a bytelike type using hex.
///
/// Implements:
///
/// * `str::FromStr`
/// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`.
/// * `fmt::{Display, Debug}` by calling `LowerHex`
/// * `serde::{Deserialize, Serialize}`
/// * `AsRef[u8; $len]`
/// * `AsRef[u8]`
/// * `Borrow<[u8; $len]>`
/// * `Borrow<[u8]>`
///
/// Requires:
///
@ -224,7 +287,8 @@ macro_rules! hash_newtype {
/// [`hex-conservative`]: <https://crates.io/crates/hex-conservative>
#[doc(hidden)]
#[macro_export]
macro_rules! impl_bytelike_traits {
#[cfg(feature = "hex")]
macro_rules! impl_hex_string_traits {
($ty:ident, $len:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
impl<$($gen: $gent),*> $crate::_export::_core::str::FromStr for $ty<$($gen),*> {
type Err = $crate::hex::HexToArrayError;
@ -246,25 +310,19 @@ macro_rules! impl_bytelike_traits {
const LENGTH: usize = ($len); // parens required due to rustc parser weirdness
}
}
}
}
$crate::serde_impl!($ty, $len $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> {
/// Implements `fmt::Debug` using hex.
#[doc(hidden)]
#[macro_export]
macro_rules! impl_debug_only {
($ty:ident, $len:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
#[inline]
fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> {
#[inline]
fn as_ref(&self) -> &[u8] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8; { $len }]> for $ty<$($gen),*> {
fn borrow(&self) -> &[u8; { $len }] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> {
fn borrow(&self) -> &[u8] { self.as_byte_array() }
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
$crate::debug_hex(self.as_byte_array(), f)
}
}
}
}
@ -433,6 +491,17 @@ pub mod serde_details {
}
}
/// Implements `Serialize` and `Deserialize` for a new type created with [`crate::hash_newtype`] macro.
#[macro_export]
#[cfg(feature = "serde")]
macro_rules! impl_serde_for_newtype {
($($newtype:ident),*) => {
$(
$crate::serde_impl!($newtype, { <$newtype as $crate::Hash>::LEN });
)*
}
}
/// Implements `Serialize` and `Deserialize` for a type `$t` which
/// represents a newtype over a byte-slice over length `$len`.
#[doc(hidden)]
@ -501,13 +570,29 @@ mod test {
/// Test hash.
struct TestHash(crate::sha256d::Hash);
}
#[cfg(feature = "hex")]
crate::impl_hex_for_newtype!(TestHash);
#[cfg(not(feature = "hex"))]
crate::impl_debug_only_for_newtype!(TestHash);
impl TestHash {
fn all_zeros() -> Self { Self::from_byte_array([0; 32]) }
}
// NB: This runs with and without `hex` feature enabled, testing different code paths for each.
#[test]
#[cfg(feature = "alloc")]
fn debug() {
use alloc::format;
let want = "0000000000000000000000000000000000000000000000000000000000000000";
let got = format!("{:?}", TestHash::all_zeros());
assert_eq!(got, want)
}
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn display() {
use alloc::format;
@ -518,6 +603,7 @@ mod test {
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn display_alternate() {
use alloc::format;
@ -528,6 +614,7 @@ mod test {
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn lower_hex() {
use alloc::format;
@ -538,6 +625,7 @@ mod test {
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn lower_hex_alternate() {
use alloc::format;

View File

@ -8,8 +8,6 @@ use core::arch::x86::*;
use core::arch::x86_64::*;
use core::{cmp, convert, fmt};
use hex::DisplayHex;
use crate::{incomplete_block_len, sha256d, HashEngine as _};
#[cfg(doc)]
use crate::{sha256t, sha256t_tag};
@ -218,8 +216,15 @@ impl Midstate {
impl fmt::Debug for Midstate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
struct Encoder<'a> {
bytes: &'a [u8; 32],
}
impl fmt::Debug for Encoder<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { crate::debug_hex(self.bytes, f) }
}
f.debug_struct("Midstate")
.field("bytes", &self.bytes.as_hex())
.field("bytes", &Encoder { bytes: &self.bytes })
.field("length", &self.bytes_hashed)
.finish()
}

View File

@ -321,9 +321,14 @@ mod tests {
#[hash_newtype(backward)]
struct NewTypeHashBackward(sha256t::Hash<NewTypeTagBackward>);
}
#[cfg(feature = "hex")]
crate::impl_hex_for_newtype!(NewTypeHashBackward);
#[cfg(not(feature = "hex"))]
crate::impl_debug_only_for_newtype!(NewTypeHashBackward);
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn macro_created_sha256t_hash_type_backward() {
use alloc::string::ToString;
@ -344,9 +349,14 @@ mod tests {
#[hash_newtype(forward)]
struct NewTypeHashForward(sha256t::Hash<NewTypeTagForward>);
}
#[cfg(feature = "hex")]
crate::impl_hex_for_newtype!(NewTypeHashForward);
#[cfg(not(feature = "hex"))]
crate::impl_debug_only_for_newtype!(NewTypeHashForward);
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn macro_created_sha256t_hash_type_prints_forward() {
use alloc::string::ToString;

View File

@ -3,6 +3,7 @@
//! Test the `bitcoin-io` implementations.
#![cfg(feature = "bitcoin-io")]
#![cfg(feature = "hex")]
use bitcoin_hashes::{
hash160, hmac, ripemd160, sha1, sha256, sha256d, sha384, sha512, sha512_256, siphash24,

View File

@ -2,6 +2,8 @@
//!
//! Note that if `bitcoin-io` is enabled then we get more regression-like testing from `./io.rs`.
#![cfg(feature = "hex")]
use bitcoin_hashes::{
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
GeneralHash as _, HashEngine as _, Hmac, HmacEngine,

View File

@ -22,7 +22,7 @@ serde = ["dep:serde", "hashes/serde", "internals/serde", "units/serde", "alloc"]
arbitrary = ["dep:arbitrary", "units/arbitrary"]
[dependencies]
hashes = { package = "bitcoin_hashes", version = "0.15.0", default-features = false, features = ["bitcoin-io"] }
hashes = { package = "bitcoin_hashes", version = "0.15.0", default-features = false, features = ["bitcoin-io", "hex"] }
hex = { package = "hex-conservative", version = "0.3.0", default-features = false }
internals = { package = "bitcoin-internals", version = "0.4.0" }
io = { package = "bitcoin-io", version = "0.2.0", default-features = false }

View File

@ -295,6 +295,10 @@ hashes::hash_newtype! {
pub struct WitnessCommitment(sha256d::Hash);
}
hashes::impl_hex_for_newtype!(BlockHash, WitnessCommitment);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(BlockHash, WitnessCommitment);
impl BlockHash {
/// Dummy hash used as the previous blockhash of the genesis block.
pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]);

View File

@ -10,3 +10,7 @@ hashes::hash_newtype! {
/// A hash corresponding to the Merkle tree root for witness data.
pub struct WitnessMerkleNode(sha256d::Hash);
}
hashes::impl_hex_for_newtype!(TxMerkleNode, WitnessMerkleNode);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TxMerkleNode, WitnessMerkleNode);

View File

@ -18,6 +18,10 @@ hash_newtype! {
pub struct TapLeafHash(sha256t::Hash<TapLeafTag>);
}
hashes::impl_hex_for_newtype!(TapLeafHash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapLeafHash);
sha256t_tag! {
pub struct TapBranchTag = hash_str("TapBranch");
}
@ -29,6 +33,10 @@ hash_newtype! {
pub struct TapNodeHash(sha256t::Hash<TapBranchTag>);
}
hashes::impl_hex_for_newtype!(TapNodeHash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapNodeHash);
sha256t_tag! {
pub struct TapTweakTag = hash_str("TapTweak");
}
@ -40,6 +48,10 @@ hash_newtype! {
pub struct TapTweakHash(sha256t::Hash<TapTweakTag>);
}
hashes::impl_hex_for_newtype!(TapTweakHash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapTweakHash);
impl From<TapLeafHash> for TapNodeHash {
fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) }
}

View File

@ -488,6 +488,10 @@ hashes::hash_newtype! {
pub struct Wtxid(sha256d::Hash);
}
hashes::impl_hex_for_newtype!(Txid, Wtxid);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(Txid, Wtxid);
impl Txid {
/// The `Txid` used in a coinbase prevout.
///