Use TapNodeHash in NodeInfo

This cleans up some ugly code where we had to use sha256::Hash for
combining TapLeafHash and TapBranchHash
This commit is contained in:
sanket1729 2022-12-15 08:17:39 -08:00
parent 5ff2635585
commit f39cd88f5f
2 changed files with 34 additions and 34 deletions

View File

@ -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());
} }

View File

@ -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};
@ -116,7 +116,7 @@ impl From<&ScriptLeaf> for TapLeafHash {
impl TapNodeHash { 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) -> TapNodeHash { pub fn from_node_hashes(a: TapNodeHash, b: TapNodeHash) -> TapNodeHash {
let mut eng = TapNodeHash::engine(); let mut eng = TapNodeHash::engine();
if a < b { if a < b {
eng.input(a.as_ref()); eng.input(a.as_ref());
@ -127,6 +127,11 @@ impl TapNodeHash {
}; };
TapNodeHash::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 { impl From<TapLeafHash> for TapNodeHash {
@ -268,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(TapNodeHash::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);
@ -441,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)
@ -541,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.
@ -550,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,
} }
} }
@ -577,7 +581,7 @@ impl NodeInfo {
} }
let hash = TapNodeHash::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,
}) })
@ -629,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 `TapNodeHash` 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> {
@ -650,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();
@ -663,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 {
@ -682,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.
@ -691,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 {
@ -701,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 {
@ -719,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)]
@ -808,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 = TapNodeHash::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 = TapNodeHash::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 =
@ -1064,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"),
} }
@ -1141,7 +1141,7 @@ 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"), TapNodeHash::hash(&[]).into_inner()); assert_eq!(empty_hash("TapBranch"), TapNodeHash::hash(&[]).into_inner());