diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index eea64036..ec2aa198 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -39,6 +39,7 @@ use io::{self, Cursor, Read}; use util::endian; use util::psbt; +use util::taproot::TapLeafHash; use hashes::hex::ToHex; use blockdata::transaction::{TxOut, Transaction, TxIn}; @@ -594,6 +595,7 @@ impl_vec!(TxOut); impl_vec!(TxIn); impl_vec!(Vec); impl_vec!(u64); +impl_vec!(TapLeafHash); #[cfg(feature = "std")] impl_vec!(Inventory); #[cfg(feature = "std")] impl_vec!((u32, Address)); @@ -767,6 +769,18 @@ impl Decodable for sha256::Hash { } } +impl Encodable for TapLeafHash { + fn consensus_encode(&self, s: S) -> Result { + self.into_inner().consensus_encode(s) + } +} + +impl Decodable for TapLeafHash { + fn consensus_decode(d: D) -> Result { + Ok(Self::from_inner(<::Inner>::consensus_decode(d)?)) + } +} + // Tests #[cfg(test)] mod tests { diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index e6481b4e..a443f402 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -28,6 +28,9 @@ use util::psbt::raw; use util::psbt::serialize::Deserialize; use util::psbt::{Error, error}; +use schnorr; +use util::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash}; + /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00; /// Type: Witness UTXO PSBT_IN_WITNESS_UTXO = 0x01 @@ -54,6 +57,18 @@ const PSBT_IN_SHA256: u8 = 0x0b; const PSBT_IN_HASH160: u8 = 0x0c; /// Type: HASH256 preimage PSBT_IN_HASH256 = 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 const PSBT_IN_PROPRIETARY: u8 = 0xFC; @@ -104,6 +119,21 @@ pub struct Input { /// HAS256 hash to preimage map #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))] pub hash256_preimages: BTreeMap>, + /// Serialized schnorr signature with sighash type for key spend + pub tap_key_sig: Option, + /// Map of | 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, + /// 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, KeySource)>, + /// Taproot Internal key + pub tap_internal_key : Option, + /// Taproot Merkle root + pub tap_merkle_root : Option, /// Proprietary key-value pairs for this input. #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))] pub proprietary: BTreeMap>, @@ -177,6 +207,36 @@ impl Map for Input { PSBT_IN_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 <= | + } + } + PSBT_IN_TAP_SCRIPT_SIG => { + impl_psbt_insert_pair! { + self.tap_script_sigs <= | + } + } + PSBT_IN_TAP_LEAF_SCRIPT=> { + impl_psbt_insert_pair! { + self.tap_scripts <= |< raw_value: (Script, LeafVersion)> + } + } + PSBT_IN_TAP_BIP32_DERIVATION => { + impl_psbt_insert_pair! { + self.tap_key_origins <= |< raw_value: (Vec, KeySource)> + } + } + PSBT_IN_TAP_INTERNAL_KEY => { + impl_psbt_insert_pair! { + self.tap_internal_key <= |< raw_value: schnorr::PublicKey> + } + } + PSBT_IN_TAP_MERKLE_ROOT => { + impl_psbt_insert_pair! { + self.tap_merkle_root <= |< raw_value: TapBranchHash> + } + } 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::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), @@ -249,6 +309,30 @@ impl Map for Input { rv.push(self.hash256_preimages as |>) } + impl_psbt_get_pair! { + rv.push(self.tap_key_sig as |>) + } + + impl_psbt_get_pair! { + rv.push(self.tap_script_sigs as |>) + } + + impl_psbt_get_pair! { + rv.push(self.tap_scripts as |<(Script, LeafVersion)>) + } + + impl_psbt_get_pair! { + rv.push(self.tap_key_origins as |<(Vec, KeySource)>) + } + + impl_psbt_get_pair! { + rv.push(self.tap_internal_key as |) + } + + impl_psbt_get_pair! { + rv.push(self.tap_merkle_root as |) + } for (key, value) in self.proprietary.iter() { rv.push(raw::Pair { key: key.to_key(), @@ -280,6 +364,9 @@ impl Map for Input { self.sha256_preimages.extend(other.sha256_preimages); self.hash160_preimages.extend(other.hash160_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.unknown.extend(other.unknown); @@ -287,6 +374,9 @@ impl Map for Input { merge!(witness_script, self, other); merge!(final_script_sig, 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(()) } diff --git a/src/util/psbt/map/mod.rs b/src/util/psbt/map/mod.rs index 94506bc5..a40de9d2 100644 --- a/src/util/psbt/map/mod.rs +++ b/src/util/psbt/map/mod.rs @@ -55,3 +55,4 @@ mod output; pub use self::input::Input; pub use self::output::Output; +pub use self::output::TapTree; diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index 119f8c61..75e764c6 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -25,12 +25,23 @@ use util::psbt::map::Map; use util::psbt::raw; use util::psbt::Error; +use schnorr; +use util::taproot::TapLeafHash; + +use util::taproot::{NodeInfo, TaprootBuilder}; + /// Type: Redeem Script PSBT_OUT_REDEEM_SCRIPT = 0x00 const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00; /// Type: Witness Script PSBT_OUT_WITNESS_SCRIPT = 0x01 const PSBT_OUT_WITNESS_SCRIPT: u8 = 0x01; /// Type: BIP 32 Derivation Path PSBT_OUT_BIP32_DERIVATION = 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 const PSBT_OUT_PROPRIETARY: u8 = 0xFC; @@ -47,14 +58,67 @@ pub struct Output { /// corresponding master key fingerprints and derivation paths. #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))] pub bip32_derivation: BTreeMap, + /// The internal pubkey + pub tap_internal_key: Option, + /// Taproot Output tree + pub tap_tree: Option, + /// 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, KeySource)>, /// 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>, /// 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>, } +/// 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 { + 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 { fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { let raw::Pair { @@ -82,10 +146,29 @@ impl Map for Output { btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), } - _ => 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()), + PSBT_OUT_TAP_INTERNAL_KEY => { + impl_psbt_insert_pair! { + self.tap_internal_key <= | + } } + PSBT_OUT_TAP_TREE => { + impl_psbt_insert_pair! { + self.tap_tree <= | + } + } + PSBT_OUT_TAP_BIP32_DERIVATION => { + impl_psbt_insert_pair! { + self.tap_key_origins <= |< raw_value: (Vec, 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(()) @@ -106,6 +189,19 @@ impl Map for Output { rv.push(self.bip32_derivation as |) } + impl_psbt_get_pair! { + rv.push(self.tap_internal_key as |) + } + + impl_psbt_get_pair! { + rv.push(self.tap_tree as |) + } + + impl_psbt_get_pair! { + rv.push(self.tap_key_origins as |<(Vec, KeySource)>) + } + for (key, value) in self.proprietary.iter() { rv.push(raw::Pair { key: key.to_key(), @@ -127,9 +223,12 @@ impl Map for Output { self.bip32_derivation.extend(other.bip32_derivation); self.proprietary.extend(other.proprietary); self.unknown.extend(other.unknown); + self.tap_key_origins.extend(other.tap_key_origins); merge!(redeem_script, self, other); merge!(witness_script, self, other); + merge!(tap_internal_key, self, other); + merge!(tap_tree, self, other); Ok(()) } diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index a02db4be..6e3b4a03 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -40,7 +40,7 @@ mod macros; pub mod serialize; mod map; -pub use self::map::{Map, Input, Output}; +pub use self::map::{Map, Input, Output, TapTree}; 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::(&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] fn serialize_and_deserialize_preimage_psbt(){ // create a sha preimage map diff --git a/src/util/psbt/serialize.rs b/src/util/psbt/serialize.rs index 99e2cf61..7c9e7687 100644 --- a/src/util/psbt/serialize.rs +++ b/src/util/psbt/serialize.rs @@ -24,12 +24,18 @@ use io; use blockdata::script::Script; 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 hashes::{hash160, ripemd160, sha256, sha256d, Hash}; use util::ecdsa::PublicKey; 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 /// key-value pairs. pub trait Serialize { @@ -48,9 +54,14 @@ impl_psbt_de_serialize!(TxOut); impl_psbt_de_serialize!(Vec>); // scriptWitness impl_psbt_hash_de_serialize!(ripemd160::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!(sha256d::Hash); +// taproot +impl_psbt_de_serialize!(Vec); + impl Serialize for Script { fn serialize(&self) -> Vec { self.to_bytes() @@ -80,7 +91,7 @@ impl Deserialize for PublicKey { impl Serialize for KeySource { fn serialize(&self) -> Vec { - let mut rv: Vec = Vec::with_capacity(4 + 4 * (self.1).as_ref().len()); + let mut rv: Vec = Vec::with_capacity(key_source_len(&self)); 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 { + schnorr::PublicKey::serialize(&self).to_vec() + } +} + +impl Deserialize for schnorr::PublicKey { + fn deserialize(bytes: &[u8]) -> Result { + schnorr::PublicKey::from_slice(bytes) + .map_err(|_| encode::Error::ParseFailed("Invalid xonly public key")) + } +} + +impl Serialize for schnorr::SchnorrSig { + fn serialize(&self) -> Vec { + self.to_vec() + } +} + +impl Deserialize for schnorr::SchnorrSig { + fn deserialize(bytes: &[u8]) -> Result { + 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 { + 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 { + 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 { + ControlBlock::serialize(&self) + } +} + +impl Deserialize for ControlBlock { + fn deserialize(bytes: &[u8]) -> Result { + Self::from_slice(bytes) + .map_err(|_| encode::Error::ParseFailed("Invalid control block")) + } +} + +// Versioned Script +impl Serialize for (Script, LeafVersion) { + fn serialize(&self) -> Vec { + 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 { + 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, KeySource) { + fn serialize(&self) -> Vec { + 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, KeySource) { + fn deserialize(bytes: &[u8]) -> Result { + let (leafhash_vec, consumed) = deserialize_partial::>(&bytes)?; + let key_source = KeySource::deserialize(&bytes[consumed..])?; + Ok((leafhash_vec, key_source)) + } +} + +impl Serialize for TapTree { + fn serialize(&self) -> Vec { + 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 { + 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::