Merge rust-bitcoin/rust-bitcoin#1833: Use new `hex-conservative` crate
bb8bd16302
internals: Remove hex module (Tobin C. Harding)2268b44911
Depend on hex-conservative (Tobin C. Harding)db50509cd3
Add usage docs to the "core2" feature (Tobin C. Harding) Pull request description: Use the newly released `hex-conservative` crate, by doing the following: - Depend on `hex-conservative` in `bitcoin` and `hashes` - Re-export `hex-conservative` as `hex` from both crate roots. - Remove all the old hex code from `hashes` - Remove all the old hex code from `internals` - Remove the now unused `internals::prelude` - Fix all the import statements (makes up the bulk of the lines changes in this patch) ACKs for top commit: apoelstra: ACKbb8bd16302
sanket1729: utACKbb8bd16302
Tree-SHA512: ec83b3941cae6f32272471779f28461bb04959a3f6a126a68bbf2c748d83ff9518ff8932d9e937a6f389c10028bf3eb58c6b6d71ea066924dd7a34faaec7a087
This commit is contained in:
commit
04976eddcf
|
@ -41,6 +41,7 @@ dependencies = [
|
||||||
"bitcoin_hashes",
|
"bitcoin_hashes",
|
||||||
"bitcoinconsensus",
|
"bitcoinconsensus",
|
||||||
"core2",
|
"core2",
|
||||||
|
"hex-conservative",
|
||||||
"hex_lit",
|
"hex_lit",
|
||||||
"mutagen",
|
"mutagen",
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
|
@ -74,6 +75,7 @@ version = "0.12.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcoin-internals",
|
"bitcoin-internals",
|
||||||
"core2",
|
"core2",
|
||||||
|
"hex-conservative",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -163,6 +165,15 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex-conservative"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2"
|
||||||
|
dependencies = [
|
||||||
|
"core2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex_lit"
|
name = "hex_lit"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
|
@ -40,6 +40,7 @@ dependencies = [
|
||||||
"bitcoin_hashes",
|
"bitcoin_hashes",
|
||||||
"bitcoinconsensus",
|
"bitcoinconsensus",
|
||||||
"core2",
|
"core2",
|
||||||
|
"hex-conservative",
|
||||||
"hex_lit",
|
"hex_lit",
|
||||||
"mutagen",
|
"mutagen",
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
|
@ -73,6 +74,7 @@ version = "0.12.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcoin-internals",
|
"bitcoin-internals",
|
||||||
"core2",
|
"core2",
|
||||||
|
"hex-conservative",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -156,6 +158,15 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex-conservative"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2"
|
||||||
|
dependencies = [
|
||||||
|
"core2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex_lit"
|
name = "hex_lit"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
|
@ -26,8 +26,8 @@ bitcoinconsensus-std = ["bitcoinconsensus/std", "std"]
|
||||||
# The no-std feature doesn't disable std - you need to turn off the std feature for that by disabling default.
|
# The no-std feature doesn't disable std - you need to turn off the std feature for that by disabling default.
|
||||||
# Instead no-std enables additional features required for this crate to be usable without std.
|
# Instead no-std enables additional features required for this crate to be usable without std.
|
||||||
# As a result, both can be enabled without conflict.
|
# As a result, both can be enabled without conflict.
|
||||||
std = ["secp256k1/std", "hashes/std", "bech32/std", "internals/std"]
|
std = ["secp256k1/std", "hashes/std", "bech32/std", "internals/std", "hex/std"]
|
||||||
no-std = ["core2", "hashes/alloc", "hashes/core2", "secp256k1/alloc"]
|
no-std = ["core2", "hashes/alloc", "hashes/core2", "secp256k1/alloc", "hex/alloc", "hex/core2"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
@ -35,6 +35,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
internals = { package = "bitcoin-internals", version = "0.2.0" }
|
internals = { package = "bitcoin-internals", version = "0.2.0" }
|
||||||
|
hex = { package = "hex-conservative", version = "0.1.1", default-features = false }
|
||||||
bech32 = { version = "0.9.0", default-features = false }
|
bech32 = { version = "0.9.0", default-features = false }
|
||||||
hashes = { package = "bitcoin_hashes", version = "0.12.0", default-features = false }
|
hashes = { package = "bitcoin_hashes", version = "0.12.0", default-features = false }
|
||||||
secp256k1 = { version = "0.27.0", default-features = false, features = ["bitcoin_hashes"] }
|
secp256k1 = { version = "0.27.0", default-features = false, features = ["bitcoin_hashes"] }
|
||||||
|
@ -43,6 +44,8 @@ hex_lit = "0.1.1"
|
||||||
base64 = { version = "0.13.0", optional = true }
|
base64 = { version = "0.13.0", optional = true }
|
||||||
# Only use this feature for no-std builds, otherwise use bitcoinconsensus-std.
|
# Only use this feature for no-std builds, otherwise use bitcoinconsensus-std.
|
||||||
bitcoinconsensus = { version = "0.20.2-0.5.0", default-features = false, optional = true }
|
bitcoinconsensus = { version = "0.20.2-0.5.0", default-features = false, optional = true }
|
||||||
|
|
||||||
|
# There is no reason to use this dependency directly, it is activated by the "no-std" feature.
|
||||||
core2 = { version = "0.3.2", default-features = false, features = ["alloc"], optional = true }
|
core2 = { version = "0.3.2", default-features = false, features = ["alloc"], optional = true }
|
||||||
# Do NOT use this as a feature! Use the `serde` feature instead.
|
# Do NOT use this as a feature! Use the `serde` feature instead.
|
||||||
actual-serde = { package = "serde", version = "1.0.103", default-features = false, features = [ "derive", "alloc" ], optional = true }
|
actual-serde = { package = "serde", version = "1.0.103", default-features = false, features = [ "derive", "alloc" ], optional = true }
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{env, process};
|
||||||
|
|
||||||
use bitcoin::address::Address;
|
use bitcoin::address::Address;
|
||||||
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
|
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
|
||||||
use bitcoin::hashes::hex::FromHex;
|
use bitcoin::hex::FromHex;
|
||||||
use bitcoin::secp256k1::ffi::types::AlignedType;
|
use bitcoin::secp256k1::ffi::types::AlignedType;
|
||||||
use bitcoin::secp256k1::Secp256k1;
|
use bitcoin::secp256k1::Secp256k1;
|
||||||
use bitcoin::PublicKey;
|
use bitcoin::PublicKey;
|
||||||
|
|
|
@ -371,7 +371,7 @@ impl BlockTransactions {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::blockdata::locktime::absolute;
|
use crate::blockdata::locktime::absolute;
|
||||||
|
|
|
@ -12,7 +12,7 @@ use core::ops::Index;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use core::{fmt, slice};
|
use core::{fmt, slice};
|
||||||
|
|
||||||
use hashes::{hex, sha512, Hash, HashEngine, Hmac, HmacEngine};
|
use hashes::{sha512, Hash, HashEngine, Hmac, HmacEngine};
|
||||||
use internals::{impl_array_newtype, write_err};
|
use internals::{impl_array_newtype, write_err};
|
||||||
use secp256k1::{self, Secp256k1, XOnlyPublicKey};
|
use secp256k1::{self, Secp256k1, XOnlyPublicKey};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -468,7 +468,7 @@ pub enum Error {
|
||||||
/// Base58 encoding error
|
/// Base58 encoding error
|
||||||
Base58(base58::Error),
|
Base58(base58::Error),
|
||||||
/// Hexadecimal decoding error
|
/// Hexadecimal decoding error
|
||||||
Hex(hex::Error),
|
Hex(hex::HexToArrayError),
|
||||||
/// `PublicKey` hex should be 66 or 130 digits long.
|
/// `PublicKey` hex should be 66 or 130 digits long.
|
||||||
InvalidPublicKeyHexLength(usize),
|
InvalidPublicKeyHexLength(usize),
|
||||||
}
|
}
|
||||||
|
|
|
@ -423,7 +423,7 @@ impl std::error::Error for ValidationError {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::consensus::encode::{deserialize, serialize};
|
use crate::consensus::encode::{deserialize, serialize};
|
||||||
|
|
|
@ -513,7 +513,7 @@ impl<'de> serde::Deserialize<'de> for ScriptBuf {
|
||||||
{
|
{
|
||||||
use core::fmt::Formatter;
|
use core::fmt::Formatter;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
if deserializer.is_human_readable() {
|
if deserializer.is_human_readable() {
|
||||||
struct Visitor;
|
struct Visitor;
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
use hashes::hex;
|
|
||||||
use secp256k1::{Secp256k1, Verification};
|
use secp256k1::{Secp256k1, Verification};
|
||||||
|
|
||||||
use crate::blockdata::opcodes::all::*;
|
use crate::blockdata::opcodes::all::*;
|
||||||
|
@ -156,8 +155,8 @@ impl ScriptBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`ScriptBuf`] from a hex string.
|
/// Creates a [`ScriptBuf`] from a hex string.
|
||||||
pub fn from_hex(s: &str) -> Result<Self, hex::Error> {
|
pub fn from_hex(s: &str) -> Result<Self, hex::HexToBytesError> {
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
let v = Vec::from_hex(s)?;
|
let v = Vec::from_hex(s)?;
|
||||||
Ok(ScriptBuf::from_bytes(v))
|
Ok(ScriptBuf::from_bytes(v))
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl fmt::Display for OutPoint {
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ParseOutPointError {
|
pub enum ParseOutPointError {
|
||||||
/// Error in TXID part.
|
/// Error in TXID part.
|
||||||
Txid(hashes::hex::Error),
|
Txid(hex::HexToArrayError),
|
||||||
/// Error in vout part.
|
/// Error in vout part.
|
||||||
Vout(crate::error::ParseIntError),
|
Vout(crate::error::ParseIntError),
|
||||||
/// Error in general format.
|
/// Error in general format.
|
||||||
|
@ -1390,7 +1390,7 @@ impl InputWeightPrediction {
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::blockdata::constants::WITNESS_SCALE_FACTOR;
|
use crate::blockdata::constants::WITNESS_SCALE_FACTOR;
|
||||||
|
|
|
@ -462,8 +462,8 @@ impl<'de> serde::Deserialize<'de> for Witness {
|
||||||
self,
|
self,
|
||||||
mut a: A,
|
mut a: A,
|
||||||
) -> Result<Self::Value, A::Error> {
|
) -> Result<Self::Value, A::Error> {
|
||||||
use hashes::hex::Error::*;
|
use hex::FromHex;
|
||||||
use hashes::hex::FromHex;
|
use hex::HexToBytesError::*;
|
||||||
use serde::de::{self, Unexpected};
|
use serde::de::{self, Unexpected};
|
||||||
|
|
||||||
let mut ret = match a.size_hint() {
|
let mut ret = match a.size_hint() {
|
||||||
|
@ -485,10 +485,6 @@ impl<'de> serde::Deserialize<'de> for Witness {
|
||||||
},
|
},
|
||||||
OddLengthString(len) =>
|
OddLengthString(len) =>
|
||||||
de::Error::invalid_length(len, &"an even length string"),
|
de::Error::invalid_length(len, &"an even length string"),
|
||||||
InvalidLength(expected, got) => {
|
|
||||||
let exp = format!("expected length: {}", expected);
|
|
||||||
de::Error::invalid_length(got, &exp.as_str())
|
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
ret.push(vec);
|
ret.push(vec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub mod hex {
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use internals::hex::BufEncoder;
|
use hex::buf_encoder::BufEncoder;
|
||||||
|
|
||||||
/// Marker for upper/lower case type-level flags ("type-level enum").
|
/// Marker for upper/lower case type-level flags ("type-level enum").
|
||||||
///
|
///
|
||||||
|
@ -54,15 +54,15 @@ pub mod hex {
|
||||||
mod sealed {
|
mod sealed {
|
||||||
pub trait Case {
|
pub trait Case {
|
||||||
/// Internal detail, don't depend on it!!!
|
/// Internal detail, don't depend on it!!!
|
||||||
const INTERNAL_CASE: internals::hex::Case;
|
const INTERNAL_CASE: hex::Case;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Case for super::Lower {
|
impl Case for super::Lower {
|
||||||
const INTERNAL_CASE: internals::hex::Case = internals::hex::Case::Lower;
|
const INTERNAL_CASE: hex::Case = hex::Case::Lower;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Case for super::Upper {
|
impl Case for super::Upper {
|
||||||
const INTERNAL_CASE: internals::hex::Case = internals::hex::Case::Upper;
|
const INTERNAL_CASE: hex::Case = hex::Case::Upper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,18 +102,18 @@ pub mod hex {
|
||||||
|
|
||||||
/// Error returned when a hex string decoder can't be created.
|
/// Error returned when a hex string decoder can't be created.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DecodeInitError(hashes::hex::Error);
|
pub struct DecodeInitError(hex::HexToBytesError);
|
||||||
|
|
||||||
/// Error returned when a hex string contains invalid characters.
|
/// Error returned when a hex string contains invalid characters.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DecodeError(hashes::hex::Error);
|
pub struct DecodeError(hex::HexToBytesError);
|
||||||
|
|
||||||
/// Hex decoder state.
|
/// Hex decoder state.
|
||||||
pub struct Decoder<'a>(hashes::hex::HexIterator<'a>);
|
pub struct Decoder<'a>(hex::HexToBytesIter<'a>);
|
||||||
|
|
||||||
impl<'a> Decoder<'a> {
|
impl<'a> Decoder<'a> {
|
||||||
fn new(s: &'a str) -> Result<Self, DecodeInitError> {
|
fn new(s: &'a str) -> Result<Self, DecodeInitError> {
|
||||||
match hashes::hex::HexIterator::new(s) {
|
match hex::HexToBytesIter::new(s) {
|
||||||
Ok(iter) => Ok(Decoder(iter)),
|
Ok(iter) => Ok(Decoder(iter)),
|
||||||
Err(error) => Err(DecodeInitError(error)),
|
Err(error) => Err(DecodeInitError(error)),
|
||||||
}
|
}
|
||||||
|
@ -138,10 +138,10 @@ pub mod hex {
|
||||||
|
|
||||||
impl super::IntoDeError for DecodeInitError {
|
impl super::IntoDeError for DecodeInitError {
|
||||||
fn into_de_error<E: serde::de::Error>(self) -> E {
|
fn into_de_error<E: serde::de::Error>(self) -> E {
|
||||||
use hashes::hex::Error;
|
use hex::HexToBytesError;
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Error::OddLengthString(len) =>
|
HexToBytesError::OddLengthString(len) =>
|
||||||
E::invalid_length(len, &"an even number of ASCII-encoded hex digits"),
|
E::invalid_length(len, &"an even number of ASCII-encoded hex digits"),
|
||||||
error => panic!("unexpected error: {:?}", error),
|
error => panic!("unexpected error: {:?}", error),
|
||||||
}
|
}
|
||||||
|
@ -150,15 +150,15 @@ pub mod hex {
|
||||||
|
|
||||||
impl super::IntoDeError for DecodeError {
|
impl super::IntoDeError for DecodeError {
|
||||||
fn into_de_error<E: serde::de::Error>(self) -> E {
|
fn into_de_error<E: serde::de::Error>(self) -> E {
|
||||||
use hashes::hex::Error;
|
use hex::HexToBytesError;
|
||||||
use serde::de::Unexpected;
|
use serde::de::Unexpected;
|
||||||
|
|
||||||
const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit";
|
const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit";
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Error::InvalidChar(c) if c.is_ascii() =>
|
HexToBytesError::InvalidChar(c) if c.is_ascii() =>
|
||||||
E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR),
|
E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR),
|
||||||
Error::InvalidChar(c) =>
|
HexToBytesError::InvalidChar(c) =>
|
||||||
E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR),
|
E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR),
|
||||||
error => panic!("unexpected error: {:?}", error),
|
error => panic!("unexpected error: {:?}", error),
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use core::{fmt, iter};
|
use core::{fmt, iter};
|
||||||
|
|
||||||
use hashes::hex::{self, FromHex};
|
use hex::FromHex;
|
||||||
use internals::hex::display::DisplayHex;
|
|
||||||
use internals::write_err;
|
use internals::write_err;
|
||||||
use secp256k1;
|
use secp256k1;
|
||||||
|
|
||||||
|
@ -188,8 +187,8 @@ impl<'a> IntoIterator for &'a SerializedSignature {
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Hex encoding error
|
/// Hex decoding error
|
||||||
HexEncoding(hex::Error),
|
Hex(hex::HexToBytesError),
|
||||||
/// Base58 encoding error
|
/// Base58 encoding error
|
||||||
NonStandardSighashType(u32),
|
NonStandardSighashType(u32),
|
||||||
/// Empty Signature
|
/// Empty Signature
|
||||||
|
@ -201,7 +200,7 @@ pub enum Error {
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::HexEncoding(ref e) => write_err!(f, "Signature hex encoding error"; e),
|
Error::Hex(ref e) => write_err!(f, "Signature hex decoding error"; e),
|
||||||
Error::NonStandardSighashType(hash_ty) =>
|
Error::NonStandardSighashType(hash_ty) =>
|
||||||
write!(f, "Non standard signature hash type {}", hash_ty),
|
write!(f, "Non standard signature hash type {}", hash_ty),
|
||||||
Error::EmptySignature => write!(f, "Empty ECDSA signature"),
|
Error::EmptySignature => write!(f, "Empty ECDSA signature"),
|
||||||
|
@ -216,7 +215,7 @@ impl std::error::Error for Error {
|
||||||
use self::Error::*;
|
use self::Error::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
HexEncoding(e) => Some(e),
|
Hex(e) => Some(e),
|
||||||
Secp256k1(e) => Some(e),
|
Secp256k1(e) => Some(e),
|
||||||
NonStandardSighashType(_) | EmptySignature => None,
|
NonStandardSighashType(_) | EmptySignature => None,
|
||||||
}
|
}
|
||||||
|
@ -231,6 +230,6 @@ impl From<NonStandardSighashType> for Error {
|
||||||
fn from(err: NonStandardSighashType) -> Self { Error::NonStandardSighashType(err.0) }
|
fn from(err: NonStandardSighashType) -> Self { Error::NonStandardSighashType(err.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<hex::Error> for Error {
|
impl From<hex::HexToBytesError> for Error {
|
||||||
fn from(err: hex::Error) -> Self { Error::HexEncoding(err) }
|
fn from(err: hex::HexToBytesError) -> Self { Error::Hex(err) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ use core::fmt::{self, Write};
|
||||||
use core::ops;
|
use core::ops;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hashes::{hash160, Hash};
|
||||||
use hashes::{hash160, hex, Hash};
|
use hex::FromHex;
|
||||||
use internals::write_err;
|
use internals::write_err;
|
||||||
#[cfg(feature = "rand-std")]
|
#[cfg(feature = "rand-std")]
|
||||||
pub use secp256k1::rand;
|
pub use secp256k1::rand;
|
||||||
|
@ -34,7 +34,7 @@ pub enum Error {
|
||||||
/// Invalid key prefix error
|
/// Invalid key prefix error
|
||||||
InvalidKeyPrefix(u8),
|
InvalidKeyPrefix(u8),
|
||||||
/// Hex decoding error
|
/// Hex decoding error
|
||||||
Hex(hex::Error),
|
Hex(hex::HexToArrayError),
|
||||||
/// `PublicKey` hex should be 66 or 130 digits long.
|
/// `PublicKey` hex should be 66 or 130 digits long.
|
||||||
InvalidHexLength(usize),
|
InvalidHexLength(usize),
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,8 @@ impl From<secp256k1::Error> for Error {
|
||||||
fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) }
|
fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<hex::Error> for Error {
|
impl From<hex::HexToArrayError> for Error {
|
||||||
fn from(e: hex::Error) -> Self { Error::Hex(e) }
|
fn from(e: hex::HexToArrayError) -> Self { Error::Hex(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Bitcoin ECDSA public key
|
/// A Bitcoin ECDSA public key
|
||||||
|
@ -735,7 +735,7 @@ impl From<TweakedKeyPair> for TweakedPublicKey {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
use secp256k1::Secp256k1;
|
use secp256k1::Secp256k1;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1110,8 +1110,8 @@ fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, output_len
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
|
||||||
use hashes::HashEngine;
|
use hashes::HashEngine;
|
||||||
|
use hex::FromHex;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::address::Address;
|
use crate::address::Address;
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub(crate) use test_macros::*;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_macros {
|
mod test_macros {
|
||||||
|
|
||||||
macro_rules! hex (($hex:expr) => (<Vec<u8> as hashes::hex::FromHex>::from_hex($hex).unwrap()));
|
macro_rules! hex (($hex:expr) => (<Vec<u8> as $crate::hex::FromHex>::from_hex($hex).unwrap()));
|
||||||
pub(crate) use hex;
|
pub(crate) use hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ mod test_macros {
|
||||||
/// - core::fmt::UpperHex
|
/// - core::fmt::UpperHex
|
||||||
/// - core::fmt::Display
|
/// - core::fmt::Display
|
||||||
/// - core::str::FromStr
|
/// - core::str::FromStr
|
||||||
/// - hashes::hex::FromHex
|
/// - hex::FromHex
|
||||||
macro_rules! impl_bytes_newtype {
|
macro_rules! impl_bytes_newtype {
|
||||||
($t:ident, $len:literal) => {
|
($t:ident, $len:literal) => {
|
||||||
impl $t {
|
impl $t {
|
||||||
|
@ -83,14 +83,14 @@ macro_rules! impl_bytes_newtype {
|
||||||
|
|
||||||
impl core::fmt::LowerHex for $t {
|
impl core::fmt::LowerHex for $t {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
use internals::hex::{display, Case};
|
use $crate::hex::{display, Case};
|
||||||
display::fmt_hex_exact!(f, $len, &self.0, Case::Lower)
|
display::fmt_hex_exact!(f, $len, &self.0, Case::Lower)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::UpperHex for $t {
|
impl core::fmt::UpperHex for $t {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
use internals::hex::{display, Case};
|
use $crate::hex::{display, Case};
|
||||||
display::fmt_hex_exact!(f, $len, &self.0, Case::Upper)
|
display::fmt_hex_exact!(f, $len, &self.0, Case::Upper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,30 +107,22 @@ macro_rules! impl_bytes_newtype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::hashes::hex::FromHex for $t {
|
impl $crate::hex::FromHex for $t {
|
||||||
fn from_byte_iter<I>(iter: I) -> Result<Self, $crate::hashes::hex::Error>
|
type Err = $crate::hex::HexToArrayError;
|
||||||
|
|
||||||
|
fn from_byte_iter<I>(iter: I) -> Result<Self, $crate::hex::HexToArrayError>
|
||||||
where
|
where
|
||||||
I: core::iter::Iterator<Item = Result<u8, $crate::hashes::hex::Error>>
|
I: core::iter::Iterator<Item = Result<u8, $crate::hex::HexToBytesError>>
|
||||||
+ core::iter::ExactSizeIterator
|
+ core::iter::ExactSizeIterator
|
||||||
+ core::iter::DoubleEndedIterator,
|
+ core::iter::DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
if iter.len() == $len {
|
Ok($t($crate::hex::FromHex::from_byte_iter(iter)?))
|
||||||
let mut ret = [0; $len];
|
|
||||||
for (n, byte) in iter.enumerate() {
|
|
||||||
ret[n] = byte?;
|
|
||||||
}
|
|
||||||
Ok($t(ret))
|
|
||||||
} else {
|
|
||||||
Err($crate::hashes::hex::Error::InvalidLength(2 * $len, 2 * iter.len()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::str::FromStr for $t {
|
impl core::str::FromStr for $t {
|
||||||
type Err = $crate::hashes::hex::Error;
|
type Err = $crate::hex::HexToArrayError;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> { $crate::hex::FromHex::from_hex(s) }
|
||||||
$crate::hashes::hex::FromHex::from_hex(s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -164,7 +156,7 @@ macro_rules! impl_bytes_newtype {
|
||||||
use $crate::serde::de::Unexpected;
|
use $crate::serde::de::Unexpected;
|
||||||
|
|
||||||
if let Ok(hex) = core::str::from_utf8(v) {
|
if let Ok(hex) = core::str::from_utf8(v) {
|
||||||
$crate::hashes::hex::FromHex::from_hex(hex).map_err(E::custom)
|
$crate::hex::FromHex::from_hex(hex).map_err(E::custom)
|
||||||
} else {
|
} else {
|
||||||
return Err(E::invalid_value(Unexpected::Bytes(v), &self));
|
return Err(E::invalid_value(Unexpected::Bytes(v), &self));
|
||||||
}
|
}
|
||||||
|
@ -174,7 +166,7 @@ macro_rules! impl_bytes_newtype {
|
||||||
where
|
where
|
||||||
E: $crate::serde::de::Error,
|
E: $crate::serde::de::Error,
|
||||||
{
|
{
|
||||||
$crate::hashes::hex::FromHex::from_hex(v).map_err(E::custom)
|
$crate::hex::FromHex::from_hex(v).map_err(E::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,15 @@ pub extern crate bech32;
|
||||||
/// Bitcoin's libbitcoinconsensus with Rust binding.
|
/// Bitcoin's libbitcoinconsensus with Rust binding.
|
||||||
pub extern crate bitcoinconsensus;
|
pub extern crate bitcoinconsensus;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
extern crate core2;
|
||||||
|
|
||||||
/// Rust implementation of cryptographic hash function algorithems.
|
/// Rust implementation of cryptographic hash function algorithems.
|
||||||
pub extern crate hashes;
|
pub extern crate hashes;
|
||||||
|
|
||||||
|
/// Re-export the `hex-conservative` crate.
|
||||||
|
pub extern crate hex;
|
||||||
|
|
||||||
/// Rust wrapper library for Pieter Wuille's libsecp256k1. Implements ECDSA and BIP 340 signatures
|
/// Rust wrapper library for Pieter Wuille's libsecp256k1. Implements ECDSA and BIP 340 signatures
|
||||||
/// for the SECG elliptic curve group secp256k1 and related utilities.
|
/// for the SECG elliptic curve group secp256k1 and related utilities.
|
||||||
pub extern crate secp256k1;
|
pub extern crate secp256k1;
|
||||||
|
@ -186,7 +192,7 @@ mod prelude {
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
pub use crate::io_extras::sink;
|
pub use crate::io_extras::sink;
|
||||||
|
|
||||||
pub use internals::hex::display::DisplayHex;
|
pub use hex::DisplayHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(bench)]
|
#[cfg(bench)]
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use bitcoin::hash_types::Txid;
|
//! use bitcoin::hash_types::Txid;
|
||||||
//! use bitcoin::hashes::hex::FromHex;
|
//! use bitcoin::hex::FromHex;
|
||||||
//! use bitcoin::{Block, MerkleBlock};
|
//! use bitcoin::{Block, MerkleBlock};
|
||||||
//!
|
//!
|
||||||
//! // Get the proof from a bitcoind by running in the terminal:
|
//! // Get the proof from a bitcoind by running in the terminal:
|
||||||
|
@ -73,7 +73,7 @@ impl MerkleBlock {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use bitcoin::hash_types::Txid;
|
/// use bitcoin::hash_types::Txid;
|
||||||
/// use bitcoin::hashes::hex::FromHex;
|
/// use bitcoin::hex::FromHex;
|
||||||
/// use bitcoin::{Block, MerkleBlock};
|
/// use bitcoin::{Block, MerkleBlock};
|
||||||
///
|
///
|
||||||
/// // Block 80000
|
/// // Block 80000
|
||||||
|
@ -223,7 +223,7 @@ impl PartialMerkleTree {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use bitcoin::hash_types::Txid;
|
/// use bitcoin::hash_types::Txid;
|
||||||
/// use bitcoin::hashes::hex::FromHex;
|
/// use bitcoin::hex::FromHex;
|
||||||
/// use bitcoin::merkle_tree::{MerkleBlock, PartialMerkleTree};
|
/// use bitcoin::merkle_tree::{MerkleBlock, PartialMerkleTree};
|
||||||
///
|
///
|
||||||
/// // Block 80000
|
/// // Block 80000
|
||||||
|
@ -751,7 +751,7 @@ mod tests {
|
||||||
/// Returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
|
/// Returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
|
||||||
/// with 9 txs.
|
/// with 9 txs.
|
||||||
fn get_block_13b8a() -> Block {
|
fn get_block_13b8a() -> Block {
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
let block_hex = include_str!("../../tests/data/block_13b8a.hex");
|
let block_hex = include_str!("../../tests/data/block_13b8a.hex");
|
||||||
deserialize(&Vec::from_hex(block_hex).unwrap()).unwrap()
|
deserialize(&Vec::from_hex(block_hex).unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,7 +306,7 @@ mod test {
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
use super::{AddrV2, AddrV2Message, Address};
|
use super::{AddrV2, AddrV2Message, Address};
|
||||||
use crate::consensus::encode::{deserialize, serialize};
|
use crate::consensus::encode::{deserialize, serialize};
|
||||||
|
|
|
@ -31,7 +31,7 @@ use core::fmt::Display;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use core::{fmt, ops};
|
use core::{fmt, ops};
|
||||||
|
|
||||||
use hashes::hex::{Error, FromHex};
|
use hex::FromHex;
|
||||||
use internals::{debug_from_display, write_err};
|
use internals::{debug_from_display, write_err};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -313,7 +313,7 @@ impl Magic {
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct ParseMagicError {
|
pub struct ParseMagicError {
|
||||||
/// The error that occurred when parsing the string.
|
/// The error that occurred when parsing the string.
|
||||||
error: Error,
|
error: hex::HexToArrayError,
|
||||||
/// The byte string that failed to parse.
|
/// The byte string that failed to parse.
|
||||||
magic: String,
|
magic: String,
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ impl TryFrom<Magic> for Network {
|
||||||
|
|
||||||
impl fmt::Display for Magic {
|
impl fmt::Display for Magic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
internals::fmt_hex_exact!(f, 4, &self.0, internals::hex::Case::Lower)?;
|
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,14 +370,14 @@ debug_from_display!(Magic);
|
||||||
|
|
||||||
impl fmt::LowerHex for Magic {
|
impl fmt::LowerHex for Magic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
internals::fmt_hex_exact!(f, 4, &self.0, internals::hex::Case::Lower)?;
|
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::UpperHex for Magic {
|
impl fmt::UpperHex for Magic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
internals::fmt_hex_exact!(f, 4, &self.0, internals::hex::Case::Upper)?;
|
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Upper)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -790,13 +790,13 @@ macro_rules! impl_hex {
|
||||||
($hex:ident, $case:expr) => {
|
($hex:ident, $case:expr) => {
|
||||||
impl $hex for U256 {
|
impl $hex for U256 {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
internals::hex::display::fmt_hex_exact!(f, 32, &self.to_be_bytes(), $case)
|
hex::fmt_hex_exact!(f, 32, &self.to_be_bytes(), $case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
impl_hex!(LowerHex, internals::hex::Case::Lower);
|
impl_hex!(LowerHex, hex::Case::Lower);
|
||||||
impl_hex!(UpperHex, internals::hex::Case::Upper);
|
impl_hex!(UpperHex, hex::Case::Upper);
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl crate::serde::Serialize for U256 {
|
impl crate::serde::Serialize for U256 {
|
||||||
|
@ -825,7 +825,7 @@ impl<'de> crate::serde::Deserialize<'de> for U256 {
|
||||||
fn deserialize<D: crate::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
fn deserialize<D: crate::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
use crate::serde::de;
|
use crate::serde::de;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
macro_rules! hex_psbt {
|
macro_rules! hex_psbt {
|
||||||
($s:expr) => {
|
($s:expr) => {
|
||||||
<$crate::psbt::Psbt>::deserialize(
|
<$crate::psbt::Psbt>::deserialize(
|
||||||
&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap(),
|
&<$crate::prelude::Vec<u8> as $crate::hex::FromHex>::from_hex($s).unwrap(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,9 +178,7 @@ impl Deserialize for ecdsa::Signature {
|
||||||
ecdsa::Error::EmptySignature => Error::InvalidEcdsaSignature(e),
|
ecdsa::Error::EmptySignature => Error::InvalidEcdsaSignature(e),
|
||||||
ecdsa::Error::NonStandardSighashType(flag) => Error::NonStandardSighashType(flag),
|
ecdsa::Error::NonStandardSighashType(flag) => Error::NonStandardSighashType(flag),
|
||||||
ecdsa::Error::Secp256k1(..) => Error::InvalidEcdsaSignature(e),
|
ecdsa::Error::Secp256k1(..) => Error::InvalidEcdsaSignature(e),
|
||||||
ecdsa::Error::HexEncoding(..) => {
|
ecdsa::Error::Hex(..) => unreachable!("Decoding from slice, not hex"),
|
||||||
unreachable!("Decoding from slice, not hex")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ impl<'a> serde::Serialize for SerializeBytesAsHex<'a> {
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
use internals::hex::display::DisplayHex;
|
use hex::DisplayHex;
|
||||||
|
|
||||||
serializer.collect_str(&format_args!("{:x}", self.0.as_hex()))
|
serializer.collect_str(&format_args!("{:x}", self.0.as_hex()))
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ pub mod btreemap_byte_values {
|
||||||
|
|
||||||
// NOTE: This module can be exactly copied to use with HashMap.
|
// NOTE: This module can be exactly copied to use with HashMap.
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
use serde;
|
use serde;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
@ -248,7 +248,7 @@ pub mod hex_bytes {
|
||||||
//! Module for serialization of byte arrays as hex strings.
|
//! Module for serialization of byte arrays as hex strings.
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hex::FromHex;
|
||||||
use serde;
|
use serde;
|
||||||
|
|
||||||
pub fn serialize<T, S>(bytes: &T, s: S) -> Result<S::Ok, S::Error>
|
pub fn serialize<T, S>(bytes: &T, s: S) -> Result<S::Ok, S::Error>
|
||||||
|
|
|
@ -1561,9 +1561,9 @@ impl std::error::Error for TaprootError {
|
||||||
mod test {
|
mod test {
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
|
||||||
use hashes::sha256t::Tag;
|
use hashes::sha256t::Tag;
|
||||||
use hashes::{sha256, Hash, HashEngine};
|
use hashes::{sha256, Hash, HashEngine};
|
||||||
|
use hex::FromHex;
|
||||||
use secp256k1::{VerifyOnly, XOnlyPublicKey};
|
use secp256k1::{VerifyOnly, XOnlyPublicKey};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use bitcoin::bip32::{ExtendedPrivKey, ExtendedPubKey, Fingerprint, IntoDerivatio
|
||||||
use bitcoin::blockdata::opcodes::OP_0;
|
use bitcoin::blockdata::opcodes::OP_0;
|
||||||
use bitcoin::blockdata::script;
|
use bitcoin::blockdata::script;
|
||||||
use bitcoin::consensus::encode::{deserialize, serialize_hex};
|
use bitcoin::consensus::encode::{deserialize, serialize_hex};
|
||||||
use bitcoin::hashes::hex::FromHex;
|
use bitcoin::hex::FromHex;
|
||||||
use bitcoin::psbt::{Psbt, PsbtSighashType};
|
use bitcoin::psbt::{Psbt, PsbtSighashType};
|
||||||
use bitcoin::script::PushBytes;
|
use bitcoin::script::PushBytes;
|
||||||
use bitcoin::secp256k1::{self, Secp256k1};
|
use bitcoin::secp256k1::{self, Secp256k1};
|
||||||
|
|
|
@ -31,8 +31,8 @@ use bitcoin::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource};
|
||||||
use bitcoin::blockdata::locktime::{absolute, relative};
|
use bitcoin::blockdata::locktime::{absolute, relative};
|
||||||
use bitcoin::blockdata::witness::Witness;
|
use bitcoin::blockdata::witness::Witness;
|
||||||
use bitcoin::consensus::encode::deserialize;
|
use bitcoin::consensus::encode::deserialize;
|
||||||
use bitcoin::hashes::hex::FromHex;
|
|
||||||
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
||||||
|
use bitcoin::hex::FromHex;
|
||||||
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
|
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
|
||||||
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
|
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
|
||||||
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
||||||
|
|
|
@ -14,9 +14,11 @@ exclude = ["tests", "contrib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["alloc", "internals/std"]
|
std = ["alloc", "internals/std", "hex/std"]
|
||||||
alloc = ["internals/alloc"]
|
alloc = ["internals/alloc", "hex/alloc"]
|
||||||
serde-std = ["serde/std"]
|
serde-std = ["serde/std"]
|
||||||
|
# If you want I/O you must enable either "std" or "core2".
|
||||||
|
core2 = ["actual-core2", "hex/core2"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
@ -24,12 +26,15 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
internals = { package = "bitcoin-internals", version = "0.2.0" }
|
internals = { package = "bitcoin-internals", version = "0.2.0" }
|
||||||
|
hex = { package = "hex-conservative", version = "0.1.1", default-features = false }
|
||||||
|
|
||||||
core2 = { version = "0.3.0", default_features = false, optional = true }
|
|
||||||
schemars = { version = "0.8.3", optional = true }
|
schemars = { version = "0.8.3", optional = true }
|
||||||
# Only enable this if you explicitly do not want to use "std", otherwise enable "serde-std".
|
# Only enable this if you explicitly do not want to use "std", otherwise enable "serde-std".
|
||||||
serde = { version = "1.0", default-features = false, optional = true }
|
serde = { version = "1.0", default-features = false, optional = true }
|
||||||
|
|
||||||
|
# Do NOT use this feature! Use the "core2" feature instead.
|
||||||
|
actual-core2 = { package = "core2", version = "0.3.2", default-features = false, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_test = "1.0"
|
serde_test = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -1,225 +0,0 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
//! Hex encoding and decoding.
|
|
||||||
//!
|
|
||||||
|
|
||||||
use core::{fmt, str};
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
#[cfg(all(feature = "core2", not(feature = "std")))]
|
|
||||||
use core2::io;
|
|
||||||
|
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
|
||||||
use crate::alloc::vec::Vec;
|
|
||||||
|
|
||||||
/// Hex decoding error.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Non-hexadecimal character.
|
|
||||||
InvalidChar(u8),
|
|
||||||
/// Purported hex string had odd length.
|
|
||||||
OddLengthString(usize),
|
|
||||||
/// Tried to parse fixed-length hash from a string with the wrong type (expected, got).
|
|
||||||
InvalidLength(usize, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Error::InvalidChar(ch) => write!(f, "invalid hex character {}", ch),
|
|
||||||
Error::OddLengthString(ell) => write!(f, "odd hex string length {}", ell),
|
|
||||||
Error::InvalidLength(ell, ell2) =>
|
|
||||||
write!(f, "bad hex string length {} (expected {})", ell2, ell),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl std::error::Error for Error {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
use self::Error::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
InvalidChar(_) | OddLengthString(_) | InvalidLength(_, _) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait for objects that can be deserialized from hex strings.
|
|
||||||
pub trait FromHex: Sized {
|
|
||||||
/// Produces an object from a byte iterator.
|
|
||||||
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator;
|
|
||||||
|
|
||||||
/// Produces an object from a hex string.
|
|
||||||
fn from_hex(s: &str) -> Result<Self, Error> { Self::from_byte_iter(HexIterator::new(s)?) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterator over a hex-encoded string slice which decodes hex and yields bytes.
|
|
||||||
pub struct HexIterator<'a> {
|
|
||||||
/// The `Bytes` iterator whose next two bytes will be decoded to yield
|
|
||||||
/// the next byte.
|
|
||||||
iter: str::Bytes<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HexIterator<'a> {
|
|
||||||
/// Constructs a new `HexIterator` from a string slice.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If the input string is of odd length.
|
|
||||||
pub fn new(s: &'a str) -> Result<HexIterator<'a>, Error> {
|
|
||||||
if s.len() % 2 != 0 {
|
|
||||||
Err(Error::OddLengthString(s.len()))
|
|
||||||
} else {
|
|
||||||
Ok(HexIterator { iter: s.bytes() })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn chars_to_hex(hi: u8, lo: u8) -> Result<u8, Error> {
|
|
||||||
let hih = (hi as char).to_digit(16).ok_or(Error::InvalidChar(hi))?;
|
|
||||||
let loh = (lo as char).to_digit(16).ok_or(Error::InvalidChar(lo))?;
|
|
||||||
|
|
||||||
let ret = (hih << 4) + loh;
|
|
||||||
Ok(ret as u8)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for HexIterator<'a> {
|
|
||||||
type Item = Result<u8, Error>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<u8, Error>> {
|
|
||||||
let hi = self.iter.next()?;
|
|
||||||
let lo = self.iter.next().unwrap();
|
|
||||||
Some(chars_to_hex(hi, lo))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
let (min, max) = self.iter.size_hint();
|
|
||||||
(min / 2, max.map(|x| x / 2))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "core2"))]
|
|
||||||
impl<'a> io::Read for HexIterator<'a> {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
let mut bytes_read = 0usize;
|
|
||||||
for dst in buf {
|
|
||||||
match self.next() {
|
|
||||||
Some(Ok(src)) => {
|
|
||||||
*dst = src;
|
|
||||||
bytes_read += 1;
|
|
||||||
}
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(bytes_read)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DoubleEndedIterator for HexIterator<'a> {
|
|
||||||
fn next_back(&mut self) -> Option<Result<u8, Error>> {
|
|
||||||
let lo = self.iter.next_back()?;
|
|
||||||
let hi = self.iter.next_back().unwrap();
|
|
||||||
Some(chars_to_hex(hi, lo))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ExactSizeIterator for HexIterator<'a> {}
|
|
||||||
|
|
||||||
#[cfg(any(test, feature = "std", feature = "alloc"))]
|
|
||||||
impl FromHex for Vec<u8> {
|
|
||||||
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator,
|
|
||||||
{
|
|
||||||
iter.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_fromhex_array {
|
|
||||||
($len:expr) => {
|
|
||||||
impl FromHex for [u8; $len] {
|
|
||||||
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator,
|
|
||||||
{
|
|
||||||
if iter.len() == $len {
|
|
||||||
let mut ret = [0; $len];
|
|
||||||
for (n, byte) in iter.enumerate() {
|
|
||||||
ret[n] = byte?;
|
|
||||||
}
|
|
||||||
Ok(ret)
|
|
||||||
} else {
|
|
||||||
Err(Error::InvalidLength(2 * $len, 2 * iter.len()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_fromhex_array!(2);
|
|
||||||
impl_fromhex_array!(4);
|
|
||||||
impl_fromhex_array!(6);
|
|
||||||
impl_fromhex_array!(8);
|
|
||||||
impl_fromhex_array!(10);
|
|
||||||
impl_fromhex_array!(12);
|
|
||||||
impl_fromhex_array!(14);
|
|
||||||
impl_fromhex_array!(16);
|
|
||||||
impl_fromhex_array!(20);
|
|
||||||
impl_fromhex_array!(24);
|
|
||||||
impl_fromhex_array!(28);
|
|
||||||
impl_fromhex_array!(32);
|
|
||||||
impl_fromhex_array!(33);
|
|
||||||
impl_fromhex_array!(64);
|
|
||||||
impl_fromhex_array!(65);
|
|
||||||
impl_fromhex_array!(128);
|
|
||||||
impl_fromhex_array!(256);
|
|
||||||
impl_fromhex_array!(384);
|
|
||||||
impl_fromhex_array!(512);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
mod tests {
|
|
||||||
use internals::hex::exts::DisplayHex;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hex_roundtrip() {
|
|
||||||
let expected = "0123456789abcdef";
|
|
||||||
let expected_up = "0123456789ABCDEF";
|
|
||||||
|
|
||||||
let parse: Vec<u8> = FromHex::from_hex(expected).expect("parse lowercase string");
|
|
||||||
assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
|
|
||||||
let ser = parse.to_lower_hex_string();
|
|
||||||
assert_eq!(ser, expected);
|
|
||||||
|
|
||||||
let parse: Vec<u8> = FromHex::from_hex(expected_up).expect("parse uppercase string");
|
|
||||||
assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
|
|
||||||
let ser = parse.to_lower_hex_string();
|
|
||||||
assert_eq!(ser, expected);
|
|
||||||
|
|
||||||
let parse: [u8; 8] = FromHex::from_hex(expected_up).expect("parse uppercase string");
|
|
||||||
assert_eq!(parse, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
|
|
||||||
let ser = parse.to_lower_hex_string();
|
|
||||||
assert_eq!(ser, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hex_error() {
|
|
||||||
let oddlen = "0123456789abcdef0";
|
|
||||||
let badchar1 = "Z123456789abcdef";
|
|
||||||
let badchar2 = "012Y456789abcdeb";
|
|
||||||
let badchar3 = "«23456789abcdef";
|
|
||||||
|
|
||||||
assert_eq!(Vec::<u8>::from_hex(oddlen), Err(Error::OddLengthString(17)));
|
|
||||||
assert_eq!(<[u8; 4]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
|
|
||||||
assert_eq!(<[u8; 8]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
|
|
||||||
assert_eq!(Vec::<u8>::from_hex(badchar1), Err(Error::InvalidChar(b'Z')));
|
|
||||||
assert_eq!(Vec::<u8>::from_hex(badchar2), Err(Error::InvalidChar(b'Y')));
|
|
||||||
assert_eq!(Vec::<u8>::from_hex(badchar3), Err(Error::InvalidChar(194)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,13 +5,7 @@
|
||||||
//! Implementations of traits defined in `std` / `core2` and not in `core`.
|
//! Implementations of traits defined in `std` / `core2` and not in `core`.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
use crate::{hmac, io, ripemd160, sha1, sha256, sha512, siphash24, HashEngine};
|
||||||
use std::io;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use core2::io;
|
|
||||||
|
|
||||||
use crate::{hmac, ripemd160, sha1, sha256, sha512, siphash24, HashEngine};
|
|
||||||
|
|
||||||
impl io::Write for sha1::HashEngine {
|
impl io::Write for sha1::HashEngine {
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||||
|
|
|
@ -9,11 +9,11 @@ macro_rules! arr_newtype_fmt_impl {
|
||||||
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
|
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::Hash as _;
|
use crate::Hash as _;
|
||||||
let case = internals::hex::Case::Lower;
|
let case = $crate::hex::Case::Lower;
|
||||||
if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
|
if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
|
||||||
internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
|
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
|
||||||
} else {
|
} else {
|
||||||
internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
|
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,11 @@ macro_rules! arr_newtype_fmt_impl {
|
||||||
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
|
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::Hash as _;
|
use crate::Hash as _;
|
||||||
let case = internals::hex::Case::Upper;
|
let case = $crate::hex::Case::Upper;
|
||||||
if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
|
if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
|
||||||
internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
|
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
|
||||||
} else {
|
} else {
|
||||||
internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
|
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ macro_rules! hash_trait_impls {
|
||||||
/// This is mainly intended as an internal method and you shouldn't need it unless
|
/// This is mainly intended as an internal method and you shouldn't need it unless
|
||||||
/// you're doing something special.
|
/// you're doing something special.
|
||||||
pub fn forward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
|
pub fn forward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
|
||||||
internals::hex::display::DisplayHex::as_hex(&self.0)
|
$crate::hex::DisplayHex::as_hex(&self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Displays hex backwards, regardless of how this type would display it naturally.
|
/// Displays hex backwards, regardless of how this type would display it naturally.
|
||||||
|
@ -84,7 +84,7 @@ macro_rules! hash_trait_impls {
|
||||||
/// This is mainly intended as an internal method and you shouldn't need it unless
|
/// This is mainly intended as an internal method and you shouldn't need it unless
|
||||||
/// you're doing something special.
|
/// you're doing something special.
|
||||||
pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
|
pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
|
||||||
internals::hex::display::DisplayArray::<_, [u8; $bits / 8 * 2]>::new(self.0.iter().rev())
|
$crate::hex::display::DisplayArray::<_, [u8; $bits / 8 * 2]>::new(self.0.iter().rev())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zero cost conversion between a fixed length byte array shared reference and
|
/// Zero cost conversion between a fixed length byte array shared reference and
|
||||||
|
@ -103,15 +103,15 @@ macro_rules! hash_trait_impls {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> {
|
impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> {
|
||||||
type Err = $crate::hex::Error;
|
type Err = $crate::hex::HexToArrayError;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
use $crate::hex::{FromHex, HexIterator};
|
use $crate::hex::{FromHex, HexToBytesIter};
|
||||||
use $crate::Hash;
|
use $crate::Hash;
|
||||||
|
|
||||||
let inner: [u8; $bits / 8] = if $reverse {
|
let inner: [u8; $bits / 8] = if $reverse {
|
||||||
FromHex::from_byte_iter(HexIterator::new(s)?.rev())?
|
FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())?
|
||||||
} else {
|
} else {
|
||||||
FromHex::from_byte_iter(HexIterator::new(s)?)?
|
FromHex::from_byte_iter(HexToBytesIter::new(s)?)?
|
||||||
};
|
};
|
||||||
Ok(Self::from_byte_array(inner))
|
Ok(Self::from_byte_array(inner))
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,12 +79,12 @@
|
||||||
// Instead of littering the codebase for non-fuzzing code just globally allow.
|
// Instead of littering the codebase for non-fuzzing code just globally allow.
|
||||||
#![cfg_attr(hashes_fuzz, allow(dead_code, unused_imports))]
|
#![cfg_attr(hashes_fuzz, allow(dead_code, unused_imports))]
|
||||||
|
|
||||||
|
#[cfg(all(not(test), not(feature = "std"), feature = "core2"))]
|
||||||
|
extern crate actual_core2 as core2;
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[cfg(any(test, feature = "std"))]
|
#[cfg(any(test, feature = "std"))]
|
||||||
extern crate core;
|
extern crate core;
|
||||||
#[cfg(feature = "core2")]
|
|
||||||
extern crate core2;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
/// A generic serialization/deserialization framework.
|
/// A generic serialization/deserialization framework.
|
||||||
|
@ -95,6 +95,9 @@ extern crate serde_test;
|
||||||
#[cfg(bench)]
|
#[cfg(bench)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
/// Re-export the `hex-conservative` crate.
|
||||||
|
pub extern crate hex;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod _export {
|
pub mod _export {
|
||||||
/// A re-export of core::*
|
/// A re-export of core::*
|
||||||
|
@ -113,9 +116,8 @@ mod util;
|
||||||
pub mod serde_macros;
|
pub mod serde_macros;
|
||||||
pub mod cmp;
|
pub mod cmp;
|
||||||
pub mod hash160;
|
pub mod hash160;
|
||||||
pub mod hex;
|
|
||||||
pub mod hmac;
|
pub mod hmac;
|
||||||
#[cfg(any(feature = "std", feature = "core2"))]
|
#[cfg(any(test, feature = "std", feature = "core2"))]
|
||||||
mod impls;
|
mod impls;
|
||||||
pub mod ripemd160;
|
pub mod ripemd160;
|
||||||
pub mod sha1;
|
pub mod sha1;
|
||||||
|
@ -127,7 +129,12 @@ pub mod sha512_256;
|
||||||
pub mod siphash24;
|
pub mod siphash24;
|
||||||
|
|
||||||
use core::{borrow, fmt, hash, ops};
|
use core::{borrow, fmt, hash, ops};
|
||||||
|
// You get I/O if you enable "std" or "core2" (as well as during testing).
|
||||||
|
#[cfg(any(test, feature = "std"))]
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[cfg(all(not(test), not(feature = "std"), feature = "core2"))]
|
||||||
|
use core2::io;
|
||||||
pub use hmac::{Hmac, HmacEngine};
|
pub use hmac::{Hmac, HmacEngine};
|
||||||
|
|
||||||
/// A hashing engine which bytes can be serialized into.
|
/// A hashing engine which bytes can be serialized into.
|
||||||
|
|
|
@ -125,7 +125,7 @@ impl<I: SliceIndex<[u8]>> Index<I> for Midstate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl str::FromStr for Midstate {
|
impl str::FromStr for Midstate {
|
||||||
type Err = hex::Error;
|
type Err = hex::HexToArrayError;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> { hex::FromHex::from_hex(s) }
|
fn from_str(s: &str) -> Result<Self, Self::Err> { hex::FromHex::from_hex(s) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +174,12 @@ impl Midstate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hex::FromHex for Midstate {
|
impl hex::FromHex for Midstate {
|
||||||
fn from_byte_iter<I>(iter: I) -> Result<Self, hex::Error>
|
type Err = hex::HexToArrayError;
|
||||||
|
fn from_byte_iter<I>(iter: I) -> Result<Self, Self::Err>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Result<u8, hex::Error>> + ExactSizeIterator + DoubleEndedIterator,
|
I: Iterator<Item = Result<u8, hex::HexToBytesError>>
|
||||||
|
+ ExactSizeIterator
|
||||||
|
+ DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
// DISPLAY_BACKWARD is true
|
// DISPLAY_BACKWARD is true
|
||||||
Ok(Midstate::from_byte_array(hex::FromHex::from_byte_iter(iter.rev())?))
|
Ok(Midstate::from_byte_array(hex::FromHex::from_byte_iter(iter.rev())?))
|
||||||
|
|
|
@ -268,15 +268,15 @@ macro_rules! hash_newtype {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::_export::_core::str::FromStr for $newtype {
|
impl $crate::_export::_core::str::FromStr for $newtype {
|
||||||
type Err = $crate::hex::Error;
|
type Err = $crate::hex::HexToArrayError;
|
||||||
fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> {
|
fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> {
|
||||||
use $crate::hex::{HexIterator, FromHex};
|
use $crate::hex::{FromHex, HexToBytesIter};
|
||||||
use $crate::Hash;
|
use $crate::Hash;
|
||||||
|
|
||||||
let inner: <$hash as Hash>::Bytes = if <Self as $crate::Hash>::DISPLAY_BACKWARD {
|
let inner: <$hash as Hash>::Bytes = if <Self as $crate::Hash>::DISPLAY_BACKWARD {
|
||||||
FromHex::from_byte_iter(HexIterator::new(s)?.rev())?
|
FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())?
|
||||||
} else {
|
} else {
|
||||||
FromHex::from_byte_iter(HexIterator::new(s)?)?
|
FromHex::from_byte_iter(HexToBytesIter::new(s)?)?
|
||||||
};
|
};
|
||||||
Ok($newtype(<$hash>::from_byte_array(inner)))
|
Ok($newtype(<$hash>::from_byte_array(inner)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,396 +0,0 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
//! Implements a buffered encoder.
|
|
||||||
//!
|
|
||||||
//! The main type of this module is [`BufEncoder`] which provides buffered hex encoding. Such is
|
|
||||||
//! faster than the usual `write!(f, "{02x}", b)?` in a for loop because it reduces dynamic
|
|
||||||
//! dispatch and decreases the number of allocations if a `String` is being created.
|
|
||||||
|
|
||||||
use core::borrow::Borrow;
|
|
||||||
|
|
||||||
pub use out_bytes::OutBytes;
|
|
||||||
|
|
||||||
use super::Case;
|
|
||||||
|
|
||||||
/// Trait for types that can be soundly converted to `OutBytes`.
|
|
||||||
///
|
|
||||||
/// To protect the API from future breakage this sealed trait guards which types can be used with
|
|
||||||
/// the `Encoder`. Currently it is implemented for byte arrays of various interesting lengths.
|
|
||||||
///
|
|
||||||
/// ## Safety
|
|
||||||
///
|
|
||||||
/// This is not `unsafe` yet but the `as_out_bytes` should always return the same reference if the
|
|
||||||
/// same reference is supplied. IOW the returned memory address and length should be the same if
|
|
||||||
/// the input memory address and length are the same.
|
|
||||||
///
|
|
||||||
/// If the trait ever becomes `unsafe` this will be required for soundness.
|
|
||||||
pub trait AsOutBytes: out_bytes::Sealed {
|
|
||||||
/// Performs the conversion.
|
|
||||||
fn as_out_bytes(&self) -> &OutBytes;
|
|
||||||
|
|
||||||
/// Performs the conversion.
|
|
||||||
fn as_mut_out_bytes(&mut self) -> &mut OutBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A buffer with compile-time-known length.
|
|
||||||
///
|
|
||||||
/// This is essentially `Default + AsOutBytes` but supports lengths 1.41 doesn't.
|
|
||||||
pub trait FixedLenBuf: Sized + AsOutBytes {
|
|
||||||
/// Creates an uninitialized buffer.
|
|
||||||
///
|
|
||||||
/// The current implementtions initialize the buffer with zeroes but it should be treated a
|
|
||||||
/// uninitialized anyway.
|
|
||||||
fn uninit() -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements `OutBytes`
|
|
||||||
///
|
|
||||||
/// This prevents the rest of the crate from accessing the field of `OutBytes`.
|
|
||||||
mod out_bytes {
|
|
||||||
use super::AsOutBytes;
|
|
||||||
|
|
||||||
/// A byte buffer that can only be written-into.
|
|
||||||
///
|
|
||||||
/// You shouldn't concern yourself with this, just call `BufEncoder::new` with your array.
|
|
||||||
///
|
|
||||||
/// This prepares the API for potential future support of `[MaybeUninit<u8>]`. We don't want to use
|
|
||||||
/// `unsafe` until it's proven to be needed but if it does we have an easy, compatible upgrade
|
|
||||||
/// option.
|
|
||||||
///
|
|
||||||
/// Warning: `repr(transparent)` is an internal implementation detail and **must not** be
|
|
||||||
/// relied on!
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct OutBytes([u8]);
|
|
||||||
|
|
||||||
impl OutBytes {
|
|
||||||
/// Returns the first `len` bytes as initialized.
|
|
||||||
///
|
|
||||||
/// Not `unsafe` because we don't use `unsafe` (yet).
|
|
||||||
///
|
|
||||||
/// ## Panics
|
|
||||||
///
|
|
||||||
/// The method panics if `len` is out of bounds.
|
|
||||||
#[track_caller]
|
|
||||||
pub(crate) fn assume_init(&self, len: usize) -> &[u8] { &self.0[..len] }
|
|
||||||
|
|
||||||
/// Writes given bytes into the buffer.
|
|
||||||
///
|
|
||||||
/// ## Panics
|
|
||||||
///
|
|
||||||
/// The method panics if pos is out of bounds or `bytes` don't fit into the buffer.
|
|
||||||
#[track_caller]
|
|
||||||
pub(crate) fn write(&mut self, pos: usize, bytes: &[u8]) {
|
|
||||||
self.0[pos..(pos + bytes.len())].copy_from_slice(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the length of the buffer.
|
|
||||||
pub(crate) fn len(&self) -> usize { self.0.len() }
|
|
||||||
|
|
||||||
fn from_bytes(slice: &[u8]) -> &Self {
|
|
||||||
// SAFETY: copied from std
|
|
||||||
// conversion of reference to pointer of the same referred type is always sound,
|
|
||||||
// including in unsized types.
|
|
||||||
// Thanks to repr(transparent) the types have the same layout making the other
|
|
||||||
// conversion sound.
|
|
||||||
// The pointer was just created from a reference that's still alive so dereferencing is
|
|
||||||
// sound.
|
|
||||||
unsafe { &*(slice as *const [u8] as *const Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_mut_bytes(slice: &mut [u8]) -> &mut Self {
|
|
||||||
// SAFETY: copied from std
|
|
||||||
// conversion of reference to pointer of the same referred type is always sound,
|
|
||||||
// including in unsized types.
|
|
||||||
// Thanks to repr(transparent) the types have the same layout making the other
|
|
||||||
// conversion sound.
|
|
||||||
// The pointer was just created from a reference that's still alive so dereferencing is
|
|
||||||
// sound.
|
|
||||||
unsafe { &mut *(slice as *mut [u8] as *mut Self) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_from_array {
|
|
||||||
($($len:expr),* $(,)?) => {
|
|
||||||
$(
|
|
||||||
impl super::FixedLenBuf for [u8; $len] {
|
|
||||||
fn uninit() -> Self {
|
|
||||||
[0u8; $len]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsOutBytes for [u8; $len] {
|
|
||||||
fn as_out_bytes(&self) -> &OutBytes {
|
|
||||||
OutBytes::from_bytes(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_mut_out_bytes(&mut self) -> &mut OutBytes {
|
|
||||||
OutBytes::from_mut_bytes(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sealed for [u8; $len] {}
|
|
||||||
|
|
||||||
impl<'a> super::super::display::DisplayHex for &'a [u8; $len / 2] {
|
|
||||||
type Display = super::super::display::DisplayArray<core::slice::Iter<'a, u8>, [u8; $len]>;
|
|
||||||
fn as_hex(self) -> Self::Display {
|
|
||||||
super::super::display::DisplayArray::new(self.iter())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hex_reserve_suggestion(self) -> usize {
|
|
||||||
$len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: AsOutBytes + ?Sized> AsOutBytes for &'_ mut T {
|
|
||||||
fn as_out_bytes(&self) -> &OutBytes { (**self).as_out_bytes() }
|
|
||||||
|
|
||||||
fn as_mut_out_bytes(&mut self) -> &mut OutBytes { (**self).as_mut_out_bytes() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: AsOutBytes + ?Sized> Sealed for &'_ mut T {}
|
|
||||||
|
|
||||||
impl AsOutBytes for OutBytes {
|
|
||||||
fn as_out_bytes(&self) -> &OutBytes { self }
|
|
||||||
|
|
||||||
fn as_mut_out_bytes(&mut self) -> &mut OutBytes { self }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sealed for OutBytes {}
|
|
||||||
|
|
||||||
// As a sanity check we only provide conversions for even, non-empty arrays.
|
|
||||||
// Weird lengths 66 and 130 are provided for serialized public keys.
|
|
||||||
impl_from_array!(
|
|
||||||
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 40, 64, 66, 128, 130, 256, 512,
|
|
||||||
1024, 2048, 4096, 8192
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Prevents outside crates from implementing the trait
|
|
||||||
pub trait Sealed {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Hex-encodes bytes into the provided buffer.
|
|
||||||
///
|
|
||||||
/// This is an important building block for fast hex-encoding. Because string writing tools
|
|
||||||
/// provided by `core::fmt` involve dynamic dispatch and don't allow reserving capacity in strings
|
|
||||||
/// buffering the hex and then formatting it is significantly faster.
|
|
||||||
pub struct BufEncoder<T: AsOutBytes> {
|
|
||||||
buf: T,
|
|
||||||
pos: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: AsOutBytes> BufEncoder<T> {
|
|
||||||
/// Creates an empty `BufEncoder`.
|
|
||||||
///
|
|
||||||
/// This is usually used with uninitialized (zeroed) byte array allocated on stack.
|
|
||||||
/// This can only be constructed with an even-length, non-empty array.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(buf: T) -> Self { BufEncoder { buf, pos: 0 } }
|
|
||||||
|
|
||||||
/// Encodes `byte` as hex in given `case` and appends it to the buffer.
|
|
||||||
///
|
|
||||||
/// ## Panics
|
|
||||||
///
|
|
||||||
/// The method panics if the buffer is full.
|
|
||||||
#[inline]
|
|
||||||
#[track_caller]
|
|
||||||
pub fn put_byte(&mut self, byte: u8, case: Case) {
|
|
||||||
self.buf.as_mut_out_bytes().write(self.pos, &super::byte_to_hex(byte, case.table()));
|
|
||||||
self.pos += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encodes `bytes` as hex in given `case` and appends them to the buffer.
|
|
||||||
///
|
|
||||||
/// ## Panics
|
|
||||||
///
|
|
||||||
/// The method panics if the bytes wouldn't fit the buffer.
|
|
||||||
#[inline]
|
|
||||||
#[track_caller]
|
|
||||||
pub fn put_bytes<I>(&mut self, bytes: I, case: Case)
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<u8>,
|
|
||||||
{
|
|
||||||
self.put_bytes_inner(bytes.into_iter(), case)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[track_caller]
|
|
||||||
fn put_bytes_inner<I>(&mut self, bytes: I, case: Case)
|
|
||||||
where
|
|
||||||
I: Iterator,
|
|
||||||
I::Item: Borrow<u8>,
|
|
||||||
{
|
|
||||||
// May give the compiler better optimization opportunity
|
|
||||||
if let Some(max) = bytes.size_hint().1 {
|
|
||||||
assert!(max <= self.space_remaining());
|
|
||||||
}
|
|
||||||
for byte in bytes {
|
|
||||||
self.put_byte(*byte.borrow(), case);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encodes as many `bytes` as fit into the buffer as hex and return the remainder.
|
|
||||||
///
|
|
||||||
/// This method works just like `put_bytes` but instead of panicking it returns the unwritten
|
|
||||||
/// bytes. The method returns an empty slice if all bytes were written
|
|
||||||
#[must_use = "this may write only part of the input buffer"]
|
|
||||||
#[inline]
|
|
||||||
#[track_caller]
|
|
||||||
pub fn put_bytes_min<'a>(&mut self, bytes: &'a [u8], case: Case) -> &'a [u8] {
|
|
||||||
let to_write = self.space_remaining().min(bytes.len());
|
|
||||||
self.put_bytes(&bytes[..to_write], case);
|
|
||||||
&bytes[to_write..]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if no more bytes can be written into the buffer.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_full(&self) -> bool { self.pos == self.buf.as_out_bytes().len() }
|
|
||||||
|
|
||||||
/// Returns the written bytes as a hex `str`.
|
|
||||||
#[inline]
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
core::str::from_utf8(self.buf.as_out_bytes().assume_init(self.pos))
|
|
||||||
.expect("we only write ASCII")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets the buffer to become empty.
|
|
||||||
#[inline]
|
|
||||||
pub fn clear(&mut self) { self.pos = 0; }
|
|
||||||
|
|
||||||
/// How many bytes can be written to this buffer.
|
|
||||||
///
|
|
||||||
/// Note that this returns the number of bytes before encoding, not number of hex digits.
|
|
||||||
#[inline]
|
|
||||||
pub fn space_remaining(&self) -> usize { (self.buf.as_out_bytes().len() - self.pos) / 2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty() {
|
|
||||||
let mut buf = [0u8; 2];
|
|
||||||
let encoder = BufEncoder::new(&mut buf);
|
|
||||||
assert_eq!(encoder.as_str(), "");
|
|
||||||
assert!(!encoder.is_full());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn single_byte_exact_buf() {
|
|
||||||
let mut buf = [0u8; 2];
|
|
||||||
let mut encoder = BufEncoder::new(&mut buf);
|
|
||||||
assert_eq!(encoder.space_remaining(), 1);
|
|
||||||
encoder.put_byte(42, Case::Lower);
|
|
||||||
assert_eq!(encoder.as_str(), "2a");
|
|
||||||
assert_eq!(encoder.space_remaining(), 0);
|
|
||||||
assert!(encoder.is_full());
|
|
||||||
encoder.clear();
|
|
||||||
assert_eq!(encoder.space_remaining(), 1);
|
|
||||||
assert!(!encoder.is_full());
|
|
||||||
encoder.put_byte(42, Case::Upper);
|
|
||||||
assert_eq!(encoder.as_str(), "2A");
|
|
||||||
assert_eq!(encoder.space_remaining(), 0);
|
|
||||||
assert!(encoder.is_full());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn single_byte_oversized_buf() {
|
|
||||||
let mut buf = [0u8; 4];
|
|
||||||
let mut encoder = BufEncoder::new(&mut buf);
|
|
||||||
assert_eq!(encoder.space_remaining(), 2);
|
|
||||||
encoder.put_byte(42, Case::Lower);
|
|
||||||
assert_eq!(encoder.space_remaining(), 1);
|
|
||||||
assert_eq!(encoder.as_str(), "2a");
|
|
||||||
assert!(!encoder.is_full());
|
|
||||||
encoder.clear();
|
|
||||||
assert_eq!(encoder.space_remaining(), 2);
|
|
||||||
encoder.put_byte(42, Case::Upper);
|
|
||||||
assert_eq!(encoder.as_str(), "2A");
|
|
||||||
assert_eq!(encoder.space_remaining(), 1);
|
|
||||||
assert!(!encoder.is_full());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn two_bytes() {
|
|
||||||
let mut buf = [0u8; 4];
|
|
||||||
let mut encoder = BufEncoder::new(&mut buf);
|
|
||||||
encoder.put_byte(42, Case::Lower);
|
|
||||||
assert_eq!(encoder.space_remaining(), 1);
|
|
||||||
encoder.put_byte(255, Case::Lower);
|
|
||||||
assert_eq!(encoder.space_remaining(), 0);
|
|
||||||
assert_eq!(encoder.as_str(), "2aff");
|
|
||||||
assert!(encoder.is_full());
|
|
||||||
encoder.clear();
|
|
||||||
assert!(!encoder.is_full());
|
|
||||||
encoder.put_byte(42, Case::Upper);
|
|
||||||
encoder.put_byte(255, Case::Upper);
|
|
||||||
assert_eq!(encoder.as_str(), "2AFF");
|
|
||||||
assert!(encoder.is_full());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn put_bytes_min() {
|
|
||||||
let mut buf = [0u8; 2];
|
|
||||||
let mut encoder = BufEncoder::new(&mut buf);
|
|
||||||
let remainder = encoder.put_bytes_min(b"", Case::Lower);
|
|
||||||
assert_eq!(remainder, b"");
|
|
||||||
assert_eq!(encoder.as_str(), "");
|
|
||||||
let remainder = encoder.put_bytes_min(b"*", Case::Lower);
|
|
||||||
assert_eq!(remainder, b"");
|
|
||||||
assert_eq!(encoder.as_str(), "2a");
|
|
||||||
encoder.clear();
|
|
||||||
let remainder = encoder.put_bytes_min(&[42, 255], Case::Lower);
|
|
||||||
assert_eq!(remainder, &[255]);
|
|
||||||
assert_eq!(encoder.as_str(), "2a");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn same_as_fmt() {
|
|
||||||
use core::fmt::{self, Write};
|
|
||||||
|
|
||||||
struct Writer {
|
|
||||||
buf: [u8; 2],
|
|
||||||
pos: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Writer {
|
|
||||||
fn as_str(&self) -> &str { core::str::from_utf8(&self.buf[..self.pos]).unwrap() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for Writer {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
assert!(self.pos <= 2);
|
|
||||||
if s.len() > 2 - self.pos {
|
|
||||||
Err(fmt::Error)
|
|
||||||
} else {
|
|
||||||
self.buf[self.pos..(self.pos + s.len())].copy_from_slice(s.as_bytes());
|
|
||||||
self.pos += s.len();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut writer = Writer { buf: [0u8; 2], pos: 0 };
|
|
||||||
let mut buf = [0u8; 2];
|
|
||||||
let mut encoder = BufEncoder::new(&mut buf);
|
|
||||||
|
|
||||||
for i in 0..=255 {
|
|
||||||
write!(writer, "{:02x}", i).unwrap();
|
|
||||||
encoder.put_byte(i, Case::Lower);
|
|
||||||
assert_eq!(encoder.as_str(), writer.as_str());
|
|
||||||
writer.pos = 0;
|
|
||||||
encoder.clear();
|
|
||||||
}
|
|
||||||
for i in 0..=255 {
|
|
||||||
write!(writer, "{:02X}", i).unwrap();
|
|
||||||
encoder.put_byte(i, Case::Upper);
|
|
||||||
assert_eq!(encoder.as_str(), writer.as_str());
|
|
||||||
writer.pos = 0;
|
|
||||||
encoder.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,303 +0,0 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
//! Helpers for displaying bytes as hex strings.
|
|
||||||
//!
|
|
||||||
//! This module provides a trait for displaying things as hex as well as an implementation for
|
|
||||||
//! `&[u8]`.
|
|
||||||
|
|
||||||
use core::borrow::Borrow;
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
use super::buf_encoder::{BufEncoder, OutBytes};
|
|
||||||
use super::Case;
|
|
||||||
use crate::hex::buf_encoder::FixedLenBuf;
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
/// Extension trait for types that can be displayed as hex.
|
|
||||||
///
|
|
||||||
/// Types that have a single, obvious text representation being hex should **not** implement this
|
|
||||||
/// trait and simply implement `Display` instead.
|
|
||||||
///
|
|
||||||
/// This trait should be generally implemented for references only. We would prefer to use GAT but
|
|
||||||
/// that is beyond our MSRV. As a lint we require the `IsRef` trait which is implemented for all
|
|
||||||
/// references.
|
|
||||||
pub trait DisplayHex: Copy + sealed::IsRef {
|
|
||||||
/// The type providing [`fmt::Display`] implementation.
|
|
||||||
///
|
|
||||||
/// This is usually a wrapper type holding a reference to `Self`.
|
|
||||||
type Display: fmt::LowerHex + fmt::UpperHex;
|
|
||||||
|
|
||||||
/// Display `Self` as a continuous sequence of ASCII hex chars.
|
|
||||||
fn as_hex(self) -> Self::Display;
|
|
||||||
|
|
||||||
/// Create a lower-hex-encoded string.
|
|
||||||
///
|
|
||||||
/// A shorthand for `to_hex_string(Case::Lower)`, so that `Case` doesn't need to be imported.
|
|
||||||
///
|
|
||||||
/// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn to_lower_hex_string(self) -> String { self.to_hex_string(Case::Lower) }
|
|
||||||
|
|
||||||
/// Create an upper-hex-encoded string.
|
|
||||||
///
|
|
||||||
/// A shorthand for `to_hex_string(Case::Upper)`, so that `Case` doesn't need to be imported.
|
|
||||||
///
|
|
||||||
/// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn to_upper_hex_string(self) -> String { self.to_hex_string(Case::Upper) }
|
|
||||||
|
|
||||||
/// Create a hex-encoded string.
|
|
||||||
///
|
|
||||||
/// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn to_hex_string(self, case: Case) -> String {
|
|
||||||
let mut string = String::new();
|
|
||||||
self.append_hex_to_string(case, &mut string);
|
|
||||||
string
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Appends hex-encoded content to an existing `String`.
|
|
||||||
///
|
|
||||||
/// This may be faster than `write!(string, "{:x}", self.display_hex())` because it uses
|
|
||||||
/// `reserve_sugggestion`.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn append_hex_to_string(self, case: Case, string: &mut String) {
|
|
||||||
use fmt::Write;
|
|
||||||
|
|
||||||
string.reserve(self.hex_reserve_suggestion());
|
|
||||||
match case {
|
|
||||||
Case::Lower => write!(string, "{:x}", self.as_hex()),
|
|
||||||
Case::Upper => write!(string, "{:X}", self.as_hex()),
|
|
||||||
}
|
|
||||||
.unwrap_or_else(|_| {
|
|
||||||
let name = core::any::type_name::<Self::Display>();
|
|
||||||
// We don't expect `std` to ever be buggy, so the bug is most likely in the `Display`
|
|
||||||
// impl of `Self::Display`.
|
|
||||||
panic!("The implementation of Display for {} returned an error when it shouldn't", name)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Hints how much bytes to reserve when creating a `String`.
|
|
||||||
///
|
|
||||||
/// Implementors that know the number of produced bytes upfront should override this.
|
|
||||||
/// Defaults to 0.
|
|
||||||
///
|
|
||||||
// We prefix the name with `hex_` to avoid potential collision with other methods.
|
|
||||||
fn hex_reserve_suggestion(self) -> usize { 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
mod sealed {
|
|
||||||
/// Trait marking a shared reference.
|
|
||||||
pub trait IsRef: Copy {}
|
|
||||||
|
|
||||||
impl<T: ?Sized> IsRef for &'_ T {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DisplayHex for &'a [u8] {
|
|
||||||
type Display = DisplayByteSlice<'a>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn hex_reserve_suggestion(self) -> usize {
|
|
||||||
// Since the string wouldn't fit into address space if this overflows (actually even for
|
|
||||||
// smaller amounts) it's better to panic right away. It should also give the optimizer
|
|
||||||
// better opportunities.
|
|
||||||
self.len().checked_mul(2).expect("the string wouldn't fit into address space")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
impl<'a> DisplayHex for &'a alloc::vec::Vec<u8> {
|
|
||||||
type Display = DisplayByteSlice<'a>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn hex_reserve_suggestion(self) -> usize {
|
|
||||||
// Since the string wouldn't fit into address space if this overflows (actually even for
|
|
||||||
// smaller amounts) it's better to panic right away. It should also give the optimizer
|
|
||||||
// better opportunities.
|
|
||||||
self.len().checked_mul(2).expect("the string wouldn't fit into address space")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Displays byte slice as hex.
|
|
||||||
///
|
|
||||||
/// Created by [`<&[u8] as DisplayHex>::as_hex`](DisplayHex::as_hex).
|
|
||||||
pub struct DisplayByteSlice<'a> {
|
|
||||||
// pub because we want to keep lengths in sync
|
|
||||||
pub(crate) bytes: &'a [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DisplayByteSlice<'a> {
|
|
||||||
fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
|
|
||||||
let mut buf = [0u8; 1024];
|
|
||||||
let mut encoder = super::BufEncoder::new(&mut buf);
|
|
||||||
|
|
||||||
let mut chunks = self.bytes.chunks_exact(512);
|
|
||||||
for chunk in &mut chunks {
|
|
||||||
encoder.put_bytes(chunk, case);
|
|
||||||
f.write_str(encoder.as_str())?;
|
|
||||||
encoder.clear();
|
|
||||||
}
|
|
||||||
encoder.put_bytes(chunks.remainder(), case);
|
|
||||||
f.write_str(encoder.as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> fmt::LowerHex for DisplayByteSlice<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> fmt::UpperHex for DisplayByteSlice<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Displays byte array as hex.
|
|
||||||
///
|
|
||||||
/// Created by [`<&[u8; LEN] as DisplayHex>::as_hex`](DisplayHex::as_hex).
|
|
||||||
pub struct DisplayArray<A: Clone + IntoIterator, B: FixedLenBuf>
|
|
||||||
where
|
|
||||||
A::Item: Borrow<u8>,
|
|
||||||
{
|
|
||||||
array: A,
|
|
||||||
_buffer_marker: core::marker::PhantomData<B>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Clone + IntoIterator, B: FixedLenBuf> DisplayArray<A, B>
|
|
||||||
where
|
|
||||||
A::Item: Borrow<u8>,
|
|
||||||
{
|
|
||||||
/// Creates the wrapper.
|
|
||||||
pub fn new(array: A) -> Self { DisplayArray { array, _buffer_marker: Default::default() } }
|
|
||||||
|
|
||||||
fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
|
|
||||||
let mut buf = B::uninit();
|
|
||||||
let mut encoder = super::BufEncoder::new(&mut buf);
|
|
||||||
encoder.put_bytes(self.array.clone(), case);
|
|
||||||
f.pad_integral(true, "0x", encoder.as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Clone + IntoIterator, B: FixedLenBuf> fmt::LowerHex for DisplayArray<A, B>
|
|
||||||
where
|
|
||||||
A::Item: Borrow<u8>,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Clone + IntoIterator, B: FixedLenBuf> fmt::UpperHex for DisplayArray<A, B>
|
|
||||||
where
|
|
||||||
A::Item: Borrow<u8>,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Format known-length array as hex.
|
|
||||||
///
|
|
||||||
/// This supports all formatting options of formatter and may be faster than calling
|
|
||||||
/// `display_as_hex()` on an arbitrary `&[u8]`. Note that the implementation intentionally keeps
|
|
||||||
/// leading zeros even when not requested. This is designed to display values such as hashes and
|
|
||||||
/// keys and removing leading zeros would be confusing.
|
|
||||||
///
|
|
||||||
/// ## Parameters
|
|
||||||
///
|
|
||||||
/// * `$formatter` - a [`fmt::Formatter`].
|
|
||||||
/// * `$len` known length of `$bytes`, must be a const expression.
|
|
||||||
/// * `$bytes` - bytes to be encoded, most likely a reference to an array.
|
|
||||||
/// * `$case` - value of type [`Case`] determining whether to format as lower or upper case.
|
|
||||||
///
|
|
||||||
/// ## Panics
|
|
||||||
///
|
|
||||||
/// This macro panics if `$len` is not equal to `$bytes.len()`. It also fails to compile if `$len`
|
|
||||||
/// is more than half of `usize::MAX`.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! fmt_hex_exact {
|
|
||||||
($formatter:expr, $len:expr, $bytes:expr, $case:expr) => {{
|
|
||||||
// statically check $len
|
|
||||||
#[allow(deprecated)]
|
|
||||||
const _: () = [()][($len > usize::MAX / 2) as usize];
|
|
||||||
assert_eq!($bytes.len(), $len);
|
|
||||||
let mut buf = [0u8; $len * 2];
|
|
||||||
let buf = $crate::hex::buf_encoder::AsOutBytes::as_mut_out_bytes(&mut buf);
|
|
||||||
$crate::hex::display::fmt_hex_exact_fn($formatter, buf, $bytes, $case)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
pub use fmt_hex_exact;
|
|
||||||
|
|
||||||
// Implementation detail of `write_hex_exact` macro to de-duplicate the code
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub fn fmt_hex_exact_fn<I>(
|
|
||||||
f: &mut fmt::Formatter,
|
|
||||||
buf: &mut OutBytes,
|
|
||||||
bytes: I,
|
|
||||||
case: Case,
|
|
||||||
) -> fmt::Result
|
|
||||||
where
|
|
||||||
I: IntoIterator,
|
|
||||||
I::Item: Borrow<u8>,
|
|
||||||
{
|
|
||||||
let mut encoder = BufEncoder::new(buf);
|
|
||||||
encoder.put_bytes(bytes, case);
|
|
||||||
f.pad_integral(true, "0x", encoder.as_str())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
mod alloc {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn check_encoding(bytes: &[u8]) {
|
|
||||||
use core::fmt::Write;
|
|
||||||
|
|
||||||
let s1 = bytes.to_lower_hex_string();
|
|
||||||
let mut s2 = String::with_capacity(bytes.len() * 2);
|
|
||||||
for b in bytes {
|
|
||||||
write!(s2, "{:02x}", b).unwrap();
|
|
||||||
}
|
|
||||||
assert_eq!(s1, s2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty() { check_encoding(b""); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn single() { check_encoding(b"*"); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn two() { check_encoding(b"*x"); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn just_below_boundary() { check_encoding(&[42; 512]); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn just_above_boundary() { check_encoding(&[42; 513]); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn just_above_double_boundary() { check_encoding(&[42; 1025]); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn fmt_exact_macro() {
|
|
||||||
use crate::alloc::string::ToString;
|
|
||||||
|
|
||||||
struct Dummy([u8; 32]);
|
|
||||||
|
|
||||||
impl fmt::Display for Dummy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
fmt_hex_exact!(f, 32, &self.0, Case::Lower)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(Dummy([42; 32]).to_string(), "2a".repeat(32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
//! Helpers for encoding bytes as hex strings.
|
|
||||||
|
|
||||||
pub mod buf_encoder;
|
|
||||||
pub mod display;
|
|
||||||
|
|
||||||
pub use buf_encoder::BufEncoder;
|
|
||||||
|
|
||||||
/// Reexports of extension traits.
|
|
||||||
pub mod exts {
|
|
||||||
pub use super::display::DisplayHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Possible case of hex.
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
||||||
pub enum Case {
|
|
||||||
/// Produce lower-case chars (`[0-9a-f]`).
|
|
||||||
///
|
|
||||||
/// This is the default.
|
|
||||||
Lower,
|
|
||||||
|
|
||||||
/// Produce upper-case chars (`[0-9A-F]`).
|
|
||||||
Upper,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Case {
|
|
||||||
fn default() -> Self { Case::Lower }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Case {
|
|
||||||
/// Returns the encoding table.
|
|
||||||
///
|
|
||||||
/// The returned table may only contain displayable ASCII chars.
|
|
||||||
#[inline]
|
|
||||||
#[rustfmt::skip]
|
|
||||||
pub(crate) fn table(self) -> &'static [u8; 16] {
|
|
||||||
static LOWER: [u8; 16] = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f'];
|
|
||||||
static UPPER: [u8; 16] = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F'];
|
|
||||||
|
|
||||||
match self {
|
|
||||||
Case::Lower => &LOWER,
|
|
||||||
Case::Upper => &UPPER,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encodes single byte as two ASCII chars using the given table.
|
|
||||||
///
|
|
||||||
/// The function guarantees only returning values from the provided table.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn byte_to_hex(byte: u8, table: &[u8; 16]) -> [u8; 2] {
|
|
||||||
[table[usize::from(byte.wrapping_shr(4))], table[usize::from(byte & 0x0F)]]
|
|
||||||
}
|
|
|
@ -19,13 +19,6 @@ extern crate alloc;
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod hex;
|
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
mod parse;
|
mod parse;
|
||||||
pub mod serde;
|
pub mod serde;
|
||||||
|
|
||||||
/// Mainly reexports based on features.
|
|
||||||
pub(crate) mod prelude {
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
pub(crate) use alloc::string::String;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue