New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unify TapLeafHash
and TapBranchHash
into TapNodeHash
while tree construction
#1479
Conversation
Oh, yeah, I wanted to open #1481 before but didn't have time and forgot. It should completely resolve the issue you found. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have to run so not a deep review but looks mostly fine.
@@ -622,16 +630,14 @@ impl ScriptLeaf { | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't ScriptLeaf::leaf_hash
return TapNodeHash
? Do we even need TapLeafHash
for anything now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need TapLeafHash
in taproot sign APIs. https://docs.rs/bitcoin/latest/bitcoin/util/sighash/struct.SighashCache.html#method.taproot_signature_hash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right, in that case we should also have a trivial impl From<TapLeafhash> for TapNodehash
.
This is really cool! It's a lot cleaner, both conceptually and code-wise, than I'd feared from the discussion in #1393. |
bitcoin/src/taproot.rs
Outdated
|
||
/// Computes the [`TapNodeHash`] from a script and a leaf version. | ||
pub fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash { | ||
TapNodeHash::from_inner(TapLeafHash::from_script(script, ver).into_inner()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In e03b945:
Can you add a comment here highlighting that you're actually casting between two hash types here, since it's maybe hard to see in the from_inner(X.into_inner())
form, explaining that this is because leaves of a taptree use a different hash prefix than the internal nodes, but the Merkle tree logic does not care about the distinction. Maybe also link to the BIP and/or to #1393.
I think a regular comment is fine, no need to doccomment this, since it's an internal implementation detail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I agree with Kix's suggestion below that we add a conversion method from TapLeafHash
to TabBranchHash
, so this line can be simplified to TapLeafHash::from_script(script, ver).into()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there's From
now we might as well use it here?
bitcoin/src/taproot.rs
Outdated
doc="Taproot-tagged hash for tapscript Merkle tree branches", false | ||
sha256t_hash_newtype!(TapNodeHash, TapBranchTag, MIDSTATE_TAPBRANCH, 64, | ||
doc="Taproot-tagged hash with tag \"TapBranch\". This hash type is used while constructing | ||
a taproot tree.", false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 6609dae:
This doccomment should be updated to say that it might be tagged either with TapBranch
or with TapLeaf
; or maybe it should not mention this at all and just say "tagged hash used in taproot trees; see BIP-340 for tagging rules"
108959b
to
27c049d
Compare
Rebased and ready for review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly nits, just one somewhat important thing.
bitcoin/src/taproot.rs
Outdated
); | ||
#[rustfmt::skip] | ||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you try splitting "This hash type..." in these two into a separate paragraph to improve the doc?
bitcoin/src/taproot.rs
Outdated
|
||
/// Computes the [`TapNodeHash`] from a script and a leaf version. | ||
pub fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash { | ||
TapNodeHash::from_inner(TapLeafHash::from_script(script, ver).into_inner()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there's From
now we might as well use it here?
bitcoin/src/taproot.rs
Outdated
@@ -544,15 +556,14 @@ pub struct NodeInfo { | |||
impl NodeInfo { | |||
/// Creates a new [`NodeInfo`] with omitted/hidden info. | |||
pub fn new_hidden_node(hash: sha256::Hash) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should accept TapNodeHash
. Or am I missing something? (Only this one is blocking.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duh, I swear all instances of sha256::Hash in this PR, but looks like I screwed up in rebasing somewhere
4bfad2f
to
c6e4454
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ready for review again
@@ -1064,15 +1062,17 @@ impl fmt::Display for TaprootError { | |||
"Merkle Tree depth({}) must be less than {}", | |||
d, TAPROOT_CONTROL_MAX_NODE_COUNT | |||
), | |||
TaprootError::InvalidTaprootLeafVersion(v) => | |||
write!(f, "Leaf version({}) must have the least significant bit 0", v), | |||
TaprootError::InvalidTaprootLeafVersion(v) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple formatting changes got sneaked in here. Don't think it should be an issue
This cleans up some ugly code where we had to use sha256::Hash for combining TapLeafHash and TapBranchHash
c6e4454
to
f39cd88
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK f39cd88
); | ||
#[rustfmt::skip] | ||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there should be an empty line, but since I'm too tired to check myself, I will ignore this nit. We can fix later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK f39cd88
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 ofsha256::Hash
that I had used to represent bothTapLeafHash
andTapBranchHash
Does not fix
TapTweakHash
. This requires some changes to macros we use.TapNodeHash
by not making ithash_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 nothash_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 ofTapNodeHash
.