Fix wrong newtype APIs
This fixes several API bugs: * Use `TryFrom` instead of `From` for fallible conversions * Move byte conversion methods from `impl_array_newtype` to `impl_bytes_newtype` * Add missing trait impls like `AsRef`, `Borrow`, their mutable versions and infallible conversions from arrays Closes #1336
This commit is contained in:
parent
7fee6239e1
commit
64f7d2549e
|
@ -33,6 +33,12 @@ pub struct ChainCode([u8; 32]);
|
||||||
impl_array_newtype!(ChainCode, u8, 32);
|
impl_array_newtype!(ChainCode, u8, 32);
|
||||||
impl_bytes_newtype!(ChainCode, 32);
|
impl_bytes_newtype!(ChainCode, 32);
|
||||||
|
|
||||||
|
impl ChainCode {
|
||||||
|
fn from_hmac(hmac: Hmac<sha512::Hash>) -> Self {
|
||||||
|
hmac[32..].try_into().expect("half of hmac is guaranteed to be 32 bytes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A fingerprint
|
/// A fingerprint
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct Fingerprint([u8; 4]);
|
pub struct Fingerprint([u8; 4]);
|
||||||
|
@ -523,7 +529,7 @@ impl ExtendedPrivKey {
|
||||||
parent_fingerprint: Default::default(),
|
parent_fingerprint: Default::default(),
|
||||||
child_number: ChildNumber::from_normal_idx(0)?,
|
child_number: ChildNumber::from_normal_idx(0)?,
|
||||||
private_key: secp256k1::SecretKey::from_slice(&hmac_result[..32])?,
|
private_key: secp256k1::SecretKey::from_slice(&hmac_result[..32])?,
|
||||||
chain_code: ChainCode::from(&hmac_result[32..]),
|
chain_code: ChainCode::from_hmac(hmac_result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,7 +594,7 @@ impl ExtendedPrivKey {
|
||||||
parent_fingerprint: self.fingerprint(secp),
|
parent_fingerprint: self.fingerprint(secp),
|
||||||
child_number: i,
|
child_number: i,
|
||||||
private_key: tweaked,
|
private_key: tweaked,
|
||||||
chain_code: ChainCode::from(&hmac_result[32..]),
|
chain_code: ChainCode::from_hmac(hmac_result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,9 +617,9 @@ impl ExtendedPrivKey {
|
||||||
Ok(ExtendedPrivKey {
|
Ok(ExtendedPrivKey {
|
||||||
network,
|
network,
|
||||||
depth: data[4],
|
depth: data[4],
|
||||||
parent_fingerprint: Fingerprint::from(&data[5..9]),
|
parent_fingerprint: data[5..9].try_into().expect("9 - 5 == 4, which is the Fingerprint length"),
|
||||||
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
|
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
|
||||||
chain_code: ChainCode::from(&data[13..45]),
|
chain_code: data[13..45].try_into().expect("45 - 13 == 32, which is the ChainCode length"),
|
||||||
private_key: secp256k1::SecretKey::from_slice(&data[46..78])?,
|
private_key: secp256k1::SecretKey::from_slice(&data[46..78])?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -643,7 +649,7 @@ impl ExtendedPrivKey {
|
||||||
|
|
||||||
/// Returns the first four bytes of the identifier
|
/// Returns the first four bytes of the identifier
|
||||||
pub fn fingerprint<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> Fingerprint {
|
pub fn fingerprint<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> Fingerprint {
|
||||||
Fingerprint::from(&self.identifier(secp)[0..4])
|
self.identifier(secp)[0..4].try_into().expect("4 is the fingerprint length")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,7 +707,7 @@ impl ExtendedPubKey {
|
||||||
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
||||||
|
|
||||||
let private_key = secp256k1::SecretKey::from_slice(&hmac_result[..32])?;
|
let private_key = secp256k1::SecretKey::from_slice(&hmac_result[..32])?;
|
||||||
let chain_code = ChainCode::from(&hmac_result[32..]);
|
let chain_code = ChainCode::from_hmac(hmac_result);
|
||||||
Ok((private_key, chain_code))
|
Ok((private_key, chain_code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -743,9 +749,9 @@ impl ExtendedPubKey {
|
||||||
return Err(Error::UnknownVersion(ver));
|
return Err(Error::UnknownVersion(ver));
|
||||||
},
|
},
|
||||||
depth: data[4],
|
depth: data[4],
|
||||||
parent_fingerprint: Fingerprint::from(&data[5..9]),
|
parent_fingerprint: data[5..9].try_into().expect("9 - 5 == 4, which is the Fingerprint length"),
|
||||||
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
|
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
|
||||||
chain_code: ChainCode::from(&data[13..45]),
|
chain_code: data[13..45].try_into().expect("45 - 13 == 32, which is the ChainCode length"),
|
||||||
public_key: secp256k1::PublicKey::from_slice(&data[45..78])?,
|
public_key: secp256k1::PublicKey::from_slice(&data[45..78])?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -775,7 +781,7 @@ impl ExtendedPubKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first four bytes of the identifier
|
/// Returns the first four bytes of the identifier
|
||||||
pub fn fingerprint(&self) -> Fingerprint { Fingerprint::from(&self.identifier()[0..4]) }
|
pub fn fingerprint(&self) -> Fingerprint { self.identifier()[0..4].try_into().expect("4 is the fingerprint length") }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ExtendedPrivKey {
|
impl fmt::Display for ExtendedPrivKey {
|
||||||
|
@ -1108,10 +1114,10 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub fn encode_fingerprint_chaincode() {
|
pub fn encode_fingerprint_chaincode() {
|
||||||
use serde_json;
|
use serde_json;
|
||||||
let fp = Fingerprint::from(&[1u8, 2, 3, 42][..]);
|
let fp = Fingerprint::from([1u8, 2, 3, 42]);
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let cc = ChainCode::from(
|
let cc = ChainCode::from(
|
||||||
&[1u8,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2][..]
|
[1u8,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]
|
||||||
);
|
);
|
||||||
|
|
||||||
serde_round_trip!(fp);
|
serde_round_trip!(fp);
|
||||||
|
@ -1156,7 +1162,7 @@ mod tests {
|
||||||
parent_fingerprint: Default::default(),
|
parent_fingerprint: Default::default(),
|
||||||
child_number: ChildNumber::Normal { index: 0 },
|
child_number: ChildNumber::Normal { index: 0 },
|
||||||
private_key: sk,
|
private_key: sk,
|
||||||
chain_code: ChainCode::from(&[0u8; 32][..])
|
chain_code: ChainCode::from([0u8; 32])
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{}", xpriv);
|
println!("{}", xpriv);
|
||||||
|
|
|
@ -115,6 +115,23 @@ mod test_macros {
|
||||||
/// - hashes::hex::FromHex
|
/// - hashes::hex::FromHex
|
||||||
macro_rules! impl_bytes_newtype {
|
macro_rules! impl_bytes_newtype {
|
||||||
($t:ident, $len:literal) => {
|
($t:ident, $len:literal) => {
|
||||||
|
impl $t {
|
||||||
|
/// Returns a reference the underlying bytes.
|
||||||
|
#[inline]
|
||||||
|
pub fn as_bytes(&self) -> &[u8; $len] { &self.0 }
|
||||||
|
|
||||||
|
/// Returns the underlying bytes.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_bytes(self) -> [u8; $len] {
|
||||||
|
// We rely on `Copy` being implemented for $t so conversion
|
||||||
|
// methods use the correct Rust naming conventions.
|
||||||
|
fn check_copy<T: Copy>() {}
|
||||||
|
check_copy::<$t>();
|
||||||
|
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
for &ch in self.0.iter() {
|
for &ch in self.0.iter() {
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl PartiallySignedTransaction {
|
||||||
}
|
}
|
||||||
let derivation = DerivationPath::from(path);
|
let derivation = DerivationPath::from(path);
|
||||||
// Keys, according to BIP-174, must be unique
|
// Keys, according to BIP-174, must be unique
|
||||||
if xpub_map.insert(xpub, (Fingerprint::from(&fingerprint[..]), derivation)).is_some() {
|
if xpub_map.insert(xpub, (Fingerprint::from(fingerprint), derivation)).is_some() {
|
||||||
return Err(encode::Error::ParseFailed("Repeated global xpub key"))
|
return Err(encode::Error::ParseFailed("Repeated global xpub key"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
//! bytes from/as PSBT key-value pairs.
|
//! bytes from/as PSBT key-value pairs.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use core::convert::TryInto;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::io;
|
use crate::io;
|
||||||
|
@ -150,7 +152,7 @@ impl Deserialize for KeySource {
|
||||||
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
let fprint: Fingerprint = Fingerprint::from(&bytes[0..4]);
|
let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length");
|
||||||
let mut dpath: Vec<ChildNumber> = Default::default();
|
let mut dpath: Vec<ChildNumber> = Default::default();
|
||||||
|
|
||||||
let mut d = &bytes[4..];
|
let mut d = &bytes[4..];
|
||||||
|
|
|
@ -27,29 +27,76 @@ macro_rules! impl_array_newtype {
|
||||||
/// Returns whether the object, as an array, is empty. Always false.
|
/// Returns whether the object, as an array, is empty. Always false.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool { false }
|
pub fn is_empty(&self) -> bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference the underlying bytes.
|
impl<'a> core::convert::From<[$ty; $len]> for $thing {
|
||||||
#[inline]
|
fn from(data: [$ty; $len]) -> Self {
|
||||||
pub fn as_bytes(&self) -> &[$ty; $len] { &self.0 }
|
$thing(data)
|
||||||
|
|
||||||
/// Returns the underlying bytes.
|
|
||||||
#[inline]
|
|
||||||
pub fn to_bytes(self) -> [$ty; $len] {
|
|
||||||
// We rely on `Copy` being implemented for $thing so conversion
|
|
||||||
// methods use the correct Rust naming conventions.
|
|
||||||
fn check_copy<T: Copy>() {}
|
|
||||||
check_copy::<$thing>();
|
|
||||||
|
|
||||||
self.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> core::convert::From<&'a [$ty]> for $thing {
|
impl<'a> core::convert::From<&'a [$ty; $len]> for $thing {
|
||||||
fn from(data: &'a [$ty]) -> $thing {
|
fn from(data: &'a [$ty; $len]) -> Self {
|
||||||
assert_eq!(data.len(), $len);
|
$thing(*data)
|
||||||
let mut ret = [0; $len];
|
}
|
||||||
ret.copy_from_slice(&data[..]);
|
}
|
||||||
$thing(ret)
|
|
||||||
|
impl<'a> core::convert::TryFrom<&'a [$ty]> for $thing {
|
||||||
|
type Error = core::array::TryFromSliceError;
|
||||||
|
|
||||||
|
fn try_from(data: &'a [$ty]) -> Result<Self, Self::Error> {
|
||||||
|
use core::convert::TryInto;
|
||||||
|
|
||||||
|
Ok($thing(data.try_into()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[$ty; $len]> for $thing {
|
||||||
|
fn as_ref(&self) -> &[$ty; $len] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[$ty; $len]> for $thing {
|
||||||
|
fn as_mut(&mut self) -> &mut [$ty; $len] {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[$ty]> for $thing {
|
||||||
|
fn as_ref(&self) -> &[$ty] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[$ty]> for $thing {
|
||||||
|
fn as_mut(&mut self) -> &mut [$ty] {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::borrow::Borrow<[$ty; $len]> for $thing {
|
||||||
|
fn borrow(&self) -> &[$ty; $len] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::borrow::BorrowMut<[$ty; $len]> for $thing {
|
||||||
|
fn borrow_mut(&mut self) -> &mut [$ty; $len] {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following two are valid because `[T; N]: Borrow<[T]>`
|
||||||
|
impl core::borrow::Borrow<[$ty]> for $thing {
|
||||||
|
fn borrow(&self) -> &[$ty] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::borrow::BorrowMut<[$ty]> for $thing {
|
||||||
|
fn borrow_mut(&mut self) -> &mut [$ty] {
|
||||||
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue