Skip to content

Commit 3536c2d

Browse files
committed
Add TweakHexDecodeError for hex decoding
Introduces a new error type to properly handle hex decoding failures in blinding factor conversions, replacing unsafe transmute workarounds with idiomatic error handling.
1 parent 1d6f947 commit 3536c2d

File tree

1 file changed

+58
-29
lines changed

1 file changed

+58
-29
lines changed

src/confidential.rs

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use secp256k1_zkp::{
2929
#[cfg(feature = "serde")]
3030
use serde::{Deserialize, Deserializer, Serialize, Serializer};
3131

32-
use std::mem;
3332
use std::{
3433
fmt, io,
3534
ops::{AddAssign, Neg},
@@ -712,6 +711,60 @@ impl<'de> Deserialize<'de> for Nonce {
712711
}
713712
}
714713

714+
/// Error decoding hexadecimal string into tweak-like value.
715+
#[derive(Debug, Clone, PartialEq, Eq)]
716+
pub enum TweakHexDecodeError {
717+
/// Invalid hexadecimal string.
718+
InvalidHex(hex_conservative::DecodeFixedLengthBytesError),
719+
/// Invalid tweak after decoding hexadecimal string.
720+
InvalidTweak(secp256k1_zkp::Error),
721+
}
722+
723+
impl fmt::Display for TweakHexDecodeError {
724+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
725+
match self {
726+
TweakHexDecodeError::InvalidHex(err) => {
727+
write!(f, "Invalid hex: {}", err)
728+
}
729+
TweakHexDecodeError::InvalidTweak(err) => {
730+
write!(f, "Invalid tweak: {}", err)
731+
}
732+
}
733+
}
734+
}
735+
736+
#[doc(hidden)]
737+
impl From<hex_conservative::DecodeFixedLengthBytesError> for TweakHexDecodeError {
738+
fn from(err: hex_conservative::DecodeFixedLengthBytesError) -> Self {
739+
TweakHexDecodeError::InvalidHex(err)
740+
}
741+
}
742+
743+
#[doc(hidden)]
744+
impl From<secp256k1_zkp::Error> for TweakHexDecodeError {
745+
fn from(err: secp256k1_zkp::Error) -> Self {
746+
TweakHexDecodeError::InvalidTweak(err)
747+
}
748+
}
749+
750+
impl From<TweakHexDecodeError> for encode::Error {
751+
fn from(value: TweakHexDecodeError) -> Self {
752+
match value {
753+
TweakHexDecodeError::InvalidHex(err) => encode::Error::HexFixedError(err),
754+
TweakHexDecodeError::InvalidTweak(err) => encode::Error::Secp256k1zkp(err),
755+
}
756+
}
757+
}
758+
759+
impl std::error::Error for TweakHexDecodeError {
760+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
761+
match self {
762+
TweakHexDecodeError::InvalidHex(err) => Some(err),
763+
TweakHexDecodeError::InvalidTweak(err) => Some(err),
764+
}
765+
}
766+
}
767+
715768
/// Blinding factor used for asset commitments.
716769
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
717770
pub struct AssetBlindingFactor(pub(crate) Tweak);
@@ -739,24 +792,12 @@ impl AssetBlindingFactor {
739792
}
740793

741794
impl hex::FromHex for AssetBlindingFactor {
742-
type Error = hex_conservative::DecodeFixedLengthBytesError;
795+
type Error = TweakHexDecodeError;
743796

744797
fn from_hex(s: &str) -> Result<Self, Self::Error> {
745798
let slice: [u8; 32] = decode_to_array(s)?;
746799

747-
let inner = Tweak::from_inner(slice).map_err(|_e| {
748-
// FIXME(Velnbur): hex_conservative disallows creation of it's internal errors
749-
// that's why we use this unsafe hack to make it compile
750-
//
751-
// Also, this is incorrect Return Error
752-
// See: https://github.com/rust-bitcoin/bitcoin_hashes/issues/124
753-
let error = unsafe {
754-
mem::transmute::<(u8, usize), hex_conservative::error::InvalidCharError>((
755-
0u8, 0usize,
756-
))
757-
};
758-
hex_conservative::DecodeFixedLengthBytesError::InvalidChar(error)
759-
})?;
800+
let inner = Tweak::from_inner(slice)?;
760801
Ok(AssetBlindingFactor(inner))
761802
}
762803
}
@@ -956,23 +997,11 @@ impl Neg for ValueBlindingFactor {
956997
}
957998

958999
impl hex::FromHex for ValueBlindingFactor {
959-
type Error = hex_conservative::DecodeFixedLengthBytesError;
1000+
type Error = TweakHexDecodeError;
9601001

9611002
fn from_hex(s: &str) -> Result<Self, Self::Error> {
9621003
let slice: [u8; 32] = decode_to_array(s)?;
963-
let inner = Tweak::from_inner(slice).map_err(|_e| {
964-
// FIXME(Velnbur): hex_conservative disallows creation of it's internal errors
965-
// that's why we use this unsafe hack to make it compile
966-
//
967-
// Also, this is incorrect Return Error
968-
// See: https://github.com/rust-bitcoin/bitcoin_hashes/issues/124
969-
let error = unsafe {
970-
mem::transmute::<(u8, usize), hex_conservative::error::InvalidCharError>((
971-
0u8, 0usize,
972-
))
973-
};
974-
hex_conservative::DecodeFixedLengthBytesError::InvalidChar(error)
975-
})?;
1004+
let inner = Tweak::from_inner(slice)?;
9761005
Ok(ValueBlindingFactor(inner))
9771006
}
9781007
}

0 commit comments

Comments
 (0)