hashes: Make hex dependency optional
The only reason we need `hex-conservative` is to parse strings and format them as hex. For users that do not require this functionality we can make the `hex-conservative` crate an optional dependency. The `serde` feature requires `Display` so we enable `hex` from the `serde` feature. If `hex` feature is not enabled we still need to be able to debug so provide `fmt::Debug` functionality by way of macros. Close: #2654
This commit is contained in:
parent
9dce0b4b8c
commit
ec06028f63
|
@ -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
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ members = ["."]
|
|||
|
||||
[features]
|
||||
alloc = ["alloc-cortex-m", "bitcoin_hashes/alloc"]
|
||||
hex = ["bitcoin_hashes/hex"]
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.6.0"
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
macro_rules! hash_trait_impls {
|
||||
($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
|
||||
$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;
|
||||
|
|
|
@ -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,6 +127,7 @@ pub mod serde_macros {
|
|||
}
|
||||
}
|
||||
|
||||
use core::fmt::{self, Write as _};
|
||||
use core::{convert, hash};
|
||||
|
||||
#[rustfmt::skip] // Keep public re-exports separate.
|
||||
|
@ -312,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::*;
|
||||
|
@ -325,7 +343,10 @@ 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")]
|
||||
|
|
|
@ -203,6 +203,7 @@ macro_rules! hash_newtype {
|
|||
/// * `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),*) => {
|
||||
$(
|
||||
|
@ -211,6 +212,18 @@ macro_rules! impl_hex_for_newtype {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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:
|
||||
|
@ -274,6 +287,7 @@ macro_rules! impl_bytelike_traits {
|
|||
/// [`hex-conservative`]: <https://crates.io/crates/hex-conservative>
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[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),*> {
|
||||
|
@ -299,6 +313,20 @@ macro_rules! impl_hex_string_traits {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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 fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
|
||||
$crate::debug_hex(self.as_byte_array(), f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generates the struct only (no impls)
|
||||
//
|
||||
// This is a separate macro to make it more readable and have a separate interface that allows for
|
||||
|
@ -542,14 +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;
|
||||
|
||||
|
@ -560,6 +603,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg(feature = "hex")]
|
||||
fn display_alternate() {
|
||||
use alloc::format;
|
||||
|
||||
|
@ -570,6 +614,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg(feature = "hex")]
|
||||
fn lower_hex() {
|
||||
use alloc::format;
|
||||
|
||||
|
@ -580,6 +625,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg(feature = "hex")]
|
||||
fn lower_hex_alternate() {
|
||||
use alloc::format;
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -321,10 +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;
|
||||
|
||||
|
@ -345,10 +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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 }
|
||||
|
|
Loading…
Reference in New Issue