bip32: split out DerivationError from the main error enum
This is a breaking change to the API of the deprecated `derive_pub` function, but it's in a way that's unlikely to break consumers (who are probably just .expect'ing the result) so we will retain the deprecated function.
This commit is contained in:
parent
32d96f6c33
commit
f0a237c001
|
@ -497,8 +497,6 @@ pub type KeySource = (Fingerprint, DerivationPath);
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// A pk->pk derivation was attempted on a hardened key
|
|
||||||
CannotDeriveFromHardenedKey,
|
|
||||||
/// A secp256k1 error occurred
|
/// A secp256k1 error occurred
|
||||||
Secp256k1(secp256k1::Error),
|
Secp256k1(secp256k1::Error),
|
||||||
/// A child number was provided that was out of range
|
/// A child number was provided that was out of range
|
||||||
|
@ -536,8 +534,6 @@ impl fmt::Display for Error {
|
||||||
use Error::*;
|
use Error::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
CannotDeriveFromHardenedKey =>
|
|
||||||
f.write_str("cannot derive hardened key from public key"),
|
|
||||||
Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e),
|
Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e),
|
||||||
InvalidChildNumber(ref n) =>
|
InvalidChildNumber(ref n) =>
|
||||||
write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
|
write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
|
||||||
|
@ -570,8 +566,7 @@ impl std::error::Error for Error {
|
||||||
Base58(ref e) => Some(e),
|
Base58(ref e) => Some(e),
|
||||||
Hex(ref e) => Some(e),
|
Hex(ref e) => Some(e),
|
||||||
InvalidBase58PayloadLength(ref e) => Some(e),
|
InvalidBase58PayloadLength(ref e) => Some(e),
|
||||||
CannotDeriveFromHardenedKey
|
InvalidChildNumber(_)
|
||||||
| InvalidChildNumber(_)
|
|
||||||
| InvalidChildNumberFormat
|
| InvalidChildNumberFormat
|
||||||
| InvalidDerivationPathFormat
|
| InvalidDerivationPathFormat
|
||||||
| UnknownVersion(_)
|
| UnknownVersion(_)
|
||||||
|
@ -596,6 +591,33 @@ impl From<InvalidBase58PayloadLengthError> for Error {
|
||||||
fn from(e: InvalidBase58PayloadLengthError) -> Error { Self::InvalidBase58PayloadLength(e) }
|
fn from(e: InvalidBase58PayloadLengthError) -> Error { Self::InvalidBase58PayloadLength(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A BIP32 error
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum DerivationError {
|
||||||
|
/// Attempted to derive a hardened child from an xpub.
|
||||||
|
///
|
||||||
|
/// You can only derive hardened children from xprivs.
|
||||||
|
CannotDeriveHardenedChild,
|
||||||
|
/// Attempted to derive a child of depth 256 or higher.
|
||||||
|
///
|
||||||
|
/// There is no way to encode such xkeys.
|
||||||
|
MaximumDepthExceeded,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for DerivationError {}
|
||||||
|
|
||||||
|
impl fmt::Display for DerivationError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Self::CannotDeriveHardenedChild =>
|
||||||
|
f.write_str("cannot derive hardened child of public key"),
|
||||||
|
Self::MaximumDepthExceeded => f.write_str("cannot derive child of depth 256 or higher"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Xpriv {
|
impl Xpriv {
|
||||||
/// Constructs a new master key from a seed value
|
/// Constructs a new master key from a seed value
|
||||||
pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Xpriv {
|
pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Xpriv {
|
||||||
|
@ -795,7 +817,7 @@ impl Xpub {
|
||||||
&self,
|
&self,
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
path: &P,
|
path: &P,
|
||||||
) -> Result<Xpub, Error> {
|
) -> Result<Xpub, DerivationError> {
|
||||||
self.derive_xpub(secp, path)
|
self.derive_xpub(secp, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,7 +828,7 @@ impl Xpub {
|
||||||
&self,
|
&self,
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
path: &P,
|
path: &P,
|
||||||
) -> Result<Xpub, Error> {
|
) -> Result<Xpub, DerivationError> {
|
||||||
let mut pk: Xpub = *self;
|
let mut pk: Xpub = *self;
|
||||||
for cnum in path.as_ref() {
|
for cnum in path.as_ref() {
|
||||||
pk = pk.ckd_pub(secp, *cnum)?
|
pk = pk.ckd_pub(secp, *cnum)?
|
||||||
|
@ -818,9 +840,9 @@ impl Xpub {
|
||||||
pub fn ckd_pub_tweak(
|
pub fn ckd_pub_tweak(
|
||||||
&self,
|
&self,
|
||||||
i: ChildNumber,
|
i: ChildNumber,
|
||||||
) -> Result<(secp256k1::SecretKey, ChainCode), Error> {
|
) -> Result<(secp256k1::SecretKey, ChainCode), DerivationError> {
|
||||||
match i {
|
match i {
|
||||||
ChildNumber::Hardened { .. } => Err(Error::CannotDeriveFromHardenedKey),
|
ChildNumber::Hardened { .. } => Err(DerivationError::CannotDeriveHardenedChild),
|
||||||
ChildNumber::Normal { index: n } => {
|
ChildNumber::Normal { index: n } => {
|
||||||
let mut engine = HmacEngine::<sha512::HashEngine>::new(&self.chain_code[..]);
|
let mut engine = HmacEngine::<sha512::HashEngine>::new(&self.chain_code[..]);
|
||||||
engine.input(&self.public_key.serialize()[..]);
|
engine.input(&self.public_key.serialize()[..]);
|
||||||
|
@ -842,7 +864,7 @@ impl Xpub {
|
||||||
&self,
|
&self,
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
i: ChildNumber,
|
i: ChildNumber,
|
||||||
) -> Result<Xpub, Error> {
|
) -> Result<Xpub, DerivationError> {
|
||||||
let (sk, chain_code) = self.ckd_pub_tweak(i)?;
|
let (sk, chain_code) = self.ckd_pub_tweak(i)?;
|
||||||
let tweaked =
|
let tweaked =
|
||||||
self.public_key.add_exp_tweak(secp, &sk.into()).expect("cryptographically unreachable");
|
self.public_key.add_exp_tweak(secp, &sk.into()).expect("cryptographically unreachable");
|
||||||
|
@ -1120,7 +1142,10 @@ mod tests {
|
||||||
// Check derivation convenience method for Xpub, should error
|
// Check derivation convenience method for Xpub, should error
|
||||||
// appropriately if any ChildNumber is hardened
|
// appropriately if any ChildNumber is hardened
|
||||||
if path.0.iter().any(|cnum| cnum.is_hardened()) {
|
if path.0.iter().any(|cnum| cnum.is_hardened()) {
|
||||||
assert_eq!(pk.derive_xpub(secp, &path), Err(Error::CannotDeriveFromHardenedKey));
|
assert_eq!(
|
||||||
|
pk.derive_xpub(secp, &path),
|
||||||
|
Err(DerivationError::CannotDeriveHardenedChild)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(&pk.derive_xpub(secp, &path).unwrap().to_string()[..], expected_pk);
|
assert_eq!(&pk.derive_xpub(secp, &path).unwrap().to_string()[..], expected_pk);
|
||||||
}
|
}
|
||||||
|
@ -1135,7 +1160,10 @@ mod tests {
|
||||||
assert_eq!(pk, pk2);
|
assert_eq!(pk, pk2);
|
||||||
}
|
}
|
||||||
Hardened { .. } => {
|
Hardened { .. } => {
|
||||||
assert_eq!(pk.ckd_pub(secp, num), Err(Error::CannotDeriveFromHardenedKey));
|
assert_eq!(
|
||||||
|
pk.ckd_pub(secp, num),
|
||||||
|
Err(DerivationError::CannotDeriveHardenedChild)
|
||||||
|
);
|
||||||
pk = Xpub::from_xpriv(secp, &sk);
|
pk = Xpub::from_xpriv(secp, &sk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue