diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 7e6c3026..c81b5361 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -8,6 +8,12 @@ version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "base58check" version = "0.1.0" @@ -159,9 +165,12 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 196e597d..2b0e4072 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -8,6 +8,12 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "base58check" version = "0.1.0" @@ -158,9 +164,12 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" diff --git a/base58/Cargo.toml b/base58/Cargo.toml index 7c294a5f..fb312dd3 100644 --- a/base58/Cargo.toml +++ b/base58/Cargo.toml @@ -25,4 +25,4 @@ hashes = { package = "bitcoin_hashes", version = "0.13.0", default-features = fa internals = { package = "bitcoin-internals", version = "0.2.0" } [dev-dependencies] -hex = { package = "hex-conservative", version = "0.1.1", default-features = false, features = ["alloc"] } +hex = { package = "hex-conservative", version = "0.2.0", default-features = false, features = ["alloc"] } diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index ffc02bb1..8a46cb1b 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -31,7 +31,7 @@ rustdoc-args = ["--cfg", "docsrs"] base58 = { package = "base58check", version = "0.1.0", default-features = false } bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] } hashes = { package = "bitcoin_hashes", version = "0.13.0", default-features = false, features = ["alloc", "io"] } -hex = { package = "hex-conservative", version = "0.1.1", default-features = false, features = ["alloc"] } +hex = { package = "hex-conservative", version = "0.2.0", default-features = false, features = ["alloc"] } hex_lit = "0.1.1" internals = { package = "bitcoin-internals", version = "0.2.0" } io = { package = "bitcoin-io", version = "0.1.1", default-features = false, features = ["alloc"] } diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs index 2974de43..d48d3b38 100644 --- a/bitcoin/src/blockdata/witness.rs +++ b/bitcoin/src/blockdata/witness.rs @@ -506,18 +506,19 @@ impl<'de> serde::Deserialize<'de> for Witness { while let Some(elem) = a.next_element::()? { let vec = Vec::::from_hex(&elem).map_err(|e| match e { - InvalidChar(b) => match core::char::from_u32(b.into()) { + InvalidChar(ref e) => match core::char::from_u32(e.invalid_char( + ).into()) { Some(c) => de::Error::invalid_value( Unexpected::Char(c), &"a valid hex character", ), None => de::Error::invalid_value( - Unexpected::Unsigned(b.into()), + Unexpected::Unsigned(e.invalid_char().into()), &"a valid hex character", ), }, - OddLengthString(len) => - de::Error::invalid_length(len, &"an even length string"), + OddLengthString(ref e) => + de::Error::invalid_length(e.length(), &"an even length string"), })?; ret.push(vec); } diff --git a/bitcoin/src/consensus/serde.rs b/bitcoin/src/consensus/serde.rs index eb5acfd4..5a096e6c 100644 --- a/bitcoin/src/consensus/serde.rs +++ b/bitcoin/src/consensus/serde.rs @@ -71,11 +71,11 @@ pub mod hex { /// Hex byte encoder. // We wrap `BufEncoder` to not leak internal representation. - pub struct Encoder(BufEncoder<[u8; HEX_BUF_SIZE]>, PhantomData); + pub struct Encoder(BufEncoder<{ HEX_BUF_SIZE }>, PhantomData); impl From> for Encoder { fn from(_: super::Hex) -> Self { - Encoder(BufEncoder::new([0; HEX_BUF_SIZE]), Default::default()) + Encoder(BufEncoder::new(), Default::default()) } } @@ -100,15 +100,15 @@ pub mod hex { // Newtypes to hide internal details. /// Error returned when a hex string decoder can't be created. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub struct DecodeInitError(hex::HexToBytesError); + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct DecodeInitError(hex::OddLengthStringError); /// Error returned when a hex string contains invalid characters. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub struct DecodeError(hex::HexToBytesError); + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct DecodeError(hex::InvalidCharError); /// Hex decoder state. - pub struct Decoder<'a>(hex::HexToBytesIter<'a>); + pub struct Decoder<'a>(hex::HexSliceToBytesIter<'a>); impl<'a> Decoder<'a> { fn new(s: &'a str) -> Result { @@ -137,29 +137,19 @@ pub mod hex { impl super::IntoDeError for DecodeInitError { fn into_de_error(self) -> E { - use hex::HexToBytesError; - - match self.0 { - HexToBytesError::OddLengthString(len) => - E::invalid_length(len, &"an even number of ASCII-encoded hex digits"), - error => panic!("unexpected error: {:?}", error), - } + E::invalid_length(self.0.length(), &"an even number of ASCII-encoded hex digits") } } impl super::IntoDeError for DecodeError { fn into_de_error(self) -> E { - use hex::HexToBytesError; use serde::de::Unexpected; const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit"; - match self.0 { - HexToBytesError::InvalidChar(c) if c.is_ascii() => - E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR), - HexToBytesError::InvalidChar(c) => - E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR), - error => panic!("unexpected error: {:?}", error), + match self.0.invalid_char() { + c if c.is_ascii() => E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR), + c => E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR), } } } diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index 48ac319c..e3babd05 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -10,7 +10,7 @@ use core::ops; use core::str::FromStr; use hashes::{hash160, Hash}; -use hex::{FromHex, HexToArrayError, HexToBytesError}; +use hex::{FromHex, HexToArrayError}; use internals::array_vec::ArrayVec; use internals::write_err; use io::{Read, Write}; @@ -233,22 +233,22 @@ impl fmt::Display for PublicKey { impl FromStr for PublicKey { type Err = ParsePublicKeyError; fn from_str(s: &str) -> Result { + use HexToArrayError::*; + match s.len() { 66 => { - PublicKey::from_slice(&<[u8; 33]>::from_hex(s).map_err(|op| { - match op { - HexToArrayError::Conversion(HexToBytesError::InvalidChar(char)) => ParsePublicKeyError::InvalidChar(char), - HexToArrayError::Conversion(HexToBytesError::OddLengthString(_)) | HexToArrayError::InvalidLength(_,_) => unreachable!("invalid length"), - } - })?).map_err(From::from) + let bytes = <[u8; 33]>::from_hex(s).map_err(|e| match e { + InvalidChar(e) => ParsePublicKeyError::InvalidChar(e.invalid_char()), + InvalidLength(_) => unreachable!("length checked already") + })?; + Ok(PublicKey::from_slice(&bytes).expect("length checked already")) }, 130 => { - PublicKey::from_slice(&<[u8; 65]>::from_hex(s).map_err(|op| { - match op { - HexToArrayError::Conversion(HexToBytesError::InvalidChar(char)) => ParsePublicKeyError::InvalidChar(char), - HexToArrayError::Conversion(HexToBytesError::OddLengthString(_)) | HexToArrayError::InvalidLength(_,_) => unreachable!("invalid length"), - } - })?).map_err(From::from) + let bytes = <[u8; 65]>::from_hex(s).map_err(|e| match e { + InvalidChar(e) => ParsePublicKeyError::InvalidChar(e.invalid_char()), + InvalidLength(_) => unreachable!("length checked already") + })?; + Ok(PublicKey::from_slice(&bytes).expect("length checked already")) } len => Err(ParsePublicKeyError::InvalidHexLength(len)), } diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index d14e186a..4eac052d 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1035,7 +1035,7 @@ mod tests { #[track_caller] pub fn hex_psbt(s: &str) -> Result { - let r: Result, hex::HexToBytesError> = Vec::from_hex(s); + let r = Vec::from_hex(s); match r { Err(_e) => panic!("unable to parse hex string {}", s), Ok(v) => Psbt::deserialize(&v), diff --git a/bitcoin/src/taproot/serialized_signature.rs b/bitcoin/src/taproot/serialized_signature.rs index 337ced5f..4def2e57 100644 --- a/bitcoin/src/taproot/serialized_signature.rs +++ b/bitcoin/src/taproot/serialized_signature.rs @@ -28,10 +28,7 @@ impl fmt::Debug for SerializedSignature { impl fmt::Display for SerializedSignature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut buf = [0u8; MAX_LEN * 2]; - let mut encoder = hex::buf_encoder::BufEncoder::new(&mut buf); - encoder.put_bytes(self, hex::Case::Lower); - f.pad_integral(true, "0x", encoder.as_str()) + hex::fmt_hex_exact!(f, MAX_LEN, self, hex::Case::Lower) } } diff --git a/hashes/Cargo.toml b/hashes/Cargo.toml index 70a6758e..14368252 100644 --- a/hashes/Cargo.toml +++ b/hashes/Cargo.toml @@ -27,7 +27,7 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -hex = { package = "hex-conservative", version = "0.1.1", default-features = false } +hex = { package = "hex-conservative", version = "0.2.0", default-features = false } bitcoin-io = { version = "0.1.1", default-features = false, optional = true } schemars = { version = "0.8.3", default-features = false, optional = true } diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 5534f697..9b3f9dde 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -89,15 +89,13 @@ macro_rules! hash_trait_impls { impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> { type Err = $crate::hex::HexToArrayError; fn from_str(s: &str) -> $crate::_export::_core::result::Result { - use $crate::hex::{FromHex, HexToBytesIter}; - use $crate::Hash; + use $crate::{Hash, hex::{FromHex}}; - let inner: [u8; $bits / 8] = if $reverse { - FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())? - } else { - FromHex::from_byte_iter(HexToBytesIter::new(s)?)? - }; - Ok(Self::from_byte_array(inner)) + let mut bytes = <[u8; $bits / 8]>::from_hex(s)?; + if $reverse { + bytes.reverse(); + } + Ok(Self::from_byte_array(bytes)) } } diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 8405232e..628809ea 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -176,15 +176,13 @@ impl Midstate { } impl hex::FromHex for Midstate { - type Err = hex::HexToArrayError; - fn from_byte_iter(iter: I) -> Result - where - I: Iterator> - + ExactSizeIterator - + DoubleEndedIterator, - { + type Error = hex::HexToArrayError; + + fn from_hex(s: &str) -> Result { // DISPLAY_BACKWARD is true - Ok(Midstate::from_byte_array(hex::FromHex::from_byte_iter(iter.rev())?)) + let mut bytes = <[u8; 32]>::from_hex(s)?; + bytes.reverse(); + Ok(Midstate(bytes)) } } diff --git a/hashes/src/util.rs b/hashes/src/util.rs index fcb1b173..c84b928a 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -270,15 +270,13 @@ macro_rules! hash_newtype { impl $crate::_export::_core::str::FromStr for $newtype { type Err = $crate::hex::HexToArrayError; fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> { - use $crate::hex::{FromHex, HexToBytesIter}; - use $crate::Hash; + use $crate::{Hash, hex::FromHex}; - let inner: <$hash as Hash>::Bytes = if ::DISPLAY_BACKWARD { - FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())? - } else { - FromHex::from_byte_iter(HexToBytesIter::new(s)?)? + let mut bytes = <[u8; ::LEN]>::from_hex(s)?; + if ::DISPLAY_BACKWARD { + bytes.reverse(); }; - Ok($newtype(<$hash>::from_byte_array(inner))) + Ok($newtype(<$hash>::from_byte_array(bytes))) } }