Merge rust-bitcoin/rust-bitcoin#591: PSBT BIP32 keys using to Secp256k1 keys instead of bitcoin ECDSA
a6e8f581db
PSBT BIP32 keys moved to Secp256k1 from bitcoin ECDSA (Dr Maxim Orlovsky) Pull request description: Fourth step in implementation of Schnorr key support after #588. This PR is a follow-up to non-API breaking #589 and API-breaking #590, which must be reviewed and merged first. ~~(The current PR includes all commits from #589 and #590, which should be reviewed there. The only commit specific to this PR is b8105e95dc8651626b783403ca060f7d32d21144)~~ UPDATE: All related PRs are merged now and this PR is ready for the review PR description: While PSBT BIP174 does not specify whether uncompressed keys are supported in BIP32-related fields, from BIP32 it follows that it is impossible to use uncompressed keys within the extended keys. This PR fixes this situation and is a companion to BIP174 PR clarifying key serialization: https://github.com/bitcoin/bips/pull/1100 ACKs for top commit: apoelstra: ACKa6e8f581db
sanket1729: ACKa6e8f581db
. Not sure which order to merge since there are many ready PRs which that would break each other. Tree-SHA512: 198ba646bbce1949b255a54a97957d952acdad8b7f9580be123116c0f44d773e6d90e0cac0d5993ec9a6b3328aa43aced0908522817861585877c50008fec835
This commit is contained in:
commit
e4d5039a86
|
@ -1038,10 +1038,10 @@ mod test {
|
||||||
let pubkey = PublicKey::from_str("0234e6a79c5359c613762d537e0e19d86c77c1666d8c9ab050f23acd198e97f93e").unwrap();
|
let pubkey = PublicKey::from_str("0234e6a79c5359c613762d537e0e19d86c77c1666d8c9ab050f23acd198e97f93e").unwrap();
|
||||||
assert!(Script::new_p2pk(&pubkey).is_p2pk());
|
assert!(Script::new_p2pk(&pubkey).is_p2pk());
|
||||||
|
|
||||||
let pubkey_hash = PubkeyHash::hash(&pubkey.serialize());
|
let pubkey_hash = PubkeyHash::hash(&pubkey.key.serialize());
|
||||||
assert!(Script::new_p2pkh(&pubkey_hash).is_p2pkh());
|
assert!(Script::new_p2pkh(&pubkey_hash).is_p2pkh());
|
||||||
|
|
||||||
let wpubkey_hash = WPubkeyHash::hash(&pubkey.serialize());
|
let wpubkey_hash = WPubkeyHash::hash(&pubkey.key.serialize());
|
||||||
assert!(Script::new_v0_wpkh(&wpubkey_hash).is_v0_p2wpkh());
|
assert!(Script::new_v0_wpkh(&wpubkey_hash).is_v0_p2wpkh());
|
||||||
|
|
||||||
let script = Builder::new().push_opcode(opcodes::all::OP_NUMEQUAL)
|
let script = Builder::new().push_opcode(opcodes::all::OP_NUMEQUAL)
|
||||||
|
|
|
@ -16,13 +16,13 @@ use prelude::*;
|
||||||
|
|
||||||
use ::{EcdsaSig, io};
|
use ::{EcdsaSig, io};
|
||||||
|
|
||||||
|
use secp256k1;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
|
use hashes::{self, hash160, ripemd160, sha256, sha256d};
|
||||||
use secp256k1::XOnlyPublicKey;
|
use secp256k1::XOnlyPublicKey;
|
||||||
use util::bip32::KeySource;
|
use util::bip32::KeySource;
|
||||||
use hashes::{self, hash160, ripemd160, sha256, sha256d};
|
|
||||||
use util::ecdsa::PublicKey;
|
|
||||||
use util::psbt;
|
use util::psbt;
|
||||||
use util::psbt::map::Map;
|
use util::psbt::map::Map;
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
|
@ -88,7 +88,7 @@ pub struct Input {
|
||||||
pub witness_utxo: Option<TxOut>,
|
pub witness_utxo: Option<TxOut>,
|
||||||
/// A map from public keys to their corresponding signature as would be
|
/// A map from public keys to their corresponding signature as would be
|
||||||
/// pushed to the stack from a scriptSig or witness for a non-taproot inputs.
|
/// pushed to the stack from a scriptSig or witness for a non-taproot inputs.
|
||||||
pub partial_sigs: BTreeMap<PublicKey, EcdsaSig>,
|
pub partial_sigs: BTreeMap<secp256k1::PublicKey, EcdsaSig>,
|
||||||
/// The sighash type to be used for this input. Signatures for this input
|
/// The sighash type to be used for this input. Signatures for this input
|
||||||
/// must use the sighash type.
|
/// must use the sighash type.
|
||||||
pub sighash_type: Option<EcdsaSigHashType>,
|
pub sighash_type: Option<EcdsaSigHashType>,
|
||||||
|
@ -99,7 +99,7 @@ pub struct Input {
|
||||||
/// A map from public keys needed to sign this input to their corresponding
|
/// A map from public keys needed to sign this input to their corresponding
|
||||||
/// master key fingerprints and derivation paths.
|
/// master key fingerprints and derivation paths.
|
||||||
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
||||||
pub bip32_derivation: BTreeMap<PublicKey, KeySource>,
|
pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>,
|
||||||
/// The finalized, fully-constructed scriptSig with signatures and any other
|
/// The finalized, fully-constructed scriptSig with signatures and any other
|
||||||
/// scripts necessary for this input to pass validation.
|
/// scripts necessary for this input to pass validation.
|
||||||
pub final_script_sig: Option<Script>,
|
pub final_script_sig: Option<Script>,
|
||||||
|
@ -162,7 +162,7 @@ impl Map for Input {
|
||||||
}
|
}
|
||||||
PSBT_IN_PARTIAL_SIG => {
|
PSBT_IN_PARTIAL_SIG => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.partial_sigs <= <raw_key: PublicKey>|<raw_value: EcdsaSig>
|
self.partial_sigs <= <raw_key: secp256k1::PublicKey>|<raw_value: EcdsaSig>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_SIGHASH_TYPE => {
|
PSBT_IN_SIGHASH_TYPE => {
|
||||||
|
@ -182,7 +182,7 @@ impl Map for Input {
|
||||||
}
|
}
|
||||||
PSBT_IN_BIP32_DERIVATION => {
|
PSBT_IN_BIP32_DERIVATION => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.bip32_derivation <= <raw_key: PublicKey>|<raw_value: KeySource>
|
self.bip32_derivation <= <raw_key: secp256k1::PublicKey>|<raw_value: KeySource>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_FINAL_SCRIPTSIG => {
|
PSBT_IN_FINAL_SCRIPTSIG => {
|
||||||
|
@ -282,7 +282,7 @@ impl Map for Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
rv.push(self.bip32_derivation as <PSBT_IN_BIP32_DERIVATION, PublicKey>|<KeySource>)
|
rv.push(self.bip32_derivation as <PSBT_IN_BIP32_DERIVATION, secp256k1::PublicKey>|<KeySource>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use blockdata::script::Script;
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
use secp256k1::XOnlyPublicKey;
|
use secp256k1::XOnlyPublicKey;
|
||||||
use util::bip32::KeySource;
|
use util::bip32::KeySource;
|
||||||
use util::ecdsa::PublicKey;
|
use secp256k1;
|
||||||
use util::psbt;
|
use util::psbt;
|
||||||
use util::psbt::map::Map;
|
use util::psbt::map::Map;
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
|
@ -57,7 +57,7 @@ pub struct Output {
|
||||||
/// A map from public keys needed to spend this output to their
|
/// A map from public keys needed to spend this output to their
|
||||||
/// corresponding master key fingerprints and derivation paths.
|
/// corresponding master key fingerprints and derivation paths.
|
||||||
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
||||||
pub bip32_derivation: BTreeMap<PublicKey, KeySource>,
|
pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>,
|
||||||
/// The internal pubkey
|
/// The internal pubkey
|
||||||
pub tap_internal_key: Option<XOnlyPublicKey>,
|
pub tap_internal_key: Option<XOnlyPublicKey>,
|
||||||
/// Taproot Output tree
|
/// Taproot Output tree
|
||||||
|
@ -139,7 +139,7 @@ impl Map for Output {
|
||||||
}
|
}
|
||||||
PSBT_OUT_BIP32_DERIVATION => {
|
PSBT_OUT_BIP32_DERIVATION => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.bip32_derivation <= <raw_key: PublicKey>|<raw_value: KeySource>
|
self.bip32_derivation <= <raw_key: secp256k1::PublicKey>|<raw_value: KeySource>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_OUT_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) {
|
PSBT_OUT_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) {
|
||||||
|
@ -186,7 +186,7 @@ impl Map for Output {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
rv.push(self.bip32_derivation as <PSBT_OUT_BIP32_DERIVATION, PublicKey>|<KeySource>)
|
rv.push(self.bip32_derivation as <PSBT_OUT_BIP32_DERIVATION, secp256k1::PublicKey>|<KeySource>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
|
|
|
@ -256,7 +256,6 @@ mod tests {
|
||||||
use network::constants::Network::Bitcoin;
|
use network::constants::Network::Bitcoin;
|
||||||
use consensus::encode::{deserialize, serialize, serialize_hex};
|
use consensus::encode::{deserialize, serialize, serialize_hex};
|
||||||
use util::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, Fingerprint, KeySource};
|
use util::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, Fingerprint, KeySource};
|
||||||
use util::ecdsa;
|
|
||||||
use util::psbt::map::{Output, Input};
|
use util::psbt::map::{Output, Input};
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
|
|
||||||
|
@ -321,10 +320,7 @@ mod tests {
|
||||||
witness_script: Some(hex_script!(
|
witness_script: Some(hex_script!(
|
||||||
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"
|
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"
|
||||||
)),
|
)),
|
||||||
bip32_derivation: hd_keypaths.into_iter().map(|(key, src)| (ecdsa::PublicKey {
|
bip32_derivation: hd_keypaths,
|
||||||
compressed: true,
|
|
||||||
key,
|
|
||||||
}, src)).collect(),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -481,10 +477,7 @@ mod tests {
|
||||||
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
|
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
|
||||||
"304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe701".parse().unwrap(),
|
"304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe701".parse().unwrap(),
|
||||||
)].into_iter().collect(),
|
)].into_iter().collect(),
|
||||||
bip32_derivation: keypaths.clone().into_iter().map(|(key, src)| (ecdsa::PublicKey {
|
bip32_derivation: keypaths.clone(),
|
||||||
compressed: true,
|
|
||||||
key,
|
|
||||||
}, src)).collect(),
|
|
||||||
final_script_witness: Some(vec![vec![1, 3], vec![5]]),
|
final_script_witness: Some(vec![vec![1, 3], vec![5]]),
|
||||||
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
||||||
sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
||||||
|
@ -495,10 +488,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
outputs: vec![Output {
|
outputs: vec![Output {
|
||||||
bip32_derivation: keypaths.into_iter().map(|(key, src)| (ecdsa::PublicKey {
|
bip32_derivation: keypaths,
|
||||||
compressed: true,
|
|
||||||
key,
|
|
||||||
}, src)).collect(),
|
|
||||||
proprietary: proprietary.clone(),
|
proprietary: proprietary.clone(),
|
||||||
unknown: unknown.clone(),
|
unknown: unknown.clone(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -28,7 +28,7 @@ use consensus::encode::{self, serialize, Decodable, Encodable, deserialize_parti
|
||||||
use secp256k1::{self, XOnlyPublicKey};
|
use secp256k1::{self, XOnlyPublicKey};
|
||||||
use util::bip32::{ChildNumber, Fingerprint, KeySource};
|
use util::bip32::{ChildNumber, Fingerprint, KeySource};
|
||||||
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
||||||
use util::ecdsa::{PublicKey, EcdsaSig};
|
use util::ecdsa::EcdsaSig;
|
||||||
use util::psbt;
|
use util::psbt;
|
||||||
use util::taproot::{TapBranchHash, TapLeafHash, ControlBlock, LeafVersion};
|
use util::taproot::{TapBranchHash, TapLeafHash, ControlBlock, LeafVersion};
|
||||||
use schnorr;
|
use schnorr;
|
||||||
|
@ -74,17 +74,15 @@ impl Deserialize for Script {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for PublicKey {
|
impl Serialize for secp256k1::PublicKey {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
let mut buf = Vec::new();
|
self.serialize().to_vec()
|
||||||
self.write_into(&mut buf).expect("vecs don't error");
|
|
||||||
buf
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for PublicKey {
|
impl Deserialize for secp256k1::PublicKey {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
||||||
PublicKey::from_slice(bytes)
|
secp256k1::PublicKey::from_slice(bytes)
|
||||||
.map_err(|_| encode::Error::ParseFailed("invalid public key"))
|
.map_err(|_| encode::Error::ParseFailed("invalid public key"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue