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:
commit
d32422cdb7
|
@ -253,8 +253,10 @@ jobs:
|
||||||
run: cd bitcoin/embedded && cargo run --target thumbv7m-none-eabi
|
run: cd bitcoin/embedded && cargo run --target thumbv7m-none-eabi
|
||||||
- name: "Run hashes/embedded no alloc"
|
- name: "Run hashes/embedded no alloc"
|
||||||
run: cd hashes/embedded && cargo run --target thumbv7m-none-eabi
|
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
|
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.
|
ASAN: # hashes crate only.
|
||||||
name: ASAN - nightly toolchain
|
name: ASAN - nightly toolchain
|
||||||
|
|
|
@ -27,7 +27,7 @@ arbitrary = ["dep:arbitrary", "units/arbitrary", "primitives/arbitrary"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base58 = { package = "base58ck", version = "0.1.0", default-features = false, features = ["alloc"] }
|
base58 = { package = "base58ck", version = "0.1.0", default-features = false, features = ["alloc"] }
|
||||||
bech32 = { version = "0.11.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"] }
|
hex = { package = "hex-conservative", version = "0.3.0", default-features = false, features = ["alloc"] }
|
||||||
internals = { package = "bitcoin-internals", version = "0.4.0", 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"] }
|
io = { package = "bitcoin-io", version = "0.2.0", default-features = false, features = ["alloc"] }
|
||||||
|
|
|
@ -62,6 +62,10 @@ hashes::hash_newtype! {
|
||||||
pub struct FilterHeader(sha256d::Hash);
|
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!(FilterHash);
|
||||||
impl_hashencode!(FilterHeader);
|
impl_hashencode!(FilterHeader);
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,10 @@ hash_newtype! {
|
||||||
pub struct XKeyIdentifier(hash160::Hash);
|
pub struct XKeyIdentifier(hash160::Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashes::impl_hex_for_newtype!(XKeyIdentifier);
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
hashes::impl_serde_for_newtype!(XKeyIdentifier);
|
||||||
|
|
||||||
/// Extended private key
|
/// Extended private key
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug))]
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
|
|
|
@ -92,6 +92,11 @@ hashes::hash_newtype! {
|
||||||
/// SegWit version of a Bitcoin Script bytecode hash.
|
/// SegWit version of a Bitcoin Script bytecode hash.
|
||||||
pub struct WScriptHash(sha256::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_asref_push_bytes!(ScriptHash, WScriptHash);
|
||||||
|
|
||||||
impl ScriptHash {
|
impl ScriptHash {
|
||||||
|
|
|
@ -264,6 +264,11 @@ hashes::hash_newtype! {
|
||||||
/// SegWit version of a public key hash.
|
/// SegWit version of a public key hash.
|
||||||
pub struct WPubkeyHash(hash160::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_asref_push_bytes!(PubkeyHash, WPubkeyHash);
|
||||||
|
|
||||||
impl From<PublicKey> for PubkeyHash {
|
impl From<PublicKey> for PubkeyHash {
|
||||||
|
|
|
@ -56,6 +56,10 @@ hash_newtype! {
|
||||||
pub struct SegwitV0Sighash(sha256d::Hash);
|
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!(LegacySighash);
|
||||||
impl_message_from_hash!(SegwitV0Sighash);
|
impl_message_from_hash!(SegwitV0Sighash);
|
||||||
|
|
||||||
|
@ -82,6 +86,10 @@ hash_newtype! {
|
||||||
pub struct TapSighash(sha256t::Hash<TapSighashTag>);
|
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);
|
impl_message_from_hash!(TapSighash);
|
||||||
|
|
||||||
/// Efficiently calculates signature hash message for legacy, segwit and Taproot inputs.
|
/// Efficiently calculates signature hash message for legacy, segwit and Taproot inputs.
|
||||||
|
|
|
@ -17,12 +17,13 @@ exclude = ["tests", "contrib"]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["alloc", "bitcoin-io?/std", "hex/std"]
|
std = ["alloc", "bitcoin-io?/std", "hex/std"]
|
||||||
alloc = ["bitcoin-io?/alloc", "hex/alloc"]
|
alloc = ["bitcoin-io?/alloc", "hex/alloc"]
|
||||||
|
serde = ["dep:serde", "hex"]
|
||||||
# Smaller (but slower) implementation of sha256, sha512 and ripemd160
|
# Smaller (but slower) implementation of sha256, sha512 and ripemd160
|
||||||
small-hash = []
|
small-hash = []
|
||||||
|
|
||||||
[dependencies]
|
[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 }
|
bitcoin-io = { version = "0.2.0", default-features = false, optional = true }
|
||||||
serde = { version = "1.0", default-features = false, optional = true }
|
serde = { version = "1.0", default-features = false, optional = true }
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ members = ["."]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alloc = ["alloc-cortex-m", "bitcoin_hashes/alloc"]
|
alloc = ["alloc-cortex-m", "bitcoin_hashes/alloc"]
|
||||||
|
hex = ["bitcoin_hashes/hex"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.6.0"
|
cortex-m = "0.6.0"
|
||||||
|
|
|
@ -12,13 +12,20 @@ extern crate bitcoin_hashes;
|
||||||
use bitcoin_hashes::{sha256, HashEngine};
|
use bitcoin_hashes::{sha256, HashEngine};
|
||||||
use bitcoin_io::Write;
|
use bitcoin_io::Write;
|
||||||
use cortex_m_rt::entry;
|
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 _;
|
use panic_halt as _;
|
||||||
|
|
||||||
hash_newtype! {
|
hash_newtype! {
|
||||||
struct TestType(sha256::Hash);
|
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
|
// this is the allocator the application will use
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
|
@ -34,16 +41,19 @@ fn main() -> ! {
|
||||||
|
|
||||||
let mut engine = sha256::Hash::engine();
|
let mut engine = sha256::Hash::engine();
|
||||||
engine.write_all(b"abc").unwrap();
|
engine.write_all(b"abc").unwrap();
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
check_result(engine);
|
check_result(engine);
|
||||||
|
|
||||||
let mut engine = sha256::Hash::engine();
|
let mut engine = sha256::Hash::engine();
|
||||||
engine.input(b"abc");
|
engine.input(b"abc");
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
check_result(engine);
|
check_result(engine);
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
fn check_result(engine: sha256::HashEngine) {
|
fn check_result(engine: sha256::HashEngine) {
|
||||||
let hash = TestType(sha256::Hash::from_engine(engine));
|
let hash = TestType(sha256::Hash::from_engine(engine));
|
||||||
|
|
||||||
|
|
|
@ -96,15 +96,15 @@ impl<T: GeneralHash> HashEngine for HmacEngine<T> {
|
||||||
fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) }
|
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) }
|
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) }
|
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) }
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,11 @@
|
||||||
/// `from_engine` obviously implements the finalization algorithm.
|
/// `from_engine` obviously implements the finalization algorithm.
|
||||||
macro_rules! hash_trait_impls {
|
macro_rules! hash_trait_impls {
|
||||||
($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
|
($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),*> {
|
impl<$($gen: $gent),*> $crate::GeneralHash for Hash<$($gen),*> {
|
||||||
type Engine = HashEngine;
|
type Engine = HashEngine;
|
||||||
|
@ -28,6 +32,9 @@ macro_rules! hash_trait_impls {
|
||||||
fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) }
|
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),*> {
|
impl<$($gen: $gent),*> $crate::Hash for Hash<$($gen),*> {
|
||||||
type Bytes = [u8; $bits / 8];
|
type Bytes = [u8; $bits / 8];
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ extern crate serde_test;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
/// Re-export the `hex-conservative` crate.
|
/// Re-export the `hex-conservative` crate.
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
pub extern crate hex;
|
pub extern crate hex;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[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.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -261,20 +263,10 @@ pub trait GeneralHash: Hash {
|
||||||
|
|
||||||
/// Trait which applies to hashes of all types.
|
/// Trait which applies to hashes of all types.
|
||||||
pub trait Hash:
|
pub trait Hash:
|
||||||
Copy
|
Copy + Clone + PartialEq + Eq + PartialOrd + Ord + hash::Hash + convert::AsRef<[u8]>
|
||||||
+ Clone
|
|
||||||
+ PartialEq
|
|
||||||
+ Eq
|
|
||||||
+ PartialOrd
|
|
||||||
+ Ord
|
|
||||||
+ hash::Hash
|
|
||||||
+ fmt::Debug
|
|
||||||
+ fmt::Display
|
|
||||||
+ fmt::LowerHex
|
|
||||||
+ convert::AsRef<[u8]>
|
|
||||||
{
|
{
|
||||||
/// The byte array that represents the hash internally.
|
/// The byte array that represents the hash internally.
|
||||||
type Bytes: hex::FromHex + Copy + IsByteArray;
|
type Bytes: Copy + IsByteArray;
|
||||||
|
|
||||||
/// Length of the hash, in bytes.
|
/// Length of the hash, in bytes.
|
||||||
const LEN: usize = Self::Bytes::LEN;
|
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
|
(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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -335,6 +343,11 @@ mod tests {
|
||||||
struct TestNewtype2(sha256d::Hash);
|
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]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
fn newtype_fmt_roundtrip() {
|
fn newtype_fmt_roundtrip() {
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
//!
|
//!
|
||||||
//! - [`sha256t_tag`](crate::sha256t_tag)
|
//! - [`sha256t_tag`](crate::sha256t_tag)
|
||||||
//! - [`hash_newtype`](crate::hash_newtype)
|
//! - [`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.
|
/// 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
|
/// 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`],
|
/// the macro already derives [`Copy`], [`Clone`], [`Eq`], [`PartialEq`],
|
||||||
/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`]. With the `serde` feature on, this also adds
|
/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`].
|
||||||
/// `Serialize` and `Deserialize` implementations.
|
|
||||||
///
|
///
|
||||||
/// You can also define multiple newtypes within one macro call:
|
/// You can also define multiple newtypes within one macro call:
|
||||||
///
|
///
|
||||||
|
@ -133,7 +134,7 @@ macro_rules! hash_newtype {
|
||||||
$({ $($type_attrs)* })*
|
$({ $($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.
|
#[allow(unused)] // Private wrapper types may not need all functions.
|
||||||
impl $newtype {
|
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.
|
/// Adds trait impls to a bytelike type.
|
||||||
///
|
///
|
||||||
/// Implements:
|
/// 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`
|
/// * `str::FromStr`
|
||||||
/// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`.
|
/// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`.
|
||||||
/// * `fmt::{Display, Debug}` by calling `LowerHex`
|
/// * `fmt::{Display, Debug}` by calling `LowerHex`
|
||||||
/// * `serde::{Deserialize, Serialize}`
|
|
||||||
/// * `AsRef[u8; $len]`
|
|
||||||
/// * `AsRef[u8]`
|
|
||||||
/// * `Borrow<[u8; $len]>`
|
|
||||||
/// * `Borrow<[u8]>`
|
|
||||||
///
|
///
|
||||||
/// Requires:
|
/// Requires:
|
||||||
///
|
///
|
||||||
|
@ -224,7 +287,8 @@ macro_rules! hash_newtype {
|
||||||
/// [`hex-conservative`]: <https://crates.io/crates/hex-conservative>
|
/// [`hex-conservative`]: <https://crates.io/crates/hex-conservative>
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[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)*) => {
|
($ty:ident, $len:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
|
||||||
impl<$($gen: $gent),*> $crate::_export::_core::str::FromStr for $ty<$($gen),*> {
|
impl<$($gen: $gent),*> $crate::_export::_core::str::FromStr for $ty<$($gen),*> {
|
||||||
type Err = $crate::hex::HexToArrayError;
|
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
|
const LENGTH: usize = ($len); // parens required due to rustc parser weirdness
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$crate::serde_impl!($ty, $len $(, $gen: $gent)*);
|
/// Implements `fmt::Debug` using hex.
|
||||||
|
#[doc(hidden)]
|
||||||
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> {
|
#[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]
|
#[inline]
|
||||||
fn as_ref(&self) -> &[u8; { $len }] { 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)
|
||||||
|
}
|
||||||
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() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
/// Implements `Serialize` and `Deserialize` for a type `$t` which
|
||||||
/// represents a newtype over a byte-slice over length `$len`.
|
/// represents a newtype over a byte-slice over length `$len`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -501,13 +570,29 @@ mod test {
|
||||||
/// Test hash.
|
/// Test hash.
|
||||||
struct TestHash(crate::sha256d::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 {
|
impl TestHash {
|
||||||
fn all_zeros() -> Self { Self::from_byte_array([0; 32]) }
|
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]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[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() {
|
fn display() {
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
|
|
||||||
|
@ -518,6 +603,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
fn display_alternate() {
|
fn display_alternate() {
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
|
|
||||||
|
@ -528,6 +614,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
fn lower_hex() {
|
fn lower_hex() {
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
|
|
||||||
|
@ -538,6 +625,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
fn lower_hex_alternate() {
|
fn lower_hex_alternate() {
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@ use core::arch::x86::*;
|
||||||
use core::arch::x86_64::*;
|
use core::arch::x86_64::*;
|
||||||
use core::{cmp, convert, fmt};
|
use core::{cmp, convert, fmt};
|
||||||
|
|
||||||
use hex::DisplayHex;
|
|
||||||
|
|
||||||
use crate::{incomplete_block_len, sha256d, HashEngine as _};
|
use crate::{incomplete_block_len, sha256d, HashEngine as _};
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::{sha256t, sha256t_tag};
|
use crate::{sha256t, sha256t_tag};
|
||||||
|
@ -218,8 +216,15 @@ impl Midstate {
|
||||||
|
|
||||||
impl fmt::Debug for Midstate {
|
impl fmt::Debug for Midstate {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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")
|
f.debug_struct("Midstate")
|
||||||
.field("bytes", &self.bytes.as_hex())
|
.field("bytes", &Encoder { bytes: &self.bytes })
|
||||||
.field("length", &self.bytes_hashed)
|
.field("length", &self.bytes_hashed)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,9 +321,14 @@ mod tests {
|
||||||
#[hash_newtype(backward)]
|
#[hash_newtype(backward)]
|
||||||
struct NewTypeHashBackward(sha256t::Hash<NewTypeTagBackward>);
|
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]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
fn macro_created_sha256t_hash_type_backward() {
|
fn macro_created_sha256t_hash_type_backward() {
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
|
|
||||||
|
@ -344,9 +349,14 @@ mod tests {
|
||||||
#[hash_newtype(forward)]
|
#[hash_newtype(forward)]
|
||||||
struct NewTypeHashForward(sha256t::Hash<NewTypeTagForward>);
|
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]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
#[cfg(feature = "hex")]
|
||||||
fn macro_created_sha256t_hash_type_prints_forward() {
|
fn macro_created_sha256t_hash_type_prints_forward() {
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
//! Test the `bitcoin-io` implementations.
|
//! Test the `bitcoin-io` implementations.
|
||||||
|
|
||||||
#![cfg(feature = "bitcoin-io")]
|
#![cfg(feature = "bitcoin-io")]
|
||||||
|
#![cfg(feature = "hex")]
|
||||||
|
|
||||||
use bitcoin_hashes::{
|
use bitcoin_hashes::{
|
||||||
hash160, hmac, ripemd160, sha1, sha256, sha256d, sha384, sha512, sha512_256, siphash24,
|
hash160, hmac, ripemd160, sha1, sha256, sha256d, sha384, sha512, sha512_256, siphash24,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
//!
|
//!
|
||||||
//! Note that if `bitcoin-io` is enabled then we get more regression-like testing from `./io.rs`.
|
//! Note that if `bitcoin-io` is enabled then we get more regression-like testing from `./io.rs`.
|
||||||
|
|
||||||
|
#![cfg(feature = "hex")]
|
||||||
|
|
||||||
use bitcoin_hashes::{
|
use bitcoin_hashes::{
|
||||||
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
|
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
|
||||||
GeneralHash as _, HashEngine as _, Hmac, HmacEngine,
|
GeneralHash as _, HashEngine as _, Hmac, HmacEngine,
|
||||||
|
|
|
@ -22,7 +22,7 @@ serde = ["dep:serde", "hashes/serde", "internals/serde", "units/serde", "alloc"]
|
||||||
arbitrary = ["dep:arbitrary", "units/arbitrary"]
|
arbitrary = ["dep:arbitrary", "units/arbitrary"]
|
||||||
|
|
||||||
[dependencies]
|
[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 }
|
hex = { package = "hex-conservative", version = "0.3.0", default-features = false }
|
||||||
internals = { package = "bitcoin-internals", version = "0.4.0" }
|
internals = { package = "bitcoin-internals", version = "0.4.0" }
|
||||||
io = { package = "bitcoin-io", version = "0.2.0", default-features = false }
|
io = { package = "bitcoin-io", version = "0.2.0", default-features = false }
|
||||||
|
|
|
@ -295,6 +295,10 @@ hashes::hash_newtype! {
|
||||||
pub struct WitnessCommitment(sha256d::Hash);
|
pub struct WitnessCommitment(sha256d::Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashes::impl_hex_for_newtype!(BlockHash, WitnessCommitment);
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
hashes::impl_serde_for_newtype!(BlockHash, WitnessCommitment);
|
||||||
|
|
||||||
impl BlockHash {
|
impl BlockHash {
|
||||||
/// Dummy hash used as the previous blockhash of the genesis block.
|
/// Dummy hash used as the previous blockhash of the genesis block.
|
||||||
pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]);
|
pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]);
|
||||||
|
|
|
@ -10,3 +10,7 @@ hashes::hash_newtype! {
|
||||||
/// A hash corresponding to the Merkle tree root for witness data.
|
/// A hash corresponding to the Merkle tree root for witness data.
|
||||||
pub struct WitnessMerkleNode(sha256d::Hash);
|
pub struct WitnessMerkleNode(sha256d::Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashes::impl_hex_for_newtype!(TxMerkleNode, WitnessMerkleNode);
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
hashes::impl_serde_for_newtype!(TxMerkleNode, WitnessMerkleNode);
|
||||||
|
|
|
@ -18,6 +18,10 @@ hash_newtype! {
|
||||||
pub struct TapLeafHash(sha256t::Hash<TapLeafTag>);
|
pub struct TapLeafHash(sha256t::Hash<TapLeafTag>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashes::impl_hex_for_newtype!(TapLeafHash);
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
hashes::impl_serde_for_newtype!(TapLeafHash);
|
||||||
|
|
||||||
sha256t_tag! {
|
sha256t_tag! {
|
||||||
pub struct TapBranchTag = hash_str("TapBranch");
|
pub struct TapBranchTag = hash_str("TapBranch");
|
||||||
}
|
}
|
||||||
|
@ -29,6 +33,10 @@ hash_newtype! {
|
||||||
pub struct TapNodeHash(sha256t::Hash<TapBranchTag>);
|
pub struct TapNodeHash(sha256t::Hash<TapBranchTag>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashes::impl_hex_for_newtype!(TapNodeHash);
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
hashes::impl_serde_for_newtype!(TapNodeHash);
|
||||||
|
|
||||||
sha256t_tag! {
|
sha256t_tag! {
|
||||||
pub struct TapTweakTag = hash_str("TapTweak");
|
pub struct TapTweakTag = hash_str("TapTweak");
|
||||||
}
|
}
|
||||||
|
@ -40,6 +48,10 @@ hash_newtype! {
|
||||||
pub struct TapTweakHash(sha256t::Hash<TapTweakTag>);
|
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 {
|
impl From<TapLeafHash> for TapNodeHash {
|
||||||
fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) }
|
fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,6 +488,10 @@ hashes::hash_newtype! {
|
||||||
pub struct Wtxid(sha256d::Hash);
|
pub struct Wtxid(sha256d::Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashes::impl_hex_for_newtype!(Txid, Wtxid);
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
hashes::impl_serde_for_newtype!(Txid, Wtxid);
|
||||||
|
|
||||||
impl Txid {
|
impl Txid {
|
||||||
/// The `Txid` used in a coinbase prevout.
|
/// The `Txid` used in a coinbase prevout.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue