Merge rust-bitcoin/rust-bitcoin#1208: Move bip32 module to crate root
8bed2ddffe
Run formmater on bip32 (Tobin C. Harding)34113c9558
Move bip32 module to crate root (Tobin C. Harding) Pull request description: We are attempting to flatten the `util` module. Move the `bip32` module to the crate root out of `util`. Currently `src/util/` is ignored by the formatter so this move requires `bip32` module to be formatted. Formatting is done as a separate patch so reviewers can run `cargo +nightly fmt` and compare the diffs if so desired. ACKs for top commit: apoelstra: ACK8bed2ddffe
Kixunil: ACK8bed2ddffe
Tree-SHA512: dadea31be0459fd10e71927bd21dc44b59428f695a6df7093052ca7257b6590d5dd5b1343a89869ac9f4d7805dbca7558b475048ea9387c36265f14246cc6852
This commit is contained in:
commit
b1869803bf
|
@ -7,22 +7,24 @@
|
|||
//! at <https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki>.
|
||||
//!
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::io::Write;
|
||||
use core::{fmt, str::FromStr, default::Default};
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::ops::Index;
|
||||
#[cfg(feature = "serde")] use serde;
|
||||
use core::str::FromStr;
|
||||
|
||||
use bitcoin_internals::write_err;
|
||||
use crate::hash_types::XpubIdentifier;
|
||||
use crate::hashes::{sha512, Hash, HashEngine, Hmac, HmacEngine, hex};
|
||||
use secp256k1::{self, Secp256k1, XOnlyPublicKey};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde;
|
||||
|
||||
use crate::network::constants::Network;
|
||||
use crate::util::{base58, endian, key};
|
||||
use crate::util::key::{PublicKey, PrivateKey, KeyPair};
|
||||
use crate::hash_types::XpubIdentifier;
|
||||
use crate::hashes::{hex, sha512, Hash, HashEngine, Hmac, HmacEngine};
|
||||
use crate::internal_macros::{impl_array_newtype, impl_bytes_newtype, serde_string_impl};
|
||||
use crate::io::Write;
|
||||
use crate::network::constants::Network;
|
||||
use crate::prelude::*;
|
||||
use crate::util::key::{KeyPair, PrivateKey, PublicKey};
|
||||
use crate::util::{base58, endian, key};
|
||||
|
||||
/// A chain code
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
@ -51,7 +53,7 @@ pub struct ExtendedPrivKey {
|
|||
/// Private key
|
||||
pub private_key: secp256k1::SecretKey,
|
||||
/// Chain code
|
||||
pub chain_code: ChainCode
|
||||
pub chain_code: ChainCode,
|
||||
}
|
||||
serde_string_impl!(ExtendedPrivKey, "a BIP-32 extended private key");
|
||||
|
||||
|
@ -84,7 +86,7 @@ pub struct ExtendedPubKey {
|
|||
/// Public key
|
||||
pub public_key: secp256k1::PublicKey,
|
||||
/// Chain code
|
||||
pub chain_code: ChainCode
|
||||
pub chain_code: ChainCode,
|
||||
}
|
||||
serde_string_impl!(ExtendedPubKey, "a BIP-32 extended public key");
|
||||
|
||||
|
@ -94,12 +96,12 @@ pub enum ChildNumber {
|
|||
/// Non-hardened key
|
||||
Normal {
|
||||
/// Key index, within [0, 2^31 - 1]
|
||||
index: u32
|
||||
index: u32,
|
||||
},
|
||||
/// Hardened key
|
||||
Hardened {
|
||||
/// Key index, within [0, 2^31 - 1]
|
||||
index: u32
|
||||
index: u32,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -131,25 +133,23 @@ impl ChildNumber {
|
|||
/// Returns `true` if the child number is a [`Normal`] value.
|
||||
///
|
||||
/// [`Normal`]: #variant.Normal
|
||||
pub fn is_normal(&self) -> bool {
|
||||
!self.is_hardened()
|
||||
}
|
||||
pub fn is_normal(&self) -> bool { !self.is_hardened() }
|
||||
|
||||
/// Returns `true` if the child number is a [`Hardened`] value.
|
||||
///
|
||||
/// [`Hardened`]: #variant.Hardened
|
||||
pub fn is_hardened(&self) -> bool {
|
||||
match self {
|
||||
ChildNumber::Hardened {..} => true,
|
||||
ChildNumber::Normal {..} => false,
|
||||
ChildNumber::Hardened { .. } => true,
|
||||
ChildNumber::Normal { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the child number that is a single increment from this one.
|
||||
pub fn increment(self) -> Result<ChildNumber, Error> {
|
||||
match self {
|
||||
ChildNumber::Normal{ index: idx } => ChildNumber::from_normal_idx(idx+1),
|
||||
ChildNumber::Hardened{ index: idx } => ChildNumber::from_hardened_idx(idx+1),
|
||||
ChildNumber::Normal { index: idx } => ChildNumber::from_normal_idx(idx + 1),
|
||||
ChildNumber::Hardened { index: idx } => ChildNumber::from_hardened_idx(idx + 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ impl fmt::Display for ChildNumber {
|
|||
fmt::Display::fmt(&index, f)?;
|
||||
let alt = f.alternate();
|
||||
f.write_str(if alt { "h" } else { "'" })
|
||||
},
|
||||
}
|
||||
ChildNumber::Normal { index } => fmt::Display::fmt(&index, f),
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,9 @@ impl FromStr for ChildNumber {
|
|||
fn from_str(inp: &str) -> Result<ChildNumber, Error> {
|
||||
let is_hardened = inp.chars().last().map_or(false, |l| l == '\'' || l == 'h');
|
||||
Ok(if is_hardened {
|
||||
ChildNumber::from_hardened_idx(inp[0..inp.len() - 1].parse().map_err(|_| Error::InvalidChildNumberFormat)?)?
|
||||
ChildNumber::from_hardened_idx(
|
||||
inp[0..inp.len() - 1].parse().map_err(|_| Error::InvalidChildNumberFormat)?,
|
||||
)?
|
||||
} else {
|
||||
ChildNumber::from_normal_idx(inp.parse().map_err(|_| Error::InvalidChildNumberFormat)?)?
|
||||
})
|
||||
|
@ -240,55 +242,45 @@ where
|
|||
type Output = <Vec<ChildNumber> as Index<I>>::Output;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: I) -> &Self::Output {
|
||||
&self.0[index]
|
||||
}
|
||||
fn index(&self, index: I) -> &Self::Output { &self.0[index] }
|
||||
}
|
||||
|
||||
impl Default for DerivationPath {
|
||||
fn default() -> DerivationPath {
|
||||
DerivationPath::master()
|
||||
}
|
||||
fn default() -> DerivationPath { DerivationPath::master() }
|
||||
}
|
||||
|
||||
impl<T> IntoDerivationPath for T where T: Into<DerivationPath> {
|
||||
fn into_derivation_path(self) -> Result<DerivationPath, Error> {
|
||||
Ok(self.into())
|
||||
}
|
||||
impl<T> IntoDerivationPath for T
|
||||
where
|
||||
T: Into<DerivationPath>,
|
||||
{
|
||||
fn into_derivation_path(self) -> Result<DerivationPath, Error> { Ok(self.into()) }
|
||||
}
|
||||
|
||||
impl IntoDerivationPath for String {
|
||||
fn into_derivation_path(self) -> Result<DerivationPath, Error> {
|
||||
self.parse()
|
||||
}
|
||||
fn into_derivation_path(self) -> Result<DerivationPath, Error> { self.parse() }
|
||||
}
|
||||
|
||||
impl<'a> IntoDerivationPath for &'a str {
|
||||
fn into_derivation_path(self) -> Result<DerivationPath, Error> {
|
||||
self.parse()
|
||||
}
|
||||
fn into_derivation_path(self) -> Result<DerivationPath, Error> { self.parse() }
|
||||
}
|
||||
|
||||
impl From<Vec<ChildNumber>> for DerivationPath {
|
||||
fn from(numbers: Vec<ChildNumber>) -> Self {
|
||||
DerivationPath(numbers)
|
||||
}
|
||||
fn from(numbers: Vec<ChildNumber>) -> Self { DerivationPath(numbers) }
|
||||
}
|
||||
|
||||
impl From<DerivationPath> for Vec<ChildNumber> {
|
||||
fn from(path: DerivationPath) -> Self {
|
||||
path.0
|
||||
}
|
||||
fn from(path: DerivationPath) -> Self { path.0 }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [ChildNumber]> for DerivationPath {
|
||||
fn from(numbers: &'a [ChildNumber]) -> Self {
|
||||
DerivationPath(numbers.to_vec())
|
||||
}
|
||||
fn from(numbers: &'a [ChildNumber]) -> Self { DerivationPath(numbers.to_vec()) }
|
||||
}
|
||||
|
||||
impl core::iter::FromIterator<ChildNumber> for DerivationPath {
|
||||
fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item=ChildNumber> {
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where
|
||||
T: IntoIterator<Item = ChildNumber>,
|
||||
{
|
||||
DerivationPath(Vec::from_iter(iter))
|
||||
}
|
||||
}
|
||||
|
@ -296,15 +288,11 @@ impl core::iter::FromIterator<ChildNumber> for DerivationPath {
|
|||
impl<'a> core::iter::IntoIterator for &'a DerivationPath {
|
||||
type Item = &'a ChildNumber;
|
||||
type IntoIter = slice::Iter<'a, ChildNumber>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter()
|
||||
}
|
||||
fn into_iter(self) -> Self::IntoIter { self.0.iter() }
|
||||
}
|
||||
|
||||
impl AsRef<[ChildNumber]> for DerivationPath {
|
||||
fn as_ref(&self) -> &[ChildNumber] {
|
||||
&self.0
|
||||
}
|
||||
fn as_ref(&self) -> &[ChildNumber] { &self.0 }
|
||||
}
|
||||
|
||||
impl FromStr for DerivationPath {
|
||||
|
@ -334,10 +322,7 @@ pub struct DerivationPathIterator<'a> {
|
|||
impl<'a> DerivationPathIterator<'a> {
|
||||
/// Start a new [DerivationPathIterator] at the given child.
|
||||
pub fn start_from(path: &'a DerivationPath, start: ChildNumber) -> DerivationPathIterator<'a> {
|
||||
DerivationPathIterator {
|
||||
base: path,
|
||||
next_child: Some(start),
|
||||
}
|
||||
DerivationPathIterator { base: path, next_child: Some(start) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,25 +338,17 @@ impl<'a> Iterator for DerivationPathIterator<'a> {
|
|||
|
||||
impl DerivationPath {
|
||||
/// Returns length of the derivation path
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
pub fn len(&self) -> usize { self.0.len() }
|
||||
|
||||
/// Returns `true` if the derivation path is empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool { self.0.is_empty() }
|
||||
|
||||
/// Returns derivation path for a master key (i.e. empty derivation path)
|
||||
pub fn master() -> DerivationPath {
|
||||
DerivationPath(vec![])
|
||||
}
|
||||
pub fn master() -> DerivationPath { DerivationPath(vec![]) }
|
||||
|
||||
/// Returns whether derivation path represents master key (i.e. it's length
|
||||
/// is empty). True for `m` path.
|
||||
pub fn is_master(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
pub fn is_master(&self) -> bool { self.0.is_empty() }
|
||||
|
||||
/// Create a new [DerivationPath] that is a child of this one.
|
||||
pub fn child(&self, cn: ChildNumber) -> DerivationPath {
|
||||
|
@ -395,12 +372,12 @@ impl DerivationPath {
|
|||
|
||||
/// Get an [Iterator] over the unhardened children of this [DerivationPath].
|
||||
pub fn normal_children(&self) -> DerivationPathIterator {
|
||||
DerivationPathIterator::start_from(self, ChildNumber::Normal{ index: 0 })
|
||||
DerivationPathIterator::start_from(self, ChildNumber::Normal { index: 0 })
|
||||
}
|
||||
|
||||
/// Get an [Iterator] over the hardened children of this [DerivationPath].
|
||||
pub fn hardened_children(&self) -> DerivationPathIterator {
|
||||
DerivationPathIterator::start_from(self, ChildNumber::Hardened{ index: 0 })
|
||||
DerivationPathIterator::start_from(self, ChildNumber::Hardened { index: 0 })
|
||||
}
|
||||
|
||||
/// Concatenate `self` with `path` and return the resulting new path.
|
||||
|
@ -438,9 +415,7 @@ impl fmt::Display for DerivationPath {
|
|||
}
|
||||
|
||||
impl fmt::Debug for DerivationPath {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self, f)
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self, f) }
|
||||
}
|
||||
|
||||
/// Full information on the used extended public key: fingerprint of the
|
||||
|
@ -468,19 +443,23 @@ pub enum Error {
|
|||
/// Base58 encoding error
|
||||
Base58(base58::Error),
|
||||
/// Hexadecimal decoding error
|
||||
Hex(hex::Error)
|
||||
Hex(hex::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::CannotDeriveFromHardenedKey => f.write_str("cannot derive hardened key from public key"),
|
||||
Error::CannotDeriveFromHardenedKey =>
|
||||
f.write_str("cannot derive hardened key from public key"),
|
||||
Error::Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e),
|
||||
Error::InvalidChildNumber(ref n) => write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
|
||||
Error::InvalidChildNumber(ref n) =>
|
||||
write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
|
||||
Error::InvalidChildNumberFormat => f.write_str("invalid child number format"),
|
||||
Error::InvalidDerivationPathFormat => f.write_str("invalid derivation path format"),
|
||||
Error::UnknownVersion(ref bytes) => write!(f, "unknown version magic bytes: {:?}", bytes),
|
||||
Error::WrongExtendedKeyLength(ref len) => write!(f, "encoded extended key data has wrong length {}", len),
|
||||
Error::UnknownVersion(ref bytes) =>
|
||||
write!(f, "unknown version magic bytes: {:?}", bytes),
|
||||
Error::WrongExtendedKeyLength(ref len) =>
|
||||
write!(f, "encoded extended key data has wrong length {}", len),
|
||||
Error::Base58(ref e) => write_err!(f, "base58 encoding error"; e),
|
||||
Error::Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e),
|
||||
}
|
||||
|
@ -513,7 +492,7 @@ impl From<key::Error> for Error {
|
|||
key::Error::Base58(e) => Error::Base58(e),
|
||||
key::Error::Secp256k1(e) => Error::Secp256k1(e),
|
||||
key::Error::InvalidKeyPrefix(_) => Error::Secp256k1(secp256k1::Error::InvalidPublicKey),
|
||||
key::Error::Hex(e) => Error::Hex(e)
|
||||
key::Error::Hex(e) => Error::Hex(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -523,9 +502,7 @@ impl From<secp256k1::Error> for Error {
|
|||
}
|
||||
|
||||
impl From<base58::Error> for Error {
|
||||
fn from(err: base58::Error) -> Self {
|
||||
Error::Base58(err)
|
||||
}
|
||||
fn from(err: base58::Error) -> Self { Error::Base58(err) }
|
||||
}
|
||||
|
||||
impl ExtendedPrivKey {
|
||||
|
@ -547,17 +524,14 @@ impl ExtendedPrivKey {
|
|||
|
||||
/// Constructs ECDSA compressed private key matching internal secret key representation.
|
||||
pub fn to_priv(self) -> PrivateKey {
|
||||
PrivateKey {
|
||||
compressed: true,
|
||||
network: self.network,
|
||||
inner: self.private_key
|
||||
}
|
||||
PrivateKey { compressed: true, network: self.network, inner: self.private_key }
|
||||
}
|
||||
|
||||
/// Constructs BIP340 keypair for Schnorr signatures and Taproot use matching the internal
|
||||
/// secret key representation.
|
||||
pub fn to_keypair<C: secp256k1::Signing>(self, secp: &Secp256k1<C>) -> KeyPair {
|
||||
KeyPair::from_seckey_slice(secp, &self.private_key[..]).expect("BIP32 internal private key representation is broken")
|
||||
KeyPair::from_seckey_slice(secp, &self.private_key[..])
|
||||
.expect("BIP32 internal private key representation is broken")
|
||||
}
|
||||
|
||||
/// Attempts to derive an extended private key from a path.
|
||||
|
@ -576,12 +550,18 @@ impl ExtendedPrivKey {
|
|||
}
|
||||
|
||||
/// Private->Private child key derivation
|
||||
pub fn ckd_priv<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>, i: ChildNumber) -> Result<ExtendedPrivKey, Error> {
|
||||
pub fn ckd_priv<C: secp256k1::Signing>(
|
||||
&self,
|
||||
secp: &Secp256k1<C>,
|
||||
i: ChildNumber,
|
||||
) -> Result<ExtendedPrivKey, Error> {
|
||||
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(&self.chain_code[..]);
|
||||
match i {
|
||||
ChildNumber::Normal { .. } => {
|
||||
// Non-hardened key: compute public data and use that
|
||||
hmac_engine.input(&secp256k1::PublicKey::from_secret_key(secp, &self.private_key).serialize()[..]);
|
||||
hmac_engine.input(
|
||||
&secp256k1::PublicKey::from_secret_key(secp, &self.private_key).serialize()[..],
|
||||
);
|
||||
}
|
||||
ChildNumber::Hardened { .. } => {
|
||||
// Hardened key: use only secret data to prevent public derivation
|
||||
|
@ -592,8 +572,10 @@ impl ExtendedPrivKey {
|
|||
|
||||
hmac_engine.input(&endian::u32_to_array_be(u32::from(i)));
|
||||
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
||||
let sk = secp256k1::SecretKey::from_slice(&hmac_result[..32]).expect("statistically impossible to hit");
|
||||
let tweaked = sk.add_tweak(&self.private_key.into()).expect("statistically impossible to hit");
|
||||
let sk = secp256k1::SecretKey::from_slice(&hmac_result[..32])
|
||||
.expect("statistically impossible to hit");
|
||||
let tweaked =
|
||||
sk.add_tweak(&self.private_key.into()).expect("statistically impossible to hit");
|
||||
|
||||
Ok(ExtendedPrivKey {
|
||||
network: self.network,
|
||||
|
@ -601,14 +583,14 @@ impl ExtendedPrivKey {
|
|||
parent_fingerprint: self.fingerprint(secp),
|
||||
child_number: i,
|
||||
private_key: tweaked,
|
||||
chain_code: ChainCode::from(&hmac_result[32..])
|
||||
chain_code: ChainCode::from(&hmac_result[32..]),
|
||||
})
|
||||
}
|
||||
|
||||
/// Decoding extended private key from binary data according to BIP 32
|
||||
pub fn decode(data: &[u8]) -> Result<ExtendedPrivKey, Error> {
|
||||
if data.len() != 78 {
|
||||
return Err(Error::WrongExtendedKeyLength(data.len()))
|
||||
return Err(Error::WrongExtendedKeyLength(data.len()));
|
||||
}
|
||||
|
||||
let network = if data[0..4] == [0x04u8, 0x88, 0xAD, 0xE4] {
|
||||
|
@ -634,10 +616,12 @@ impl ExtendedPrivKey {
|
|||
/// Extended private key binary encoding according to BIP 32
|
||||
pub fn encode(&self) -> [u8; 78] {
|
||||
let mut ret = [0; 78];
|
||||
ret[0..4].copy_from_slice(&match self.network {
|
||||
ret[0..4].copy_from_slice(
|
||||
&match self.network {
|
||||
Network::Bitcoin => [0x04, 0x88, 0xAD, 0xE4],
|
||||
Network::Testnet | Network::Signet | Network::Regtest => [0x04, 0x35, 0x83, 0x94],
|
||||
}[..]);
|
||||
}[..],
|
||||
);
|
||||
ret[4] = self.depth as u8;
|
||||
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
|
||||
ret[9..13].copy_from_slice(&endian::u32_to_array_be(u32::from(self.child_number)));
|
||||
|
@ -660,30 +644,26 @@ impl ExtendedPrivKey {
|
|||
|
||||
impl ExtendedPubKey {
|
||||
/// Derives a public key from a private key
|
||||
pub fn from_priv<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &ExtendedPrivKey) -> ExtendedPubKey {
|
||||
pub fn from_priv<C: secp256k1::Signing>(
|
||||
secp: &Secp256k1<C>,
|
||||
sk: &ExtendedPrivKey,
|
||||
) -> ExtendedPubKey {
|
||||
ExtendedPubKey {
|
||||
network: sk.network,
|
||||
depth: sk.depth,
|
||||
parent_fingerprint: sk.parent_fingerprint,
|
||||
child_number: sk.child_number,
|
||||
public_key: secp256k1::PublicKey::from_secret_key(secp, &sk.private_key),
|
||||
chain_code: sk.chain_code
|
||||
chain_code: sk.chain_code,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs ECDSA compressed public key matching internal public key representation.
|
||||
pub fn to_pub(self) -> PublicKey {
|
||||
PublicKey {
|
||||
compressed: true,
|
||||
inner: self.public_key
|
||||
}
|
||||
}
|
||||
pub fn to_pub(self) -> PublicKey { PublicKey { compressed: true, inner: self.public_key } }
|
||||
|
||||
/// Constructs BIP340 x-only public key for BIP-340 signatures and Taproot use matching
|
||||
/// the internal public key representation.
|
||||
pub fn to_x_only_pub(self) -> XOnlyPublicKey {
|
||||
XOnlyPublicKey::from(self.public_key)
|
||||
}
|
||||
pub fn to_x_only_pub(self) -> XOnlyPublicKey { XOnlyPublicKey::from(self.public_key) }
|
||||
|
||||
/// Attempts to derive an extended public key from a path.
|
||||
///
|
||||
|
@ -701,13 +681,15 @@ impl ExtendedPubKey {
|
|||
}
|
||||
|
||||
/// Compute the scalar tweak added to this key to get a child key
|
||||
pub fn ckd_pub_tweak(&self, i: ChildNumber) -> Result<(secp256k1::SecretKey, ChainCode), Error> {
|
||||
pub fn ckd_pub_tweak(
|
||||
&self,
|
||||
i: ChildNumber,
|
||||
) -> Result<(secp256k1::SecretKey, ChainCode), Error> {
|
||||
match i {
|
||||
ChildNumber::Hardened { .. } => {
|
||||
Err(Error::CannotDeriveFromHardenedKey)
|
||||
}
|
||||
ChildNumber::Hardened { .. } => Err(Error::CannotDeriveFromHardenedKey),
|
||||
ChildNumber::Normal { index: n } => {
|
||||
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(&self.chain_code[..]);
|
||||
let mut hmac_engine: HmacEngine<sha512::Hash> =
|
||||
HmacEngine::new(&self.chain_code[..]);
|
||||
hmac_engine.input(&self.public_key.serialize()[..]);
|
||||
hmac_engine.input(&endian::u32_to_array_be(n));
|
||||
|
||||
|
@ -742,7 +724,7 @@ impl ExtendedPubKey {
|
|||
/// Decoding extended public key from binary data according to BIP 32
|
||||
pub fn decode(data: &[u8]) -> Result<ExtendedPubKey, Error> {
|
||||
if data.len() != 78 {
|
||||
return Err(Error::WrongExtendedKeyLength(data.len()))
|
||||
return Err(Error::WrongExtendedKeyLength(data.len()));
|
||||
}
|
||||
|
||||
Ok(ExtendedPubKey {
|
||||
|
@ -766,10 +748,12 @@ impl ExtendedPubKey {
|
|||
/// Extended public key binary encoding according to BIP 32
|
||||
pub fn encode(&self) -> [u8; 78] {
|
||||
let mut ret = [0; 78];
|
||||
ret[0..4].copy_from_slice(&match self.network {
|
||||
ret[0..4].copy_from_slice(
|
||||
&match self.network {
|
||||
Network::Bitcoin => [0x04u8, 0x88, 0xB2, 0x1E],
|
||||
Network::Testnet | Network::Signet | Network::Regtest => [0x04u8, 0x35, 0x87, 0xCF],
|
||||
}[..]);
|
||||
}[..],
|
||||
);
|
||||
ret[4] = self.depth as u8;
|
||||
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
|
||||
ret[9..13].copy_from_slice(&endian::u32_to_array_be(u32::from(self.child_number)));
|
||||
|
@ -786,9 +770,7 @@ impl ExtendedPubKey {
|
|||
}
|
||||
|
||||
/// Returns the first four bytes of the identifier
|
||||
pub fn fingerprint(&self) -> Fingerprint {
|
||||
Fingerprint::from(&self.identifier()[0..4])
|
||||
}
|
||||
pub fn fingerprint(&self) -> Fingerprint { Fingerprint::from(&self.identifier()[0..4]) }
|
||||
}
|
||||
|
||||
impl fmt::Display for ExtendedPrivKey {
|
||||
|
@ -832,27 +814,22 @@ impl FromStr for ExtendedPubKey {
|
|||
}
|
||||
|
||||
impl From<ExtendedPubKey> for XpubIdentifier {
|
||||
fn from(key: ExtendedPubKey) -> XpubIdentifier {
|
||||
key.identifier()
|
||||
}
|
||||
fn from(key: ExtendedPubKey) -> XpubIdentifier { key.identifier() }
|
||||
}
|
||||
|
||||
impl From<&ExtendedPubKey> for XpubIdentifier {
|
||||
fn from(key: &ExtendedPubKey) -> XpubIdentifier {
|
||||
key.identifier()
|
||||
}
|
||||
fn from(key: &ExtendedPubKey) -> XpubIdentifier { key.identifier() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::ChildNumber::{Hardened, Normal};
|
||||
|
||||
use core::str::FromStr;
|
||||
|
||||
use secp256k1::{self, Secp256k1};
|
||||
use crate::hashes::hex::FromHex;
|
||||
|
||||
use super::ChildNumber::{Hardened, Normal};
|
||||
use super::*;
|
||||
use crate::hashes::hex::FromHex;
|
||||
use crate::network::constants::Network::{self, Bitcoin};
|
||||
|
||||
#[test]
|
||||
|
@ -862,7 +839,10 @@ mod tests {
|
|||
assert_eq!(DerivationPath::from_str("4/m/5"), Err(Error::InvalidDerivationPathFormat));
|
||||
assert_eq!(DerivationPath::from_str("m//3/0'"), Err(Error::InvalidChildNumberFormat));
|
||||
assert_eq!(DerivationPath::from_str("m/0h/0x"), Err(Error::InvalidChildNumberFormat));
|
||||
assert_eq!(DerivationPath::from_str("m/2147483648"), Err(Error::InvalidChildNumber(2147483648)));
|
||||
assert_eq!(
|
||||
DerivationPath::from_str("m/2147483648"),
|
||||
Err(Error::InvalidChildNumber(2147483648))
|
||||
);
|
||||
|
||||
assert_eq!(DerivationPath::master(), DerivationPath::from_str("m").unwrap());
|
||||
assert_eq!(DerivationPath::master(), DerivationPath::default());
|
||||
|
@ -873,7 +853,11 @@ mod tests {
|
|||
);
|
||||
assert_eq!(
|
||||
DerivationPath::from_str("m/0'/1"),
|
||||
Ok(vec![ChildNumber::from_hardened_idx(0).unwrap(), ChildNumber::from_normal_idx(1).unwrap()].into())
|
||||
Ok(vec![
|
||||
ChildNumber::from_hardened_idx(0).unwrap(),
|
||||
ChildNumber::from_normal_idx(1).unwrap()
|
||||
]
|
||||
.into())
|
||||
);
|
||||
assert_eq!(
|
||||
DerivationPath::from_str("m/0h/1/2'"),
|
||||
|
@ -881,7 +865,8 @@ mod tests {
|
|||
ChildNumber::from_hardened_idx(0).unwrap(),
|
||||
ChildNumber::from_normal_idx(1).unwrap(),
|
||||
ChildNumber::from_hardened_idx(2).unwrap(),
|
||||
].into())
|
||||
]
|
||||
.into())
|
||||
);
|
||||
assert_eq!(
|
||||
DerivationPath::from_str("m/0'/1/2h/2"),
|
||||
|
@ -890,7 +875,8 @@ mod tests {
|
|||
ChildNumber::from_normal_idx(1).unwrap(),
|
||||
ChildNumber::from_hardened_idx(2).unwrap(),
|
||||
ChildNumber::from_normal_idx(2).unwrap(),
|
||||
].into())
|
||||
]
|
||||
.into())
|
||||
);
|
||||
assert_eq!(
|
||||
DerivationPath::from_str("m/0'/1/2'/2/1000000000"),
|
||||
|
@ -900,7 +886,8 @@ mod tests {
|
|||
ChildNumber::from_hardened_idx(2).unwrap(),
|
||||
ChildNumber::from_normal_idx(2).unwrap(),
|
||||
ChildNumber::from_normal_idx(1000000000).unwrap(),
|
||||
].into())
|
||||
]
|
||||
.into())
|
||||
);
|
||||
let s = "m/0'/50/3'/5/545456";
|
||||
assert_eq!(DerivationPath::from_str(s), s.into_derivation_path());
|
||||
|
@ -913,7 +900,10 @@ mod tests {
|
|||
let numbers: Vec<ChildNumber> = path.clone().into();
|
||||
let path2: DerivationPath = numbers.into();
|
||||
assert_eq!(path, path2);
|
||||
assert_eq!(&path[..2], &[ChildNumber::from_hardened_idx(0).unwrap(), ChildNumber::from_normal_idx(1).unwrap()]);
|
||||
assert_eq!(
|
||||
&path[..2],
|
||||
&[ChildNumber::from_hardened_idx(0).unwrap(), ChildNumber::from_normal_idx(1).unwrap()]
|
||||
);
|
||||
let indexed: DerivationPath = path[..2].into();
|
||||
assert_eq!(indexed, DerivationPath::from_str("m/0h/1").unwrap());
|
||||
assert_eq!(indexed.child(ChildNumber::from_hardened_idx(2).unwrap()), path);
|
||||
|
@ -925,8 +915,8 @@ mod tests {
|
|||
seed: &[u8],
|
||||
path: DerivationPath,
|
||||
expected_sk: &str,
|
||||
expected_pk: &str)
|
||||
{
|
||||
expected_pk: &str,
|
||||
) {
|
||||
let mut sk = ExtendedPrivKey::new_master(network, seed).unwrap();
|
||||
let mut pk = ExtendedPubKey::from_priv(secp, &sk);
|
||||
|
||||
|
@ -945,16 +935,13 @@ mod tests {
|
|||
for &num in path.0.iter() {
|
||||
sk = sk.ckd_priv(secp, num).unwrap();
|
||||
match num {
|
||||
Normal {..} => {
|
||||
Normal { .. } => {
|
||||
let pk2 = pk.ckd_pub(secp, num).unwrap();
|
||||
pk = ExtendedPubKey::from_priv(secp, &sk);
|
||||
assert_eq!(pk, pk2);
|
||||
}
|
||||
Hardened {..} => {
|
||||
assert_eq!(
|
||||
pk.ckd_pub(secp, num),
|
||||
Err(Error::CannotDeriveFromHardenedKey)
|
||||
);
|
||||
Hardened { .. } => {
|
||||
assert_eq!(pk.ckd_pub(secp, num), Err(Error::CannotDeriveFromHardenedKey));
|
||||
pk = ExtendedPubKey::from_priv(secp, &sk);
|
||||
}
|
||||
}
|
||||
|
@ -974,15 +961,15 @@ mod tests {
|
|||
fn test_increment() {
|
||||
let idx = 9345497; // randomly generated, I promise
|
||||
let cn = ChildNumber::from_normal_idx(idx).unwrap();
|
||||
assert_eq!(cn.increment().ok(), Some(ChildNumber::from_normal_idx(idx+1).unwrap()));
|
||||
assert_eq!(cn.increment().ok(), Some(ChildNumber::from_normal_idx(idx + 1).unwrap()));
|
||||
let cn = ChildNumber::from_hardened_idx(idx).unwrap();
|
||||
assert_eq!(cn.increment().ok(), Some(ChildNumber::from_hardened_idx(idx+1).unwrap()));
|
||||
assert_eq!(cn.increment().ok(), Some(ChildNumber::from_hardened_idx(idx + 1).unwrap()));
|
||||
|
||||
let max = (1<<31)-1;
|
||||
let max = (1 << 31) - 1;
|
||||
let cn = ChildNumber::from_normal_idx(max).unwrap();
|
||||
assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1<<31)));
|
||||
assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1 << 31)));
|
||||
let cn = ChildNumber::from_hardened_idx(max).unwrap();
|
||||
assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1<<31)));
|
||||
assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1 << 31)));
|
||||
|
||||
let cn = ChildNumber::from_normal_idx(350).unwrap();
|
||||
let path = DerivationPath::from_str("m/42'").unwrap();
|
||||
|
@ -1099,7 +1086,6 @@ mod tests {
|
|||
test_path(&secp, Bitcoin, &seed, "m/0h".parse().unwrap(),
|
||||
"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
|
||||
"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y");
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1117,7 +1103,8 @@ mod tests {
|
|||
#[cfg(feature = "serde")]
|
||||
pub fn encode_fingerprint_chaincode() {
|
||||
use serde_json;
|
||||
let fp = Fingerprint::from(&[1u8,2,3,42][..]);
|
||||
let fp = Fingerprint::from(&[1u8, 2, 3, 42][..]);
|
||||
#[rustfmt::skip]
|
||||
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][..]
|
||||
);
|
||||
|
@ -1175,7 +1162,6 @@ mod tests {
|
|||
ExtendedPrivKey::from_str(xpriv_str).unwrap();
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Secp256k1(InvalidSecretKey)")]
|
||||
fn schnorr_broken_privkey_ffs() {
|
|
@ -81,6 +81,7 @@ mod serde_utils;
|
|||
pub mod network;
|
||||
pub mod address;
|
||||
pub mod bip158;
|
||||
pub mod bip32;
|
||||
pub mod blockdata;
|
||||
pub mod consensus;
|
||||
pub mod error;
|
||||
|
|
|
@ -11,7 +11,6 @@ pub mod ecdsa;
|
|||
pub mod schnorr;
|
||||
pub mod amount;
|
||||
pub mod base58;
|
||||
pub mod bip32;
|
||||
pub mod bip152;
|
||||
pub mod hash;
|
||||
pub mod merkleblock;
|
||||
|
@ -117,5 +116,8 @@ pub mod address {
|
|||
pub use crate::address::*;
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.30.0", note = "Please use crate::bip32")]
|
||||
pub use crate::bip32;
|
||||
|
||||
#[deprecated(since = "0.30.0", note = "Please use crate::bip158")]
|
||||
pub use crate::bip158;
|
||||
|
|
Loading…
Reference in New Issue