Merge rust-bitcoin/rust-bitcoin#681: Add support for taproot psbt fields BIP 371

7d982fa9a2 Add all tests from BIP 371 (sanket1729)
d22e0149ad Taproot psbt impl BIP 371 (sanket1729)
108fc3d4db Impl encodable traits for TapLeafhash (sanket1729)
c7478d8fd0 Derive serde for taproot stuctures (sanket1729)

Pull request description:

  Built on top of #677 . Will rebase and mark ready for review after #677 is merged.

ACKs for top commit:
  apoelstra:
    ACK 7d982fa9a2
  dr-orlovsky:
    re-tACK 7d982fa9a2 basing on `git range-diff`. The original PR before last re-base was tested commit-by-commit.

Tree-SHA512: feb30e4b38d13110a9c0fabf6466d8f0fb7df09a82f4e01d70b8371b34ab0187004a6c63f9796c6585ee30841e8ee765ae9becae139d2e1e3d839553d64c3d1e
This commit is contained in:
Dr. Maxim Orlovsky 2021-12-30 02:11:39 +02:00
commit 670e808c17
No known key found for this signature in database
GPG Key ID: AF91255DEA466640
9 changed files with 496 additions and 15 deletions

View File

@ -39,6 +39,7 @@ use io::{self, Cursor, Read};
use util::endian; use util::endian;
use util::psbt; use util::psbt;
use util::taproot::TapLeafHash;
use hashes::hex::ToHex; use hashes::hex::ToHex;
use blockdata::transaction::{TxOut, Transaction, TxIn}; use blockdata::transaction::{TxOut, Transaction, TxIn};
@ -594,6 +595,7 @@ impl_vec!(TxOut);
impl_vec!(TxIn); impl_vec!(TxIn);
impl_vec!(Vec<u8>); impl_vec!(Vec<u8>);
impl_vec!(u64); impl_vec!(u64);
impl_vec!(TapLeafHash);
#[cfg(feature = "std")] impl_vec!(Inventory); #[cfg(feature = "std")] impl_vec!(Inventory);
#[cfg(feature = "std")] impl_vec!((u32, Address)); #[cfg(feature = "std")] impl_vec!((u32, Address));
@ -767,6 +769,18 @@ impl Decodable for sha256::Hash {
} }
} }
impl Encodable for TapLeafHash {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, io::Error> {
self.into_inner().consensus_encode(s)
}
}
impl Decodable for TapLeafHash {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(Self::from_inner(<<Self as Hash>::Inner>::consensus_decode(d)?))
}
}
// Tests // Tests
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -28,6 +28,9 @@ use util::psbt::raw;
use util::psbt::serialize::Deserialize; use util::psbt::serialize::Deserialize;
use util::psbt::{Error, error}; use util::psbt::{Error, error};
use schnorr;
use util::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash};
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00; const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00;
/// Type: Witness UTXO PSBT_IN_WITNESS_UTXO = 0x01 /// Type: Witness UTXO PSBT_IN_WITNESS_UTXO = 0x01
@ -54,6 +57,18 @@ const PSBT_IN_SHA256: u8 = 0x0b;
const PSBT_IN_HASH160: u8 = 0x0c; const PSBT_IN_HASH160: u8 = 0x0c;
/// Type: HASH256 preimage PSBT_IN_HASH256 = 0x0d /// Type: HASH256 preimage PSBT_IN_HASH256 = 0x0d
const PSBT_IN_HASH256: u8 = 0x0d; const PSBT_IN_HASH256: u8 = 0x0d;
/// Type: Schnorr Signature in Key Spend PSBT_IN_TAP_KEY_SIG = 0x13
const PSBT_IN_TAP_KEY_SIG: u8 = 0x13;
/// Type: Schnorr Signature in Script Spend PSBT_IN_TAP_SCRIPT_SIG = 0x14
const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14;
/// Type: Taproot Leaf Script PSBT_IN_TAP_LEAF_SCRIPT = 0x14
const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15;
/// Type: Taproot Key BIP 32 Derivation Path PSBT_IN_TAP_BIP32_DERIVATION = 0x16
const PSBT_IN_TAP_BIP32_DERIVATION : u8 = 0x16;
/// Type: Taproot Internal Key PSBT_IN_TAP_INTERNAL_KEY = 0x17
const PSBT_IN_TAP_INTERNAL_KEY : u8 = 0x17;
/// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18
const PSBT_IN_TAP_MERKLE_ROOT : u8 = 0x18;
/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC /// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
const PSBT_IN_PROPRIETARY: u8 = 0xFC; const PSBT_IN_PROPRIETARY: u8 = 0xFC;
@ -104,6 +119,21 @@ pub struct Input {
/// HAS256 hash to preimage map /// HAS256 hash to preimage map
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>, pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>,
/// Serialized schnorr signature with sighash type for key spend
pub tap_key_sig: Option<schnorr::SchnorrSig>,
/// Map of <xonlypubkey>|<leafhash> with signature
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_script_sigs: BTreeMap<(schnorr::PublicKey, TapLeafHash), schnorr::SchnorrSig>,
/// Map of Control blocks to Script version pair
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_scripts: BTreeMap<ControlBlock, (Script, LeafVersion)>,
/// Map of tap root x only keys to origin info and leaf hashes contained in it
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_key_origins: BTreeMap<schnorr::PublicKey, (Vec<TapLeafHash>, KeySource)>,
/// Taproot Internal key
pub tap_internal_key : Option<schnorr::PublicKey>,
/// Taproot Merkle root
pub tap_merkle_root : Option<TapBranchHash>,
/// Proprietary key-value pairs for this input. /// Proprietary key-value pairs for this input.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))]
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>, pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
@ -177,6 +207,36 @@ impl Map for Input {
PSBT_IN_HASH256 => { PSBT_IN_HASH256 => {
psbt_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsbtHash::Hash256)?; psbt_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsbtHash::Hash256)?;
} }
PSBT_IN_TAP_KEY_SIG => {
impl_psbt_insert_pair! {
self.tap_key_sig <= <raw_key: _>|<raw_value: schnorr::SchnorrSig>
}
}
PSBT_IN_TAP_SCRIPT_SIG => {
impl_psbt_insert_pair! {
self.tap_script_sigs <= <raw_key: (schnorr::PublicKey, TapLeafHash)>|<raw_value: schnorr::SchnorrSig>
}
}
PSBT_IN_TAP_LEAF_SCRIPT=> {
impl_psbt_insert_pair! {
self.tap_scripts <= <raw_key: ControlBlock>|< raw_value: (Script, LeafVersion)>
}
}
PSBT_IN_TAP_BIP32_DERIVATION => {
impl_psbt_insert_pair! {
self.tap_key_origins <= <raw_key: schnorr::PublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
}
}
PSBT_IN_TAP_INTERNAL_KEY => {
impl_psbt_insert_pair! {
self.tap_internal_key <= <raw_key: _>|< raw_value: schnorr::PublicKey>
}
}
PSBT_IN_TAP_MERKLE_ROOT => {
impl_psbt_insert_pair! {
self.tap_merkle_root <= <raw_key: _>|< raw_value: TapBranchHash>
}
}
PSBT_IN_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) { PSBT_IN_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);},
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()),
@ -249,6 +309,30 @@ impl Map for Input {
rv.push(self.hash256_preimages as <PSBT_IN_HASH256, sha256d::Hash>|<Vec<u8>>) rv.push(self.hash256_preimages as <PSBT_IN_HASH256, sha256d::Hash>|<Vec<u8>>)
} }
impl_psbt_get_pair! {
rv.push(self.tap_key_sig as <PSBT_IN_TAP_KEY_SIG, _>|<Vec<u8>>)
}
impl_psbt_get_pair! {
rv.push(self.tap_script_sigs as <PSBT_IN_TAP_SCRIPT_SIG, (schnorr::PublicKey, TapLeafHash)>|<Vec<u8>>)
}
impl_psbt_get_pair! {
rv.push(self.tap_scripts as <PSBT_IN_TAP_LEAF_SCRIPT, ControlBlock>|<(Script, LeafVersion)>)
}
impl_psbt_get_pair! {
rv.push(self.tap_key_origins as <PSBT_IN_TAP_BIP32_DERIVATION,
schnorr::PublicKey>|<(Vec<TapLeafHash>, KeySource)>)
}
impl_psbt_get_pair! {
rv.push(self.tap_internal_key as <PSBT_IN_TAP_INTERNAL_KEY, _>|<schnorr::PublicKey>)
}
impl_psbt_get_pair! {
rv.push(self.tap_merkle_root as <PSBT_IN_TAP_MERKLE_ROOT, _>|<TapBranchHash>)
}
for (key, value) in self.proprietary.iter() { for (key, value) in self.proprietary.iter() {
rv.push(raw::Pair { rv.push(raw::Pair {
key: key.to_key(), key: key.to_key(),
@ -280,6 +364,9 @@ impl Map for Input {
self.sha256_preimages.extend(other.sha256_preimages); self.sha256_preimages.extend(other.sha256_preimages);
self.hash160_preimages.extend(other.hash160_preimages); self.hash160_preimages.extend(other.hash160_preimages);
self.hash256_preimages.extend(other.hash256_preimages); self.hash256_preimages.extend(other.hash256_preimages);
self.tap_script_sigs.extend(other.tap_script_sigs);
self.tap_scripts.extend(other.tap_scripts);
self.tap_key_origins.extend(other.tap_key_origins);
self.proprietary.extend(other.proprietary); self.proprietary.extend(other.proprietary);
self.unknown.extend(other.unknown); self.unknown.extend(other.unknown);
@ -287,6 +374,9 @@ impl Map for Input {
merge!(witness_script, self, other); merge!(witness_script, self, other);
merge!(final_script_sig, self, other); merge!(final_script_sig, self, other);
merge!(final_script_witness, self, other); merge!(final_script_witness, self, other);
merge!(tap_key_sig, self, other);
merge!(tap_internal_key, self, other);
merge!(tap_merkle_root, self, other);
Ok(()) Ok(())
} }

View File

@ -55,3 +55,4 @@ mod output;
pub use self::input::Input; pub use self::input::Input;
pub use self::output::Output; pub use self::output::Output;
pub use self::output::TapTree;

View File

@ -25,12 +25,23 @@ use util::psbt::map::Map;
use util::psbt::raw; use util::psbt::raw;
use util::psbt::Error; use util::psbt::Error;
use schnorr;
use util::taproot::TapLeafHash;
use util::taproot::{NodeInfo, TaprootBuilder};
/// Type: Redeem Script PSBT_OUT_REDEEM_SCRIPT = 0x00 /// Type: Redeem Script PSBT_OUT_REDEEM_SCRIPT = 0x00
const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00; const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00;
/// Type: Witness Script PSBT_OUT_WITNESS_SCRIPT = 0x01 /// Type: Witness Script PSBT_OUT_WITNESS_SCRIPT = 0x01
const PSBT_OUT_WITNESS_SCRIPT: u8 = 0x01; const PSBT_OUT_WITNESS_SCRIPT: u8 = 0x01;
/// Type: BIP 32 Derivation Path PSBT_OUT_BIP32_DERIVATION = 0x02 /// Type: BIP 32 Derivation Path PSBT_OUT_BIP32_DERIVATION = 0x02
const PSBT_OUT_BIP32_DERIVATION: u8 = 0x02; const PSBT_OUT_BIP32_DERIVATION: u8 = 0x02;
/// Type: Taproot Internal Key PSBT_OUT_TAP_INTERNAL_KEY = 0x05
const PSBT_OUT_TAP_INTERNAL_KEY: u8 = 0x05;
/// Type: Taproot Tree PSBT_OUT_TAP_TREE = 0x06
const PSBT_OUT_TAP_TREE: u8 = 0x06;
/// Type: Taproot Key BIP 32 Derivation Path PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
const PSBT_OUT_TAP_BIP32_DERIVATION: u8 = 0x07;
/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC /// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
const PSBT_OUT_PROPRIETARY: u8 = 0xFC; const PSBT_OUT_PROPRIETARY: u8 = 0xFC;
@ -47,14 +58,67 @@ pub struct Output {
/// 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<PublicKey, KeySource>,
/// The internal pubkey
pub tap_internal_key: Option<schnorr::PublicKey>,
/// Taproot Output tree
pub tap_tree: Option<TapTree>,
/// Map of tap root x only keys to origin info and leaf hashes contained in it
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_key_origins: BTreeMap<schnorr::PublicKey, (Vec<TapLeafHash>, KeySource)>,
/// Proprietary key-value pairs for this output. /// Proprietary key-value pairs for this output.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))] #[cfg_attr(
feature = "serde",
serde(with = "::serde_utils::btreemap_as_seq_byte_values")
)]
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>, pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
/// Unknown key-value pairs for this output. /// Unknown key-value pairs for this output.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))] #[cfg_attr(
feature = "serde",
serde(with = "::serde_utils::btreemap_as_seq_byte_values")
)]
pub unknown: BTreeMap<raw::Key, Vec<u8>>, pub unknown: BTreeMap<raw::Key, Vec<u8>>,
} }
/// Taproot Tree representing a finalized [`TaprootBuilder`] (a complete binary tree)
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TapTree(pub(crate) TaprootBuilder);
impl PartialEq for TapTree {
fn eq(&self, other: &Self) -> bool {
self.node_info().hash.eq(&other.node_info().hash)
}
}
impl Eq for TapTree {}
impl TapTree {
// get the inner node info as the builder is finalized
fn node_info(&self) -> &NodeInfo {
// The builder algorithm invariant guarantees that is_complete builder
// have only 1 element in branch and that is not None.
// We make sure that we only allow is_complete builders via the from_inner
// constructor
self.0.branch()[0].as_ref().expect("from_inner only parses is_complete builders")
}
/// Convert a [`TaprootBuilder`] into a tree if it is complete binary tree.
/// Returns the inner as Err if it is not a complete tree
pub fn from_inner(inner: TaprootBuilder) -> Result<Self, TaprootBuilder> {
if inner.is_complete() {
Ok(TapTree(inner))
} else {
Err(inner)
}
}
/// Convert self into builder [`TaprootBuilder`]. The builder is guaranteed to
/// be finalized.
pub fn into_inner(self) -> TaprootBuilder {
self.0
}
}
impl Map for Output { impl Map for Output {
fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> {
let raw::Pair { let raw::Pair {
@ -82,11 +146,30 @@ impl Map for Output {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);},
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()),
} }
_ => match self.unknown.entry(raw_key) { PSBT_OUT_TAP_INTERNAL_KEY => {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, impl_psbt_insert_pair! {
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), self.tap_internal_key <= <raw_key: _>|<raw_value: schnorr::PublicKey>
} }
} }
PSBT_OUT_TAP_TREE => {
impl_psbt_insert_pair! {
self.tap_tree <= <raw_key: _>|<raw_value: TapTree>
}
}
PSBT_OUT_TAP_BIP32_DERIVATION => {
impl_psbt_insert_pair! {
self.tap_key_origins <= <raw_key: schnorr::PublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
}
}
_ => match self.unknown.entry(raw_key) {
btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value);
}
btree_map::Entry::Occupied(k) => {
return Err(Error::DuplicateKey(k.key().clone()).into())
}
},
}
Ok(()) Ok(())
} }
@ -106,6 +189,19 @@ impl Map for Output {
rv.push(self.bip32_derivation as <PSBT_OUT_BIP32_DERIVATION, PublicKey>|<KeySource>) rv.push(self.bip32_derivation as <PSBT_OUT_BIP32_DERIVATION, PublicKey>|<KeySource>)
} }
impl_psbt_get_pair! {
rv.push(self.tap_internal_key as <PSBT_OUT_TAP_INTERNAL_KEY, _>|<schnorr::PublicKey>)
}
impl_psbt_get_pair! {
rv.push(self.tap_tree as <PSBT_OUT_TAP_TREE, _>|<TaprootBuilder>)
}
impl_psbt_get_pair! {
rv.push(self.tap_key_origins as <PSBT_OUT_TAP_BIP32_DERIVATION,
schnorr::PublicKey>|<(Vec<TapLeafHash>, KeySource)>)
}
for (key, value) in self.proprietary.iter() { for (key, value) in self.proprietary.iter() {
rv.push(raw::Pair { rv.push(raw::Pair {
key: key.to_key(), key: key.to_key(),
@ -127,9 +223,12 @@ impl Map for Output {
self.bip32_derivation.extend(other.bip32_derivation); self.bip32_derivation.extend(other.bip32_derivation);
self.proprietary.extend(other.proprietary); self.proprietary.extend(other.proprietary);
self.unknown.extend(other.unknown); self.unknown.extend(other.unknown);
self.tap_key_origins.extend(other.tap_key_origins);
merge!(redeem_script, self, other); merge!(redeem_script, self, other);
merge!(witness_script, self, other); merge!(witness_script, self, other);
merge!(tap_internal_key, self, other);
merge!(tap_tree, self, other);
Ok(()) Ok(())
} }

View File

@ -40,7 +40,7 @@ mod macros;
pub mod serialize; pub mod serialize;
mod map; mod map;
pub use self::map::{Map, Input, Output}; pub use self::map::{Map, Input, Output, TapTree};
use util::bip32::{ExtendedPubKey, KeySource}; use util::bip32::{ExtendedPubKey, KeySource};
@ -814,6 +814,87 @@ mod tests {
} }
} }
mod bip_371_vectors {
use super::*;
use super::serialize;
#[test]
fn invalid_vectors() {
let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a075701172102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232000000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid xonly public key");
let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757011342173bb3d36c074afb716fec6307a069a2e450b995f3c82785945ab8df0e24260dcd703b0cbf34de399184a9481ac2b3586db6601f026a77f7e4938481bc34751701aa000000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature len");
let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid xonly public key");
let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid xonly public key");
let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07570000220702fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da7560000800100008000000080010000000000000000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid xonly public key");
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6924214022cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094089756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err();
assert_eq!(err.to_string(), "PSBT error: Hash Parse Error: bad slice length 33 (expected 32)");
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094289756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb01010000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature len");
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature len");
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid control block");
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
assert_eq!(err.to_string(), "parse failed: Invalid control block");
}
fn rtt_psbt(psbt: PartiallySignedTransaction) {
let enc = serialize(&psbt);
let psbt2 = deserialize::<PartiallySignedTransaction>(&enc).unwrap();
assert_eq!(psbt, psbt2);
}
#[test]
fn valid_psbt_vectors() {
let psbt = hex_psbt!("70736274ff010052020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a01000000160014768e1eeb4cf420866033f80aceff0f9720744969000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07572116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232002202036b772a6db74d8753c98a827958de6c78ab3312109f37d3e0304484242ece73d818772b2da7540000800100008000000080000000000000000000").unwrap();
let internal_key = psbt.inputs[0].tap_internal_key.unwrap();
assert!(psbt.inputs[0].tap_key_origins.contains_key(&internal_key));
rtt_psbt(psbt);
// vector 2
let psbt = hex_psbt!("70736274ff010052020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a01000000160014768e1eeb4cf420866033f80aceff0f9720744969000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757011340bb53ec917bad9d906af1ba87181c48b86ace5aae2b53605a725ca74625631476fc6f5baedaf4f2ee0f477f36f58f3970d5b8273b7e497b97af2e3f125c97af342116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232002202036b772a6db74d8753c98a827958de6c78ab3312109f37d3e0304484242ece73d818772b2da7540000800100008000000080000000000000000000").unwrap();
let internal_key = psbt.inputs[0].tap_internal_key.unwrap();
assert!(psbt.inputs[0].tap_key_origins.contains_key(&internal_key));
assert!(psbt.inputs[0].tap_key_sig.is_some());
rtt_psbt(psbt);
// vector 3
let psbt = hex_psbt!("70736274ff01005e020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a0100000022512083698e458c6664e1595d75da2597de1e22ee97d798e706c4c0a4b5a9823cd743000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07572116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232000105201124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e67121071124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e6711900772b2da7560000800100008000000080000000000500000000").unwrap();
let internal_key = psbt.outputs[0].tap_internal_key.unwrap();
assert!(psbt.outputs[0].tap_key_origins.contains_key(&internal_key));
rtt_psbt(psbt);
// vector 4
let psbt = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a0100000022512083698e458c6664e1595d75da2597de1e22ee97d798e706c4c0a4b5a9823cd743000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f823202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc04215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac097c6e6fea5ff714ff5724499990810e406e98aa10f5bf7e5f6784bc1d0a9a6ce23204320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b2acc06215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f82320fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca9acc021162cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d23901cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09772b2da7560000800100008002000080000000000000000021164320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b23901115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f8772b2da75600008001000080010000800000000000000000211650929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac005007c461e5d2116fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca939016f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970772b2da7560000800100008003000080000000000000000001172050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0011820f0362e2f75a6f420a5bde3eb221d96ae6720cf25f81890c95b1d775acb515e65000105201124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e67121071124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e6711900772b2da7560000800100008000000080000000000500000000").unwrap();
assert!(psbt.inputs[0].tap_internal_key.is_some());
assert!(psbt.inputs[0].tap_merkle_root.is_some());
assert!(!psbt.inputs[0].tap_key_origins.is_empty());
assert!(!psbt.inputs[0].tap_scripts.is_empty());
rtt_psbt(psbt);
// vector 5
let psbt = hex_psbt!("70736274ff01005e020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a010000002251200a8cbdc86de1ce1c0f9caeb22d6df7ced3683fe423e05d1e402a879341d6f6f5000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07572116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2320001052050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac001066f02c02220736e572900fe1252589a2143c8f3c79f71a0412d2353af755e9701c782694a02ac02c02220631c5f3b5832b8fbdebfb19704ceeb323c21f40f7a24f43d68ef0cc26b125969ac01c0222044faa49a0338de488c8dfffecdfb6f329f380bd566ef20c8df6d813eab1c4273ac210744faa49a0338de488c8dfffecdfb6f329f380bd566ef20c8df6d813eab1c42733901f06b798b92a10ed9a9d0bbfd3af173a53b1617da3a4159ca008216cd856b2e0e772b2da75600008001000080010000800000000003000000210750929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac005007c461e5d2107631c5f3b5832b8fbdebfb19704ceeb323c21f40f7a24f43d68ef0cc26b125969390118ace409889785e0ea70ceebb8e1ca892a7a78eaede0f2e296cf435961a8f4ca772b2da756000080010000800200008000000000030000002107736e572900fe1252589a2143c8f3c79f71a0412d2353af755e9701c782694a02390129a5b4915090162d759afd3fe0f93fa3326056d0b4088cb933cae7826cb8d82c772b2da7560000800100008003000080000000000300000000").unwrap();
assert!(psbt.outputs[0].tap_internal_key.is_some());
assert!(!psbt.outputs[0].tap_key_origins.is_empty());
assert!(psbt.outputs[0].tap_tree.is_some());
rtt_psbt(psbt);
// vector 6
let psbt = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a0100000022512083698e458c6664e1595d75da2597de1e22ee97d798e706c4c0a4b5a9823cd743000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b0940bf818d9757d6ffeb538ba057fb4c1fc4e0f5ef186e765beb564791e02af5fd3d5e2551d4e34e33d86f276b82c99c79aed3f0395a081efcd2cc2c65dd7e693d7941144320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b2115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f840e1f1ab6fabfa26b236f21833719dc1d428ab768d80f91f9988d8abef47bfb863bb1f2a529f768c15f00ce34ec283cdc07e88f8428be28f6ef64043c32911811a4114fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca96f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae97040ec1f0379206461c83342285423326708ab031f0da4a253ee45aafa5b8c92034d8b605490f8cd13e00f989989b97e215faa36f12dee3693d2daccf3781c1757f66215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f823202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc04215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac097c6e6fea5ff714ff5724499990810e406e98aa10f5bf7e5f6784bc1d0a9a6ce23204320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b2acc06215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f82320fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca9acc021162cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d23901cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09772b2da7560000800100008002000080000000000000000021164320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b23901115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f8772b2da75600008001000080010000800000000000000000211650929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac005007c461e5d2116fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca939016f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970772b2da7560000800100008003000080000000000000000001172050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0011820f0362e2f75a6f420a5bde3eb221d96ae6720cf25f81890c95b1d775acb515e65000105201124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e67121071124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e6711900772b2da7560000800100008000000080000000000500000000").unwrap();
assert!(psbt.inputs[0].tap_internal_key.is_some());
assert!(psbt.inputs[0].tap_merkle_root.is_some());
assert!(!psbt.inputs[0].tap_scripts.is_empty());
assert!(!psbt.inputs[0].tap_script_sigs.is_empty());
assert!(!psbt.inputs[0].tap_key_origins.is_empty());
rtt_psbt(psbt);
}
}
#[test] #[test]
fn serialize_and_deserialize_preimage_psbt(){ fn serialize_and_deserialize_preimage_psbt(){
// create a sha preimage map // create a sha preimage map

View File

@ -24,12 +24,18 @@ use io;
use blockdata::script::Script; use blockdata::script::Script;
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut}; use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
use consensus::encode::{self, serialize, Decodable}; use consensus::encode::{self, serialize, Decodable, Encodable, deserialize_partial};
use secp256k1::schnorrsig;
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; use util::ecdsa::PublicKey;
use util::psbt; use util::psbt;
use util::taproot::{TapBranchHash, TapLeafHash, ControlBlock, LeafVersion};
use schnorr;
use super::map::TapTree;
use util::taproot::TaprootBuilder;
use util::sighash::SchnorrSigHashType;
/// A trait for serializing a value as raw data for insertion into PSBT /// A trait for serializing a value as raw data for insertion into PSBT
/// key-value pairs. /// key-value pairs.
pub trait Serialize { pub trait Serialize {
@ -48,9 +54,14 @@ impl_psbt_de_serialize!(TxOut);
impl_psbt_de_serialize!(Vec<Vec<u8>>); // scriptWitness impl_psbt_de_serialize!(Vec<Vec<u8>>); // scriptWitness
impl_psbt_hash_de_serialize!(ripemd160::Hash); impl_psbt_hash_de_serialize!(ripemd160::Hash);
impl_psbt_hash_de_serialize!(sha256::Hash); impl_psbt_hash_de_serialize!(sha256::Hash);
impl_psbt_hash_de_serialize!(TapLeafHash);
impl_psbt_hash_de_serialize!(TapBranchHash);
impl_psbt_hash_de_serialize!(hash160::Hash); impl_psbt_hash_de_serialize!(hash160::Hash);
impl_psbt_hash_de_serialize!(sha256d::Hash); impl_psbt_hash_de_serialize!(sha256d::Hash);
// taproot
impl_psbt_de_serialize!(Vec<TapLeafHash>);
impl Serialize for Script { impl Serialize for Script {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> {
self.to_bytes() self.to_bytes()
@ -80,7 +91,7 @@ impl Deserialize for PublicKey {
impl Serialize for KeySource { impl Serialize for KeySource {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> {
let mut rv: Vec<u8> = Vec::with_capacity(4 + 4 * (self.1).as_ref().len()); let mut rv: Vec<u8> = Vec::with_capacity(key_source_len(&self));
rv.append(&mut self.0.to_bytes().to_vec()); rv.append(&mut self.0.to_bytes().to_vec());
@ -144,3 +155,170 @@ impl Deserialize for EcdsaSigHashType {
} }
} }
} }
// Taproot related ser/deser
impl Serialize for schnorr::PublicKey {
fn serialize(&self) -> Vec<u8> {
schnorr::PublicKey::serialize(&self).to_vec()
}
}
impl Deserialize for schnorr::PublicKey {
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
schnorr::PublicKey::from_slice(bytes)
.map_err(|_| encode::Error::ParseFailed("Invalid xonly public key"))
}
}
impl Serialize for schnorr::SchnorrSig {
fn serialize(&self) -> Vec<u8> {
self.to_vec()
}
}
impl Deserialize for schnorr::SchnorrSig {
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
match bytes.len() {
65 => {
let hash_ty = SchnorrSigHashType::from_u8(bytes[64])
.map_err(|_| encode::Error::ParseFailed("Invalid Sighash type"))?;
let sig = schnorrsig::Signature::from_slice(&bytes[..64])
.map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?;
Ok(schnorr::SchnorrSig{ sig, hash_ty })
}
64 => {
let sig = schnorrsig::Signature::from_slice(&bytes[..64])
.map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?;
Ok(schnorr::SchnorrSig{ sig, hash_ty: SchnorrSigHashType::Default })
}
_ => Err(encode::Error::ParseFailed("Invalid Schnorr signature len"))
}
}
}
impl Serialize for (schnorr::PublicKey, TapLeafHash) {
fn serialize(&self) -> Vec<u8> {
let ser_pk = self.0.serialize();
let mut buf = Vec::with_capacity(ser_pk.len() + self.1.as_ref().len());
buf.extend(&ser_pk);
buf.extend(self.1.as_ref());
buf
}
}
impl Deserialize for (schnorr::PublicKey, TapLeafHash) {
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
if bytes.len() < 32 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
}
let a: schnorr::PublicKey = Deserialize::deserialize(&bytes[..32])?;
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
Ok((a, b))
}
}
impl Serialize for ControlBlock {
fn serialize(&self) -> Vec<u8> {
ControlBlock::serialize(&self)
}
}
impl Deserialize for ControlBlock {
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
Self::from_slice(bytes)
.map_err(|_| encode::Error::ParseFailed("Invalid control block"))
}
}
// Versioned Script
impl Serialize for (Script, LeafVersion) {
fn serialize(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(self.0.len() + 1);
buf.extend(self.0.as_bytes());
buf.push(self.1.as_u8());
buf
}
}
impl Deserialize for (Script, LeafVersion) {
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
if bytes.is_empty() {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
}
// The last byte is LeafVersion.
let script = Script::deserialize(&bytes[..bytes.len() - 1])?;
let leaf_ver = LeafVersion::from_u8(bytes[bytes.len() - 1])
.map_err(|_| encode::Error::ParseFailed("invalid leaf version"))?;
Ok((script, leaf_ver))
}
}
impl Serialize for (Vec<TapLeafHash>, KeySource) {
fn serialize(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity( 32 * self.0.len() + key_source_len(&self.1));
self.0.consensus_encode(&mut buf).expect("Vecs don't error allocation");
// TODO: Add support for writing into a writer for key-source
buf.extend(self.1.serialize());
buf
}
}
impl Deserialize for (Vec<TapLeafHash>, KeySource) {
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
let (leafhash_vec, consumed) = deserialize_partial::<Vec::<TapLeafHash>>(&bytes)?;
let key_source = KeySource::deserialize(&bytes[consumed..])?;
Ok((leafhash_vec, key_source))
}
}
impl Serialize for TapTree {
fn serialize(&self) -> Vec<u8> {
match (self.0.branch().len(), self.0.branch().last()) {
(1, Some(Some(root))) => {
let mut buf = Vec::new();
for leaf_info in root.leaves.iter() {
// # Cast Safety:
//
// TaprootMerkleBranch can only have len atmost 128(TAPROOT_CONTROL_MAX_NODE_COUNT).
// safe to cast from usize to u8
buf.push(leaf_info.merkle_branch.as_inner().len() as u8);
buf.push(leaf_info.ver.as_u8());
leaf_info.script.consensus_encode(&mut buf).expect("Vecs dont err");
}
buf
}
// This should be unreachable as we Taptree is already finalized
_ => unreachable!(),
}
}
}
impl Deserialize for TapTree {
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
let mut builder = TaprootBuilder::new();
let mut bytes_iter = bytes.iter();
while let Some(depth) = bytes_iter.next() {
let version = bytes_iter.next().ok_or(encode::Error::ParseFailed("Invalid Taproot Builder"))?;
let (script, consumed) = deserialize_partial::<Script>(bytes_iter.as_slice())?;
if consumed > 0 {
bytes_iter.nth(consumed - 1);
}
let leaf_version = LeafVersion::from_u8(*version)
.map_err(|_| encode::Error::ParseFailed("Leaf Version Error"))?;
builder = builder.add_leaf_with_ver(usize::from(*depth), script, leaf_version)
.map_err(|_| encode::Error::ParseFailed("Tree not in DFS order"))?;
}
if builder.is_complete() {
Ok(TapTree(builder))
} else {
Err(encode::Error::ParseFailed("Incomplete taproot Tree"))
}
}
}
// Helper function to compute key source len
fn key_source_len(key_source: &KeySource) -> usize {
4 + 4 * (key_source.1).as_ref().len()
}

View File

@ -110,6 +110,7 @@ impl TweakedPublicKey {
/// A BIP340-341 serialized schnorr signature with the corresponding hash type. /// A BIP340-341 serialized schnorr signature with the corresponding hash type.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SchnorrSig { pub struct SchnorrSig {
/// The underlying schnorr signature /// The underlying schnorr signature
pub sig: secp256k1::schnorrsig::Signature, pub sig: secp256k1::schnorrsig::Signature,

View File

@ -104,6 +104,7 @@ pub struct ScriptPath<'s> {
/// Hashtype of an input's signature, encoded in the last byte of the signature /// Hashtype of an input's signature, encoded in the last byte of the signature
/// Fixed values so they can be casted as integer types for encoding /// Fixed values so they can be casted as integer types for encoding
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum SchnorrSigHashType { pub enum SchnorrSigHashType {
/// 0x0: Used when not explicitly specified, defaulting to [`SchnorrSigHashType::All`] /// 0x0: Used when not explicitly specified, defaulting to [`SchnorrSigHashType::All`]
Default = 0x00, Default = 0x00,

View File

@ -68,6 +68,7 @@ macro_rules! sha256t_hash_newtype {
#[doc = "The tag used for ["] #[doc = "The tag used for ["]
#[doc = $sname] #[doc = $sname]
#[doc = "]"] #[doc = "]"]
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct $tag; pub struct $tag;
impl sha256t::Tag for $tag { impl sha256t::Tag for $tag {
@ -345,6 +346,7 @@ impl TaprootSpendInfo {
/// branches in a DFS(Depth first search) walk to construct this tree. /// branches in a DFS(Depth first search) walk to construct this tree.
// Similar to Taproot Builder in bitcoin core // Similar to Taproot Builder in bitcoin core
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaprootBuilder { pub struct TaprootBuilder {
// The following doc-comment is from bitcoin core, but modified for rust // The following doc-comment is from bitcoin core, but modified for rust
// The comment below describes the current state of the builder for a given tree. // The comment below describes the current state of the builder for a given tree.
@ -418,6 +420,11 @@ impl TaprootBuilder {
self.insert(node, depth) self.insert(node, depth)
} }
/// Check if the builder is a complete tree
pub fn is_complete(&self) -> bool {
self.branch.len() == 1 && self.branch[0].is_some()
}
/// Create [`TaprootSpendInfo`] with the given internal key /// Create [`TaprootSpendInfo`] with the given internal key
pub fn finalize<C: secp256k1::Verification>( pub fn finalize<C: secp256k1::Verification>(
mut self, mut self,
@ -435,6 +442,10 @@ impl TaprootBuilder {
Ok(TaprootSpendInfo::from_node_info(secp, internal_key, node)) Ok(TaprootSpendInfo::from_node_info(secp, internal_key, node))
} }
pub(crate) fn branch(&self) -> &[Option<NodeInfo>]{
&self.branch
}
// Helper function to insert a leaf at a depth // Helper function to insert a leaf at a depth
fn insert(mut self, mut node: NodeInfo, mut depth: usize) -> Result<Self, TaprootBuilderError> { fn insert(mut self, mut node: NodeInfo, mut depth: usize) -> Result<Self, TaprootBuilderError> {
// early error on invalid depth. Though this will be checked later // early error on invalid depth. Though this will be checked later
@ -484,11 +495,12 @@ impl TaprootBuilder {
// Internally used structure to represent the node information in taproot tree // Internally used structure to represent the node information in taproot tree
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct NodeInfo { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub(crate) struct NodeInfo {
/// Merkle Hash for this node /// Merkle Hash for this node
hash: sha256::Hash, pub(crate) hash: sha256::Hash,
/// information about leaves inside this node /// information about leaves inside this node
leaves: Vec<LeafInfo>, pub(crate) leaves: Vec<LeafInfo>,
} }
impl NodeInfo { impl NodeInfo {
@ -537,13 +549,14 @@ impl NodeInfo {
// Internally used structure to store information about taproot leaf node // Internally used structure to store information about taproot leaf node
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct LeafInfo { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub(crate) struct LeafInfo {
// The underlying script // The underlying script
script: Script, pub(crate) script: Script,
// The leaf version // The leaf version
ver: LeafVersion, pub(crate) ver: LeafVersion,
// The merkle proof(hashing partners) to get this node // The merkle proof(hashing partners) to get this node
merkle_branch: TaprootMerkleBranch, pub(crate) merkle_branch: TaprootMerkleBranch,
} }
impl LeafInfo { impl LeafInfo {
@ -567,6 +580,7 @@ impl LeafInfo {
// The type of hash is sha256::Hash because the vector might contain // The type of hash is sha256::Hash because the vector might contain
// both TapBranchHash and TapLeafHash // both TapBranchHash and TapLeafHash
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaprootMerkleBranch(Vec<sha256::Hash>); pub struct TaprootMerkleBranch(Vec<sha256::Hash>);
impl TaprootMerkleBranch { impl TaprootMerkleBranch {
@ -638,6 +652,7 @@ impl TaprootMerkleBranch {
/// Control Block data structure used in Tapscript satisfaction /// Control Block data structure used in Tapscript satisfaction
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ControlBlock { pub struct ControlBlock {
/// The tapleaf version, /// The tapleaf version,
pub leaf_version: LeafVersion, pub leaf_version: LeafVersion,
@ -744,6 +759,7 @@ impl ControlBlock {
/// The leaf version for tapleafs /// The leaf version for tapleafs
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct LeafVersion(u8); pub struct LeafVersion(u8);
impl Default for LeafVersion { impl Default for LeafVersion {