Skip to content

Commit 646f317

Browse files
committed
Merge #259: Replace custom hex parsing with hex-conservative crate
775d7cd Migrate hex decoding implemenation with hex-conservative (Velnbur) Pull request description: # Overview Add hex-conservative as a dependency and refactor hex parsing code to use it instead of the custom implementation. Update FromHex trait to use associated error types and standardize hex decoding across the codebase. Closes: #258 ACKs for top commit: apoelstra: ACK 775d7cd; successfully ran local tests Tree-SHA512: 2c2a92b92f886909890b6c1b01d8313a956fbebd7978a195ca71e73bb3dc7f8e0cbc1db5942951cd2eaddcde26fd6c689cfd0ec784acff7b113956e46151d6ab
2 parents f6ffc78 + 775d7cd commit 646f317

File tree

7 files changed

+153
-177
lines changed

7 files changed

+153
-177
lines changed

Cargo-latest.lock

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ dependencies = [
6464
"bitcoin-io",
6565
"bitcoin-units",
6666
"bitcoin_hashes",
67-
"hex-conservative",
67+
"hex-conservative 0.2.1",
6868
"hex_lit",
6969
"secp256k1",
7070
"serde",
@@ -108,7 +108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
108108
checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
109109
dependencies = [
110110
"bitcoin-io",
111-
"hex-conservative",
111+
"hex-conservative 0.2.1",
112112
"serde",
113113
]
114114

@@ -196,6 +196,7 @@ dependencies = [
196196
"bincode",
197197
"bitcoin",
198198
"getrandom 0.2.16",
199+
"hex-conservative 1.0.0",
199200
"rand",
200201
"rand_chacha",
201202
"secp256k1-zkp",
@@ -274,6 +275,12 @@ dependencies = [
274275
"arrayvec",
275276
]
276277

278+
[[package]]
279+
name = "hex-conservative"
280+
version = "1.0.0"
281+
source = "registry+https://github.com/rust-lang/crates.io-index"
282+
checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0"
283+
277284
[[package]]
278285
name = "hex_lit"
279286
version = "0.1.1"

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ serde_json = { version = "1.0", optional = true }
3232
actual-serde = { package = "serde", version = "1.0.103", features = [
3333
"derive",
3434
], optional = true }
35+
hex-conservative = "1.0.0"
3536

3637

3738
[target.wasm32-unknown-unknown.dev-dependencies]

src/confidential.rs

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,60 @@ impl<'de> Deserialize<'de> for Nonce {
720720
}
721721
}
722722

723+
/// Error decoding hexadecimal string into tweak-like value.
724+
#[derive(Debug, Clone, PartialEq, Eq)]
725+
pub enum TweakHexDecodeError {
726+
/// Invalid hexadecimal string.
727+
InvalidHex(hex_conservative::DecodeFixedLengthBytesError),
728+
/// Invalid tweak after decoding hexadecimal string.
729+
InvalidTweak(secp256k1_zkp::Error),
730+
}
731+
732+
impl fmt::Display for TweakHexDecodeError {
733+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
734+
match self {
735+
TweakHexDecodeError::InvalidHex(err) => {
736+
write!(f, "Invalid hex: {}", err)
737+
}
738+
TweakHexDecodeError::InvalidTweak(err) => {
739+
write!(f, "Invalid tweak: {}", err)
740+
}
741+
}
742+
}
743+
}
744+
745+
#[doc(hidden)]
746+
impl From<hex_conservative::DecodeFixedLengthBytesError> for TweakHexDecodeError {
747+
fn from(err: hex_conservative::DecodeFixedLengthBytesError) -> Self {
748+
TweakHexDecodeError::InvalidHex(err)
749+
}
750+
}
751+
752+
#[doc(hidden)]
753+
impl From<secp256k1_zkp::Error> for TweakHexDecodeError {
754+
fn from(err: secp256k1_zkp::Error) -> Self {
755+
TweakHexDecodeError::InvalidTweak(err)
756+
}
757+
}
758+
759+
impl From<TweakHexDecodeError> for encode::Error {
760+
fn from(value: TweakHexDecodeError) -> Self {
761+
match value {
762+
TweakHexDecodeError::InvalidHex(err) => encode::Error::HexFixedError(err),
763+
TweakHexDecodeError::InvalidTweak(err) => encode::Error::Secp256k1zkp(err),
764+
}
765+
}
766+
}
767+
768+
impl std::error::Error for TweakHexDecodeError {
769+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
770+
match self {
771+
TweakHexDecodeError::InvalidHex(err) => Some(err),
772+
TweakHexDecodeError::InvalidTweak(err) => Some(err),
773+
}
774+
}
775+
}
776+
723777
/// Blinding factor used for asset commitments.
724778
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
725779
pub struct AssetBlindingFactor(pub(crate) Tweak);
@@ -747,16 +801,13 @@ impl AssetBlindingFactor {
747801
}
748802

749803
impl hex::FromHex for AssetBlindingFactor {
750-
fn from_byte_iter<I>(iter: I) -> Result<Self, hex::Error>
751-
where I: Iterator<Item=Result<u8, hex::Error>> +
752-
ExactSizeIterator +
753-
DoubleEndedIterator
754-
{
755-
let slice = <[u8; 32]>::from_byte_iter(iter.rev())?;
756-
// Incorrect Return Error
757-
// See: https://github.com/rust-bitcoin/bitcoin_hashes/issues/124
758-
let inner = Tweak::from_inner(slice)
759-
.map_err(|_e| hex::Error::InvalidChar(0))?;
804+
type Err = TweakHexDecodeError;
805+
806+
fn from_hex(s: &str) -> Result<Self, Self::Err> {
807+
let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?;
808+
slice.reverse();
809+
810+
let inner = Tweak::from_inner(slice)?;
760811
Ok(AssetBlindingFactor(inner))
761812
}
762813
}
@@ -951,16 +1002,13 @@ impl Neg for ValueBlindingFactor {
9511002
}
9521003

9531004
impl hex::FromHex for ValueBlindingFactor {
954-
fn from_byte_iter<I>(iter: I) -> Result<Self, hex::Error>
955-
where I: Iterator<Item=Result<u8, hex::Error>> +
956-
ExactSizeIterator +
957-
DoubleEndedIterator
958-
{
959-
let slice = <[u8; 32]>::from_byte_iter(iter.rev())?;
960-
// Incorrect Return Error
961-
// See: https://github.com/rust-bitcoin/bitcoin_hashes/issues/124
962-
let inner = Tweak::from_inner(slice)
963-
.map_err(|_e| hex::Error::InvalidChar(0))?;
1005+
type Err = TweakHexDecodeError;
1006+
1007+
fn from_hex(s: &str) -> Result<Self, Self::Err> {
1008+
let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?;
1009+
slice.reverse();
1010+
1011+
let inner = Tweak::from_inner(slice)?;
9641012
Ok(ValueBlindingFactor(inner))
9651013
}
9661014
}

src/encode.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::io::Cursor;
1919
use std::{any, error, fmt, io, mem};
2020

2121
use bitcoin::ScriptBuf;
22+
use hex_conservative::{DecodeFixedLengthBytesError, DecodeVariableLengthBytesError};
2223
use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak};
2324

2425
use crate::hashes::{sha256, Hash};
@@ -54,8 +55,10 @@ pub enum Error {
5455
Secp256k1zkp(secp256k1_zkp::Error),
5556
/// Pset related Errors
5657
PsetError(pset::Error),
57-
/// Hex parsing errors
58-
HexError(crate::hex::Error),
58+
/// Hex fixed parsing errors
59+
HexFixedError(DecodeFixedLengthBytesError),
60+
/// Hex variable parsing errors
61+
HexVariableError(DecodeVariableLengthBytesError),
5962
/// Got a time-based locktime when expecting a height-based one, or vice-versa
6063
BadLockTime(crate::LockTime),
6164
/// `VarInt` was encoded in a non-minimal way.
@@ -83,7 +86,8 @@ impl fmt::Display for Error {
8386
Error::Secp256k1(ref e) => write!(f, "{}", e),
8487
Error::Secp256k1zkp(ref e) => write!(f, "{}", e),
8588
Error::PsetError(ref e) => write!(f, "Pset Error: {}", e),
86-
Error::HexError(ref e) => write!(f, "Hex error {}", e),
89+
Error::HexFixedError(ref e) => write!(f, "Hex fixed error: {}", e),
90+
Error::HexVariableError(ref e) => write!(f, "Hex variable error: {}", e),
8791
Error::BadLockTime(ref lt) => write!(f, "Invalid locktime {}", lt),
8892
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
8993
}
@@ -134,9 +138,16 @@ impl From<secp256k1_zkp::Error> for Error {
134138
}
135139

136140
#[doc(hidden)]
137-
impl From<crate::hex::Error> for Error {
138-
fn from(e: crate::hex::Error) -> Self {
139-
Error::HexError(e)
141+
impl From<DecodeFixedLengthBytesError> for Error {
142+
fn from(e: DecodeFixedLengthBytesError) -> Self {
143+
Error::HexFixedError(e)
144+
}
145+
}
146+
147+
#[doc(hidden)]
148+
impl From<DecodeVariableLengthBytesError> for Error {
149+
fn from(e: DecodeVariableLengthBytesError) -> Self {
150+
Error::HexVariableError(e)
140151
}
141152
}
142153

0 commit comments

Comments
 (0)