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:
parent
5ff2635585
commit
f39cd88f5f
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in New Issue