Merge rust-bitcoin/rust-bitcoin#1479: Unify `TapLeafHash` and `TapBranchHash` into `TapNodeHash` while tree construction
f39cd88f5f
Use TapNodeHash in NodeInfo (sanket1729)5ff2635585
Rename TapBranchHash -> TapNodeHash (sanket1729) Pull request description: This does not completely fix #1393 but is a simple starter. Unfortunately, we still need hash_new_type for `TapNodeHash` because is exported as the Merkle root in taproot psbt. This requires serialization and display/from_str methods. This also adds a method 1) `TapNodeHash::from_script` to deal with single leaf case cleanly. As a nice side effect, this removes the ugly uses of `sha256::Hash` that I had used to represent both `TapLeafHash` and `TapBranchHash` Does not fix 1) Exporting `TapTweakHash`. This requires some changes to macros we use. 2) Safer usage of `TapNodeHash` by not making it `hash_new_type` and having guarded constructors. As mentioned above, this is required for psbts and sharing Merkle roots. Perhaps, we might need a new type while constructing trees that is not `hash_new_type`, and convert it to another type that represents the final Merkle root. My overall feeling is that this is best addressed with more examples than changing and complicating existing code. I don't feel strongly about the rename, so can go back if `TapBranchHash` instead of `TapNodeHash`. ACKs for top commit: Kixunil: ACKf39cd88f5f
tcharding: ACKf39cd88f5f
Tree-SHA512: 55310b89442ac1f73cce8a7202bbed6ac5a0bbefec0a938fe6065e65c65fe1d34c9e2b5e30ce56ae2bbd0cc9e4caa1363dbd03e9feb7929acb47bbac9f2a4191
This commit is contained in:
commit
8df00339ec
|
@ -50,7 +50,7 @@ use crate::hash_types::{PubkeyHash, ScriptHash};
|
||||||
use crate::hashes::{sha256, Hash, HashEngine};
|
use crate::hashes::{sha256, Hash, HashEngine};
|
||||||
use crate::network::constants::Network;
|
use crate::network::constants::Network;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::taproot::TapBranchHash;
|
use crate::taproot::TapNodeHash;
|
||||||
|
|
||||||
/// Address error.
|
/// Address error.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
@ -479,7 +479,7 @@ impl Payload {
|
||||||
pub fn p2tr<C: Verification>(
|
pub fn p2tr<C: Verification>(
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
internal_key: UntweakedPublicKey,
|
internal_key: UntweakedPublicKey,
|
||||||
merkle_root: Option<TapBranchHash>,
|
merkle_root: Option<TapNodeHash>,
|
||||||
) -> Payload {
|
) -> Payload {
|
||||||
let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
|
let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
|
||||||
Payload::WitnessProgram {
|
Payload::WitnessProgram {
|
||||||
|
@ -627,7 +627,7 @@ impl Address {
|
||||||
pub fn p2tr<C: Verification>(
|
pub fn p2tr<C: Verification>(
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
internal_key: UntweakedPublicKey,
|
internal_key: UntweakedPublicKey,
|
||||||
merkle_root: Option<TapBranchHash>,
|
merkle_root: Option<TapNodeHash>,
|
||||||
network: Network,
|
network: Network,
|
||||||
) -> Address {
|
) -> Address {
|
||||||
Address { network, payload: Payload::p2tr(secp, internal_key, merkle_root) }
|
Address { network, payload: Payload::p2tr(secp, internal_key, merkle_root) }
|
||||||
|
|
|
@ -76,7 +76,7 @@ use crate::OutPoint;
|
||||||
|
|
||||||
use crate::key::PublicKey;
|
use crate::key::PublicKey;
|
||||||
use crate::address::WitnessVersion;
|
use crate::address::WitnessVersion;
|
||||||
use crate::taproot::{LeafVersion, TapBranchHash, TapLeafHash};
|
use crate::taproot::{LeafVersion, TapNodeHash, TapLeafHash};
|
||||||
use secp256k1::{Secp256k1, Verification, XOnlyPublicKey};
|
use secp256k1::{Secp256k1, Verification, XOnlyPublicKey};
|
||||||
use crate::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey};
|
use crate::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey};
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ impl Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_v1_p2tr<C: Verification>(&self, secp: &Secp256k1<C>, internal_key: UntweakedPublicKey) -> ScriptBuf {
|
pub fn to_v1_p2tr<C: Verification>(&self, secp: &Secp256k1<C>, internal_key: UntweakedPublicKey) -> ScriptBuf {
|
||||||
let leaf_hash = self.tapscript_leaf_hash();
|
let leaf_hash = self.tapscript_leaf_hash();
|
||||||
let merkle_root = TapBranchHash::from_inner(leaf_hash.into_inner());
|
let merkle_root = TapNodeHash::from(leaf_hash);
|
||||||
ScriptBuf::new_v1_p2tr(secp, internal_key, Some(merkle_root))
|
ScriptBuf::new_v1_p2tr(secp, internal_key, Some(merkle_root))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,7 +1133,7 @@ impl ScriptBuf {
|
||||||
|
|
||||||
/// Generates P2TR for script spending path using an internal public key and some optional
|
/// Generates P2TR for script spending path using an internal public key and some optional
|
||||||
/// script tree merkle root.
|
/// script tree merkle root.
|
||||||
pub fn new_v1_p2tr<C: Verification>(secp: &Secp256k1<C>, internal_key: UntweakedPublicKey, merkle_root: Option<TapBranchHash>) -> Self {
|
pub fn new_v1_p2tr<C: Verification>(secp: &Secp256k1<C>, internal_key: UntweakedPublicKey, merkle_root: Option<TapNodeHash>) -> Self {
|
||||||
let (output_key, _) = internal_key.tap_tweak(secp, merkle_root);
|
let (output_key, _) = internal_key.tap_tweak(secp, merkle_root);
|
||||||
ScriptBuf::new_witness_program(WitnessVersion::V1, &output_key.serialize())
|
ScriptBuf::new_witness_program(WitnessVersion::V1, &output_key.serialize())
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verific
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::taproot::{TapBranchHash, TapTweakHash};
|
use crate::taproot::{TapNodeHash, TapTweakHash};
|
||||||
use crate::sighash::SchnorrSighashType;
|
use crate::sighash::SchnorrSighashType;
|
||||||
|
|
||||||
/// Untweaked BIP-340 X-coord-only public key
|
/// Untweaked BIP-340 X-coord-only public key
|
||||||
|
@ -69,7 +69,7 @@ pub trait TapTweak {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The tweaked key and its parity.
|
/// The tweaked key and its parity.
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> Self::TweakedAux;
|
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> Self::TweakedAux;
|
||||||
|
|
||||||
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
|
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
|
||||||
///
|
///
|
||||||
|
@ -94,7 +94,7 @@ impl TapTweak for UntweakedPublicKey {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The tweaked key and its parity.
|
/// The tweaked key and its parity.
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> (TweakedPublicKey, secp256k1::Parity) {
|
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> (TweakedPublicKey, secp256k1::Parity) {
|
||||||
let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar();
|
let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar();
|
||||||
let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed");
|
let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed");
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ impl TapTweak for UntweakedKeyPair {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The tweaked key and its parity.
|
/// The tweaked key and its parity.
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> TweakedKeyPair {
|
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> TweakedKeyPair {
|
||||||
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self);
|
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self);
|
||||||
let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar();
|
let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar();
|
||||||
let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed");
|
let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed");
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::psbt::map::Map;
|
||||||
use crate::psbt::serialize::Deserialize;
|
use crate::psbt::serialize::Deserialize;
|
||||||
use crate::psbt::{self, error, raw, Error};
|
use crate::psbt::{self, error, raw, Error};
|
||||||
use crate::sighash::{self, NonStandardSighashType, SighashTypeParseError, EcdsaSighashType, SchnorrSighashType};
|
use crate::sighash::{self, NonStandardSighashType, SighashTypeParseError, EcdsaSighashType, SchnorrSighashType};
|
||||||
use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash};
|
use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash};
|
||||||
|
|
||||||
/// 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;
|
||||||
|
@ -124,7 +124,7 @@ pub struct Input {
|
||||||
/// Taproot Internal key.
|
/// Taproot Internal key.
|
||||||
pub tap_internal_key: Option<XOnlyPublicKey>,
|
pub tap_internal_key: Option<XOnlyPublicKey>,
|
||||||
/// Taproot Merkle root.
|
/// Taproot Merkle root.
|
||||||
pub tap_merkle_root: Option<TapBranchHash>,
|
pub tap_merkle_root: Option<TapNodeHash>,
|
||||||
/// Proprietary key-value pairs for this input.
|
/// Proprietary key-value pairs for this input.
|
||||||
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
|
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
|
||||||
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
|
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
|
||||||
|
@ -338,7 +338,7 @@ impl Input {
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_MERKLE_ROOT => {
|
PSBT_IN_TAP_MERKLE_ROOT => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.tap_merkle_root <= <raw_key: _>|< raw_value: TapBranchHash>
|
self.tap_merkle_root <= <raw_key: _>|< raw_value: TapNodeHash>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_PROPRIETARY => {
|
PSBT_IN_PROPRIETARY => {
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::bip32::{ChildNumber, Fingerprint, KeySource};
|
||||||
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
||||||
use crate::crypto::{ecdsa, schnorr};
|
use crate::crypto::{ecdsa, schnorr};
|
||||||
use crate::psbt::{self, Error, PartiallySignedTransaction};
|
use crate::psbt::{self, Error, PartiallySignedTransaction};
|
||||||
use crate::taproot::{TapBranchHash, TapLeafHash, ControlBlock, LeafVersion};
|
use crate::taproot::{TapNodeHash, TapLeafHash, ControlBlock, LeafVersion};
|
||||||
use crate::crypto::key::PublicKey;
|
use crate::crypto::key::PublicKey;
|
||||||
|
|
||||||
use super::map::{Map, Input, Output, TapTree, PsbtSighashType};
|
use super::map::{Map, Input, Output, TapTree, PsbtSighashType};
|
||||||
|
@ -123,7 +123,7 @@ impl_psbt_de_serialize!(Witness);
|
||||||
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!(TapLeafHash);
|
||||||
impl_psbt_hash_de_serialize!(TapBranchHash);
|
impl_psbt_hash_de_serialize!(TapNodeHash);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -460,7 +460,7 @@ mod tests {
|
||||||
fn taptree_hidden() {
|
fn taptree_hidden() {
|
||||||
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2]);
|
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2]);
|
||||||
builder = builder.add_leaf_with_ver(3, ScriptBuf::from_hex("b9").unwrap(), LeafVersion::from_consensus(0xC2).unwrap()).unwrap();
|
builder = builder.add_leaf_with_ver(3, ScriptBuf::from_hex("b9").unwrap(), LeafVersion::from_consensus(0xC2).unwrap()).unwrap();
|
||||||
builder = builder.add_hidden_node(3, sha256::Hash::all_zeros()).unwrap();
|
builder = builder.add_hidden_node(3, TapNodeHash::all_zeros()).unwrap();
|
||||||
assert!(TapTree::try_from(builder).is_err());
|
assert!(TapTree::try_from(builder).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1391,7 +1391,7 @@ mod tests {
|
||||||
use secp256k1::{self, SecretKey, XOnlyPublicKey};
|
use secp256k1::{self, SecretKey, XOnlyPublicKey};
|
||||||
|
|
||||||
use crate::consensus::serde as con_serde;
|
use crate::consensus::serde as con_serde;
|
||||||
use crate::taproot::{TapBranchHash, TapTweakHash};
|
use crate::taproot::{TapNodeHash, TapTweakHash};
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
#[serde(crate = "actual_serde")]
|
#[serde(crate = "actual_serde")]
|
||||||
|
@ -1428,7 +1428,7 @@ mod tests {
|
||||||
struct KpsInputSpendingGiven {
|
struct KpsInputSpendingGiven {
|
||||||
txin_index: usize,
|
txin_index: usize,
|
||||||
internal_privkey: SecretKey,
|
internal_privkey: SecretKey,
|
||||||
merkle_root: Option<TapBranchHash>,
|
merkle_root: Option<TapNodeHash>,
|
||||||
#[serde(deserialize_with = "sighash_deser_numeric")]
|
#[serde(deserialize_with = "sighash_deser_numeric")]
|
||||||
hash_type: SchnorrSighashType,
|
hash_type: SchnorrSighashType,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use secp256k1::{self, Scalar, Secp256k1};
|
||||||
|
|
||||||
use crate::consensus::Encodable;
|
use crate::consensus::Encodable;
|
||||||
use crate::crypto::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey};
|
use crate::crypto::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey};
|
||||||
use crate::hashes::{sha256, sha256t_hash_newtype, Hash, HashEngine};
|
use crate::hashes::{sha256t_hash_newtype, Hash, HashEngine};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::{io, Script, ScriptBuf};
|
use crate::{io, Script, ScriptBuf};
|
||||||
|
|
||||||
|
@ -49,19 +49,22 @@ const MIDSTATE_TAPSIGHASH: [u8; 32] = [
|
||||||
// Taproot test vectors from BIP-341 state the hashes without any reversing
|
// Taproot test vectors from BIP-341 state the hashes without any reversing
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
sha256t_hash_newtype!(TapLeafHash, TapLeafTag, MIDSTATE_TAPLEAF, 64,
|
sha256t_hash_newtype!(TapLeafHash, TapLeafTag, MIDSTATE_TAPLEAF, 64,
|
||||||
doc="Taproot-tagged hash for tapscript Merkle tree leafs", false
|
doc="Taproot-tagged hash with tag \"TapLeaf\".
|
||||||
|
This is used for computing tapscript script spend hash.", false
|
||||||
);
|
);
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
sha256t_hash_newtype!(TapBranchHash, TapBranchTag, MIDSTATE_TAPBRANCH, 64,
|
sha256t_hash_newtype!(TapNodeHash, TapBranchTag, MIDSTATE_TAPBRANCH, 64,
|
||||||
doc="Taproot-tagged hash for tapscript Merkle tree branches", false
|
doc="Tagged hash used in taproot trees; see BIP-340 for tagging rules", false
|
||||||
);
|
);
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
sha256t_hash_newtype!(TapTweakHash, TapTweakTag, MIDSTATE_TAPTWEAK, 64,
|
sha256t_hash_newtype!(TapTweakHash, TapTweakTag, MIDSTATE_TAPTWEAK, 64,
|
||||||
doc="Taproot-tagged hash for public key tweaks", false
|
doc="Taproot-tagged hash with tag \"TapTweak\".
|
||||||
|
This hash type is used while computing the tweaked public key", false
|
||||||
);
|
);
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
sha256t_hash_newtype!(TapSighashHash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64,
|
sha256t_hash_newtype!(TapSighashHash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64,
|
||||||
doc="Taproot-tagged hash for the taproot signature hash", false
|
doc="Taproot-tagged hash with tag \"TapSighash\".
|
||||||
|
This hash type is used for computing taproot signature hash.", false
|
||||||
);
|
);
|
||||||
|
|
||||||
impl secp256k1::ThirtyTwoByteHash for TapSighashHash {
|
impl secp256k1::ThirtyTwoByteHash for TapSighashHash {
|
||||||
|
@ -73,7 +76,7 @@ impl TapTweakHash {
|
||||||
/// `P` is the internal key and `R` is the merkle root.
|
/// `P` is the internal key and `R` is the merkle root.
|
||||||
pub fn from_key_and_tweak(
|
pub fn from_key_and_tweak(
|
||||||
internal_key: UntweakedPublicKey,
|
internal_key: UntweakedPublicKey,
|
||||||
merkle_root: Option<TapBranchHash>,
|
merkle_root: Option<TapNodeHash>,
|
||||||
) -> TapTweakHash {
|
) -> TapTweakHash {
|
||||||
let mut eng = TapTweakHash::engine();
|
let mut eng = TapTweakHash::engine();
|
||||||
// always hash the key
|
// always hash the key
|
||||||
|
@ -111,10 +114,10 @@ impl From<&ScriptLeaf> for TapLeafHash {
|
||||||
fn from(leaf: &ScriptLeaf) -> TapLeafHash { leaf.leaf_hash() }
|
fn from(leaf: &ScriptLeaf) -> TapLeafHash { leaf.leaf_hash() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TapBranchHash {
|
impl TapNodeHash {
|
||||||
/// Computes branch hash given two hashes of the nodes underneath it.
|
/// Computes branch hash given two hashes of the nodes underneath it.
|
||||||
pub fn from_node_hashes(a: sha256::Hash, b: sha256::Hash) -> TapBranchHash {
|
pub fn from_node_hashes(a: TapNodeHash, b: TapNodeHash) -> TapNodeHash {
|
||||||
let mut eng = TapBranchHash::engine();
|
let mut eng = TapNodeHash::engine();
|
||||||
if a < b {
|
if a < b {
|
||||||
eng.input(a.as_ref());
|
eng.input(a.as_ref());
|
||||||
eng.input(b.as_ref());
|
eng.input(b.as_ref());
|
||||||
|
@ -122,8 +125,17 @@ impl TapBranchHash {
|
||||||
eng.input(b.as_ref());
|
eng.input(b.as_ref());
|
||||||
eng.input(a.as_ref());
|
eng.input(a.as_ref());
|
||||||
};
|
};
|
||||||
TapBranchHash::from_engine(eng)
|
TapNodeHash::from_engine(eng)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the [`TapNodeHash`] from a script and a leaf version.
|
||||||
|
pub fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash {
|
||||||
|
TapNodeHash::from(TapLeafHash::from_script(script, ver))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TapLeafHash> for TapNodeHash {
|
||||||
|
fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_inner(leaf.into_inner()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maximum depth of a taproot tree script spend path.
|
/// Maximum depth of a taproot tree script spend path.
|
||||||
|
@ -177,7 +189,7 @@ pub struct TaprootSpendInfo {
|
||||||
/// The BIP341 internal key.
|
/// The BIP341 internal key.
|
||||||
internal_key: UntweakedPublicKey,
|
internal_key: UntweakedPublicKey,
|
||||||
/// The merkle root of the script tree (None if there are no scripts).
|
/// The merkle root of the script tree (None if there are no scripts).
|
||||||
merkle_root: Option<TapBranchHash>,
|
merkle_root: Option<TapNodeHash>,
|
||||||
/// The sign final output pubkey as per BIP 341.
|
/// The sign final output pubkey as per BIP 341.
|
||||||
output_key_parity: secp256k1::Parity,
|
output_key_parity: secp256k1::Parity,
|
||||||
/// The tweaked output key.
|
/// The tweaked output key.
|
||||||
|
@ -221,7 +233,7 @@ impl TaprootSpendInfo {
|
||||||
pub fn new_key_spend<C: secp256k1::Verification>(
|
pub fn new_key_spend<C: secp256k1::Verification>(
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
internal_key: UntweakedPublicKey,
|
internal_key: UntweakedPublicKey,
|
||||||
merkle_root: Option<TapBranchHash>,
|
merkle_root: Option<TapNodeHash>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (output_key, parity) = internal_key.tap_tweak(secp, merkle_root);
|
let (output_key, parity) = internal_key.tap_tweak(secp, merkle_root);
|
||||||
Self {
|
Self {
|
||||||
|
@ -243,7 +255,7 @@ impl TaprootSpendInfo {
|
||||||
pub fn internal_key(&self) -> UntweakedPublicKey { self.internal_key }
|
pub fn internal_key(&self) -> UntweakedPublicKey { self.internal_key }
|
||||||
|
|
||||||
/// Returns the merkle root for this [`TaprootSpendInfo`].
|
/// Returns the merkle root for this [`TaprootSpendInfo`].
|
||||||
pub fn merkle_root(&self) -> Option<TapBranchHash> { self.merkle_root }
|
pub fn merkle_root(&self) -> Option<TapNodeHash> { self.merkle_root }
|
||||||
|
|
||||||
/// Returns the output key (the key used in script pubkey) for this [`TaprootSpendInfo`].
|
/// Returns the output key (the key used in script pubkey) for this [`TaprootSpendInfo`].
|
||||||
pub fn output_key(&self) -> TweakedPublicKey { self.output_key }
|
pub fn output_key(&self) -> TweakedPublicKey { self.output_key }
|
||||||
|
@ -261,7 +273,7 @@ impl TaprootSpendInfo {
|
||||||
node: NodeInfo,
|
node: NodeInfo,
|
||||||
) -> TaprootSpendInfo {
|
) -> TaprootSpendInfo {
|
||||||
// Create as if it is a key spend path with the given merkle root
|
// Create as if it is a key spend path with the given merkle root
|
||||||
let root_hash = Some(TapBranchHash::from_inner(node.hash.into_inner()));
|
let root_hash = Some(node.hash);
|
||||||
let mut info = TaprootSpendInfo::new_key_spend(secp, internal_key, root_hash);
|
let mut info = TaprootSpendInfo::new_key_spend(secp, internal_key, root_hash);
|
||||||
for leaves in node.leaves {
|
for leaves in node.leaves {
|
||||||
let key = (leaves.script, leaves.ver);
|
let key = (leaves.script, leaves.ver);
|
||||||
|
@ -434,7 +446,7 @@ impl TaprootBuilder {
|
||||||
pub fn add_hidden_node(
|
pub fn add_hidden_node(
|
||||||
self,
|
self,
|
||||||
depth: u8,
|
depth: u8,
|
||||||
hash: sha256::Hash,
|
hash: TapNodeHash,
|
||||||
) -> Result<Self, TaprootBuilderError> {
|
) -> Result<Self, TaprootBuilderError> {
|
||||||
let node = NodeInfo::new_hidden_node(hash);
|
let node = NodeInfo::new_hidden_node(hash);
|
||||||
self.insert(node, depth)
|
self.insert(node, depth)
|
||||||
|
@ -534,7 +546,7 @@ impl Default for TaprootBuilder {
|
||||||
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
||||||
pub struct NodeInfo {
|
pub struct NodeInfo {
|
||||||
/// Merkle hash for this node.
|
/// Merkle hash for this node.
|
||||||
pub(crate) hash: sha256::Hash,
|
pub(crate) hash: TapNodeHash,
|
||||||
/// Information about leaves inside this node.
|
/// Information about leaves inside this node.
|
||||||
pub(crate) leaves: Vec<ScriptLeaf>,
|
pub(crate) leaves: Vec<ScriptLeaf>,
|
||||||
/// Tracks information on hidden nodes below this node.
|
/// Tracks information on hidden nodes below this node.
|
||||||
|
@ -543,16 +555,15 @@ pub struct NodeInfo {
|
||||||
|
|
||||||
impl NodeInfo {
|
impl NodeInfo {
|
||||||
/// Creates a new [`NodeInfo`] with omitted/hidden info.
|
/// Creates a new [`NodeInfo`] with omitted/hidden info.
|
||||||
pub fn new_hidden_node(hash: sha256::Hash) -> Self {
|
pub fn new_hidden_node(hash: TapNodeHash) -> Self {
|
||||||
Self { hash, leaves: vec![], has_hidden_nodes: true }
|
Self { hash, leaves: vec![], has_hidden_nodes: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new leaf [`NodeInfo`] with given [`ScriptBuf`] and [`LeafVersion`].
|
/// Creates a new leaf [`NodeInfo`] with given [`ScriptBuf`] and [`LeafVersion`].
|
||||||
pub fn new_leaf_with_ver(script: ScriptBuf, ver: LeafVersion) -> Self {
|
pub fn new_leaf_with_ver(script: ScriptBuf, ver: LeafVersion) -> Self {
|
||||||
let leaf = ScriptLeaf::new(script, ver);
|
|
||||||
Self {
|
Self {
|
||||||
hash: sha256::Hash::from_inner(leaf.leaf_hash().into_inner()),
|
hash: TapNodeHash::from_script(&script, ver),
|
||||||
leaves: vec![leaf],
|
leaves: vec![ScriptLeaf::new(script, ver)],
|
||||||
has_hidden_nodes: false,
|
has_hidden_nodes: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,9 +579,9 @@ impl NodeInfo {
|
||||||
b_leaf.merkle_branch.push(a.hash)?; // add hashing partner
|
b_leaf.merkle_branch.push(a.hash)?; // add hashing partner
|
||||||
all_leaves.push(b_leaf);
|
all_leaves.push(b_leaf);
|
||||||
}
|
}
|
||||||
let hash = TapBranchHash::from_node_hashes(a.hash, b.hash);
|
let hash = TapNodeHash::from_node_hashes(a.hash, b.hash);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
hash: sha256::Hash::from_inner(hash.into_inner()),
|
hash,
|
||||||
leaves: all_leaves,
|
leaves: all_leaves,
|
||||||
has_hidden_nodes: a.has_hidden_nodes || b.has_hidden_nodes,
|
has_hidden_nodes: a.has_hidden_nodes || b.has_hidden_nodes,
|
||||||
})
|
})
|
||||||
|
@ -622,16 +633,14 @@ impl ScriptLeaf {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The merkle proof for inclusion of a tree in a taptree hash.
|
/// The merkle proof for inclusion of a tree in a taptree hash.
|
||||||
// The type of hash is `sha256::Hash` because the vector might contain 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))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
||||||
pub struct TaprootMerkleBranch(Vec<sha256::Hash>);
|
pub struct TaprootMerkleBranch(Vec<TapNodeHash>);
|
||||||
|
|
||||||
impl TaprootMerkleBranch {
|
impl TaprootMerkleBranch {
|
||||||
/// Returns a reference to the inner vector of hashes.
|
/// Returns a reference to the inner vector of hashes.
|
||||||
pub fn as_inner(&self) -> &[sha256::Hash] { &self.0 }
|
pub fn as_inner(&self) -> &[TapNodeHash] { &self.0 }
|
||||||
|
|
||||||
/// Creates a merkle proof from raw data representing a list of hashes.
|
/// Creates a merkle proof from raw data representing a list of hashes.
|
||||||
pub fn from_slice(sl: &[u8]) -> Result<Self, TaprootError> {
|
pub fn from_slice(sl: &[u8]) -> Result<Self, TaprootError> {
|
||||||
|
@ -643,7 +652,7 @@ impl TaprootMerkleBranch {
|
||||||
let inner = sl
|
let inner = sl
|
||||||
.chunks_exact(TAPROOT_CONTROL_NODE_SIZE)
|
.chunks_exact(TAPROOT_CONTROL_NODE_SIZE)
|
||||||
.map(|chunk| {
|
.map(|chunk| {
|
||||||
sha256::Hash::from_slice(chunk)
|
TapNodeHash::from_slice(chunk)
|
||||||
.expect("chunks_exact always returns the correct size")
|
.expect("chunks_exact always returns the correct size")
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -656,7 +665,7 @@ impl TaprootMerkleBranch {
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128).
|
/// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128).
|
||||||
fn from_collection<T: AsRef<[sha256::Hash]> + Into<Vec<sha256::Hash>>>(
|
fn from_collection<T: AsRef<[TapNodeHash]> + Into<Vec<TapNodeHash>>>(
|
||||||
collection: T,
|
collection: T,
|
||||||
) -> Result<Self, TaprootError> {
|
) -> Result<Self, TaprootError> {
|
||||||
if collection.as_ref().len() > TAPROOT_CONTROL_MAX_NODE_COUNT {
|
if collection.as_ref().len() > TAPROOT_CONTROL_MAX_NODE_COUNT {
|
||||||
|
@ -675,7 +684,7 @@ impl TaprootMerkleBranch {
|
||||||
for hash in self.0.iter() {
|
for hash in self.0.iter() {
|
||||||
writer.write_all(hash.as_ref())?;
|
writer.write_all(hash.as_ref())?;
|
||||||
}
|
}
|
||||||
Ok(self.0.len() * sha256::Hash::LEN)
|
Ok(self.0.len() * TapNodeHash::LEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes `self` as bytes.
|
/// Serializes `self` as bytes.
|
||||||
|
@ -684,7 +693,7 @@ impl TaprootMerkleBranch {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends elements to proof.
|
/// Appends elements to proof.
|
||||||
fn push(&mut self, h: sha256::Hash) -> Result<(), TaprootBuilderError> {
|
fn push(&mut self, h: TapNodeHash) -> Result<(), TaprootBuilderError> {
|
||||||
if self.0.len() >= TAPROOT_CONTROL_MAX_NODE_COUNT {
|
if self.0.len() >= TAPROOT_CONTROL_MAX_NODE_COUNT {
|
||||||
Err(TaprootBuilderError::InvalidMerkleTreeDepth(self.0.len()))
|
Err(TaprootBuilderError::InvalidMerkleTreeDepth(self.0.len()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -694,7 +703,7 @@ impl TaprootMerkleBranch {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inner list of hashes.
|
/// Returns the inner list of hashes.
|
||||||
pub fn into_inner(self) -> Vec<sha256::Hash> { self.0 }
|
pub fn into_inner(self) -> Vec<TapNodeHash> { self.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_try_from {
|
macro_rules! impl_try_from {
|
||||||
|
@ -712,9 +721,9 @@ macro_rules! impl_try_from {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
impl_try_from!(&[sha256::Hash]);
|
impl_try_from!(&[TapNodeHash]);
|
||||||
impl_try_from!(Vec<sha256::Hash>);
|
impl_try_from!(Vec<TapNodeHash>);
|
||||||
impl_try_from!(Box<[sha256::Hash]>);
|
impl_try_from!(Box<[TapNodeHash]>);
|
||||||
|
|
||||||
/// 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)]
|
||||||
|
@ -801,15 +810,11 @@ impl ControlBlock {
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// compute the script hash
|
// compute the script hash
|
||||||
// Initially the curr_hash is the leaf hash
|
// Initially the curr_hash is the leaf hash
|
||||||
let leaf_hash = TapLeafHash::from_script(script, self.leaf_version);
|
let mut curr_hash = TapNodeHash::from_script(script, self.leaf_version);
|
||||||
let mut curr_hash = TapBranchHash::from_inner(leaf_hash.into_inner());
|
|
||||||
// Verify the proof
|
// Verify the proof
|
||||||
for elem in self.merkle_branch.as_inner() {
|
for elem in self.merkle_branch.as_inner() {
|
||||||
// Recalculate the curr hash as parent hash
|
// Recalculate the curr hash as parent hash
|
||||||
curr_hash = TapBranchHash::from_node_hashes(
|
curr_hash = TapNodeHash::from_node_hashes(curr_hash, *elem);
|
||||||
sha256::Hash::from_inner(curr_hash.into_inner()),
|
|
||||||
*elem,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// compute the taptweak
|
// compute the taptweak
|
||||||
let tweak =
|
let tweak =
|
||||||
|
@ -1057,15 +1062,17 @@ impl fmt::Display for TaprootError {
|
||||||
"Merkle Tree depth({}) must be less than {}",
|
"Merkle Tree depth({}) must be less than {}",
|
||||||
d, TAPROOT_CONTROL_MAX_NODE_COUNT
|
d, TAPROOT_CONTROL_MAX_NODE_COUNT
|
||||||
),
|
),
|
||||||
TaprootError::InvalidTaprootLeafVersion(v) =>
|
TaprootError::InvalidTaprootLeafVersion(v) => {
|
||||||
write!(f, "Leaf version({}) must have the least significant bit 0", v),
|
write!(f, "Leaf version({}) must have the least significant bit 0", v)
|
||||||
|
}
|
||||||
TaprootError::InvalidControlBlockSize(sz) => write!(
|
TaprootError::InvalidControlBlockSize(sz) => write!(
|
||||||
f,
|
f,
|
||||||
"Control Block size({}) must be of the form 33 + 32*m where 0 <= m <= {} ",
|
"Control Block size({}) must be of the form 33 + 32*m where 0 <= m <= {} ",
|
||||||
sz, TAPROOT_CONTROL_MAX_NODE_COUNT
|
sz, TAPROOT_CONTROL_MAX_NODE_COUNT
|
||||||
),
|
),
|
||||||
TaprootError::InvalidInternalKey(ref e) =>
|
TaprootError::InvalidInternalKey(ref e) => {
|
||||||
write_err!(f, "invalid internal x-only key"; e),
|
write_err!(f, "invalid internal x-only key"; e)
|
||||||
|
}
|
||||||
TaprootError::InvalidParity(_) => write!(f, "invalid parity value for internal key"),
|
TaprootError::InvalidParity(_) => write!(f, "invalid parity value for internal key"),
|
||||||
TaprootError::EmptyTree => write!(f, "Taproot Tree must contain at least one script"),
|
TaprootError::EmptyTree => write!(f, "Taproot Tree must contain at least one script"),
|
||||||
}
|
}
|
||||||
|
@ -1134,10 +1141,10 @@ mod test {
|
||||||
fn empty_hash(tag_name: &str) -> [u8; 32] {
|
fn empty_hash(tag_name: &str) -> [u8; 32] {
|
||||||
let mut e = tag_engine(tag_name);
|
let mut e = tag_engine(tag_name);
|
||||||
e.input(&[]);
|
e.input(&[]);
|
||||||
sha256::Hash::from_engine(e).into_inner()
|
TapNodeHash::from_engine(e).into_inner()
|
||||||
}
|
}
|
||||||
assert_eq!(empty_hash("TapLeaf"), TapLeafHash::hash(&[]).into_inner());
|
assert_eq!(empty_hash("TapLeaf"), TapLeafHash::hash(&[]).into_inner());
|
||||||
assert_eq!(empty_hash("TapBranch"), TapBranchHash::hash(&[]).into_inner());
|
assert_eq!(empty_hash("TapBranch"), TapNodeHash::hash(&[]).into_inner());
|
||||||
assert_eq!(empty_hash("TapTweak"), TapTweakHash::hash(&[]).into_inner());
|
assert_eq!(empty_hash("TapTweak"), TapTweakHash::hash(&[]).into_inner());
|
||||||
assert_eq!(empty_hash("TapSighash"), TapSighashHash::hash(&[]).into_inner());
|
assert_eq!(empty_hash("TapSighash"), TapSighashHash::hash(&[]).into_inner());
|
||||||
}
|
}
|
||||||
|
@ -1154,7 +1161,7 @@ mod test {
|
||||||
"5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb"
|
"5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TapBranchHash::from_engine(TapBranchTag::engine()).to_string(),
|
TapNodeHash::from_engine(TapBranchTag::engine()).to_string(),
|
||||||
"53c373ec4d6f3c53c1f5fb2ff506dcefe1a0ed74874f93fa93c8214cbe9ffddf"
|
"53c373ec4d6f3c53c1f5fb2ff506dcefe1a0ed74874f93fa93c8214cbe9ffddf"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1176,7 +1183,7 @@ mod test {
|
||||||
"ed1382037800c9dd938dd8854f1a8863bcdeb6705069b4b56a66ec22519d5829"
|
"ed1382037800c9dd938dd8854f1a8863bcdeb6705069b4b56a66ec22519d5829"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TapBranchHash::hash(&[0]).to_string(),
|
TapNodeHash::hash(&[0]).to_string(),
|
||||||
"92534b1960c7e6245af7d5fda2588db04aa6d646abc2b588dab2b69e5645eb1d"
|
"92534b1960c7e6245af7d5fda2588db04aa6d646abc2b588dab2b69e5645eb1d"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1412,7 +1419,7 @@ mod test {
|
||||||
assert!(arr["intermediary"]["merkleRoot"].is_null());
|
assert!(arr["intermediary"]["merkleRoot"].is_null());
|
||||||
} else {
|
} else {
|
||||||
merkle_root = Some(
|
merkle_root = Some(
|
||||||
TapBranchHash::from_str(arr["intermediary"]["merkleRoot"].as_str().unwrap())
|
TapNodeHash::from_str(arr["intermediary"]["merkleRoot"].as_str().unwrap())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
let leaf_hashes = arr["intermediary"]["leafHashes"].as_array().unwrap();
|
let leaf_hashes = arr["intermediary"]["leafHashes"].as_array().unwrap();
|
||||||
|
|
Loading…
Reference in New Issue