Use NetworkKind in bip32 module

BIP-32 only differentiates between mainnet and some testnet when
encoding and decoding xpubs and xprivs. As such we can use the new
`NetworkKind` type instead of `Network` throughout the `bip32` module.
This commit is contained in:
Tobin C. Harding 2023-11-28 10:40:08 +11:00
parent 35bbfcded7
commit 4354f37f51
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
5 changed files with 40 additions and 48 deletions

View File

@ -8,7 +8,7 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, Xpriv, Xpub};
use bitcoin::hex::FromHex;
use bitcoin::secp256k1::ffi::types::AlignedType;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::CompressedPublicKey;
use bitcoin::{Network, NetworkKind, CompressedPublicKey};
fn main() {
// This example derives root xprv from a 32-byte seed,
@ -26,10 +26,7 @@ fn main() {
let seed_hex = &args[1];
println!("Seed: {}", seed_hex);
// default network as mainnet
let network = bitcoin::Network::Bitcoin;
println!("Network: {:?}", network);
println!("Using mainnet network");
let seed = Vec::from_hex(seed_hex).unwrap();
@ -39,7 +36,7 @@ fn main() {
let secp = Secp256k1::preallocated_new(buf.as_mut_slice()).unwrap();
// calculate root key from seed
let root = Xpriv::new_master(network, &seed).unwrap();
let root = Xpriv::new_master(NetworkKind::Main, &seed).unwrap();
println!("Root key: {}", root);
// derive child xpub
@ -53,6 +50,6 @@ fn main() {
// manually creating indexes this time
let zero = ChildNumber::from_normal_idx(0).unwrap();
let public_key = xpub.derive_pub(&secp, &[zero, zero]).unwrap().public_key;
let address = Address::p2wpkh(&CompressedPublicKey(public_key), network);
let address = Address::p2wpkh(&CompressedPublicKey(public_key), Network::Bitcoin);
println!("First receiving address: {}", address);
}

View File

@ -21,7 +21,7 @@ use serde;
use crate::base58;
use crate::crypto::key::{self, Keypair, PrivateKey, CompressedPublicKey};
use crate::internal_macros::impl_bytes_newtype;
use crate::network::Network;
use crate::network::NetworkKind;
use crate::prelude::*;
/// Version bytes for extended public keys on the Bitcoin network.
@ -69,7 +69,7 @@ hash_newtype! {
#[cfg_attr(feature = "std", derive(Debug))]
pub struct Xpriv {
/// The network this key is to be used on
pub network: Network,
pub network: NetworkKind,
/// How many derivations this key is from the master (which is 0)
pub depth: u8,
/// Fingerprint of the parent key (0 for master)
@ -101,8 +101,8 @@ impl fmt::Debug for Xpriv {
/// Extended public key
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
pub struct Xpub {
/// The network this key is to be used on
pub network: Network,
/// The network kind this key is to be used on
pub network: NetworkKind,
/// How many derivations this key is from the master (which is 0)
pub depth: u8,
/// Fingerprint of the parent key
@ -558,13 +558,13 @@ impl From<base58::Error> for Error {
impl Xpriv {
/// Construct a new master key from a seed value
pub fn new_master(network: Network, seed: &[u8]) -> Result<Xpriv, Error> {
pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Result<Xpriv, Error> {
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(b"Bitcoin seed");
hmac_engine.input(seed);
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
Ok(Xpriv {
network,
network: network.into(),
depth: 0,
parent_fingerprint: Default::default(),
child_number: ChildNumber::from_normal_idx(0)?,
@ -575,7 +575,7 @@ impl Xpriv {
/// Constructs ECDSA compressed private key matching internal secret key representation.
pub fn to_priv(self) -> PrivateKey {
PrivateKey { compressed: true, network: self.network.into(), 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
@ -645,9 +645,9 @@ impl Xpriv {
}
let network = if data.starts_with(&VERSION_BYTES_MAINNET_PRIVATE) {
Network::Bitcoin
NetworkKind::Main
} else if data.starts_with(&VERSION_BYTES_TESTNETS_PRIVATE) {
Network::Testnet
NetworkKind::Test
} else {
let (b0, b1, b2, b3) = (data[0], data[1], data[2], data[3]);
return Err(Error::UnknownVersion([b0, b1, b2, b3]));
@ -671,8 +671,8 @@ impl Xpriv {
pub fn encode(&self) -> [u8; 78] {
let mut ret = [0; 78];
ret[0..4].copy_from_slice(&match self.network {
Network::Bitcoin => VERSION_BYTES_MAINNET_PRIVATE,
Network::Testnet | Network::Signet | Network::Regtest => VERSION_BYTES_TESTNETS_PRIVATE,
NetworkKind::Main => VERSION_BYTES_MAINNET_PRIVATE,
NetworkKind::Test => VERSION_BYTES_TESTNETS_PRIVATE,
});
ret[4] = self.depth;
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
@ -777,9 +777,9 @@ impl Xpub {
}
let network = if data.starts_with(&VERSION_BYTES_MAINNET_PUBLIC) {
Network::Bitcoin
NetworkKind::Main
} else if data.starts_with(&VERSION_BYTES_TESTNETS_PUBLIC) {
Network::Testnet
NetworkKind::Test
} else {
let (b0, b1, b2, b3) = (data[0], data[1], data[2], data[3]);
return Err(Error::UnknownVersion([b0, b1, b2, b3]));
@ -803,8 +803,8 @@ impl Xpub {
pub fn encode(&self) -> [u8; 78] {
let mut ret = [0; 78];
ret[0..4].copy_from_slice(&match self.network {
Network::Bitcoin => VERSION_BYTES_MAINNET_PUBLIC,
Network::Testnet | Network::Signet | Network::Regtest => VERSION_BYTES_TESTNETS_PUBLIC,
NetworkKind::Main => VERSION_BYTES_MAINNET_PUBLIC,
NetworkKind::Test => VERSION_BYTES_TESTNETS_PUBLIC,
});
ret[4] = self.depth;
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
@ -884,7 +884,6 @@ mod tests {
use super::ChildNumber::{Hardened, Normal};
use super::*;
use crate::network::Network::{self, Bitcoin};
#[test]
fn test_parse_derivation_path() {
@ -965,7 +964,7 @@ mod tests {
fn test_path<C: secp256k1::Signing + secp256k1::Verification>(
secp: &Secp256k1<C>,
network: Network,
network: NetworkKind,
seed: &[u8],
path: DerivationPath,
expected_sk: &str,
@ -1060,32 +1059,32 @@ mod tests {
let seed = hex!("000102030405060708090a0b0c0d0e0f");
// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8");
// m/0h
test_path(&secp, Bitcoin, &seed, "m/0h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h".parse().unwrap(),
"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw");
// m/0h/1
test_path(&secp, Bitcoin, &seed, "m/0h/1".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1".parse().unwrap(),
"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ");
// m/0h/1/2h
test_path(&secp, Bitcoin, &seed, "m/0h/1/2h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h".parse().unwrap(),
"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5");
// m/0h/1/2h/2
test_path(&secp, Bitcoin, &seed, "m/0h/1/2h/2".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h/2".parse().unwrap(),
"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV");
// m/0h/1/2h/2/1000000000
test_path(&secp, Bitcoin, &seed, "m/0h/1/2h/2/1000000000".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h/2/1000000000".parse().unwrap(),
"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy");
}
@ -1096,32 +1095,32 @@ mod tests {
let seed = hex!("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542");
// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB");
// m/0
test_path(&secp, Bitcoin, &seed, "m/0".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0".parse().unwrap(),
"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH");
// m/0/2147483647h
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h".parse().unwrap(),
"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a");
// m/0/2147483647h/1
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1".parse().unwrap(),
"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon");
// m/0/2147483647h/1/2147483646h
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1/2147483646h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1/2147483646h".parse().unwrap(),
"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL");
// m/0/2147483647h/1/2147483646h/2
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1/2147483646h/2".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1/2147483646h/2".parse().unwrap(),
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt");
}
@ -1132,12 +1131,12 @@ mod tests {
let seed = hex!("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be");
// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6",
"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13");
// m/0h
test_path(&secp, Bitcoin, &seed, "m/0h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h".parse().unwrap(),
"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y");
}
@ -1200,7 +1199,7 @@ mod tests {
}
let xpriv = Xpriv {
network: Network::Bitcoin,
network: NetworkKind::Main,
depth: 0,
parent_fingerprint: Default::default(),
child_number: ChildNumber::Normal { index: 0 },

View File

@ -1014,7 +1014,6 @@ mod tests {
use crate::blockdata::script::ScriptBuf;
use crate::blockdata::transaction::{self, OutPoint, Sequence, Transaction, TxIn, TxOut};
use crate::blockdata::witness::Witness;
use crate::network::Network::Bitcoin;
use crate::network::NetworkKind;
use crate::psbt::map::{Input, Output};
use crate::psbt::raw;
@ -1152,7 +1151,7 @@ mod tests {
let mut hd_keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = Default::default();
let mut sk: Xpriv = Xpriv::new_master(Bitcoin, &seed).unwrap();
let mut sk: Xpriv = Xpriv::new_master(NetworkKind::Main, &seed).unwrap();
let fprint = sk.fingerprint(secp);

View File

@ -209,7 +209,6 @@ pub fn signed_msg_hash(msg: &str) -> sha256d::Hash {
#[cfg(test)]
mod tests {
use super::*;
use crate::network::NetworkKind;
#[test]
fn test_signed_msg_hash() {
@ -227,7 +226,7 @@ mod tests {
use secp256k1;
use crate::{Address, AddressType, Network};
use crate::{Address, AddressType, Network, NetworkKind};
let secp = secp256k1::Secp256k1::new();
let message = "rust-bitcoin MessageSignature test";

View File

@ -13,12 +13,10 @@ use bitcoin::psbt::{Psbt, PsbtSighashType};
use bitcoin::script::PushBytes;
use bitcoin::secp256k1::{self, Secp256k1};
use bitcoin::{
absolute, Amount, Denomination, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence,
Transaction, TxIn, TxOut, Witness,
absolute, Amount, Denomination, NetworkKind, OutPoint, PrivateKey, PublicKey, ScriptBuf,
Sequence, Transaction, TxIn, TxOut, Witness,
};
const NETWORK: Network = Network::Testnet;
#[track_caller]
fn hex_psbt(s: &str) -> Psbt {
let v: Vec<u8> = Vec::from_hex(s).expect("valid hex digits");
@ -124,7 +122,7 @@ fn build_extended_private_key() -> Xpriv {
let xpriv = Xpriv::from_str(extended_private_key).unwrap();
let sk = PrivateKey::from_wif(seed).unwrap();
let seeded = Xpriv::new_master(NETWORK, &sk.inner.secret_bytes()).unwrap();
let seeded = Xpriv::new_master(NetworkKind::Test, &sk.inner.secret_bytes()).unwrap();
assert_eq!(xpriv, seeded);
xpriv