Skip to content
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

Merged
merged 2 commits into from Jan 11, 2023

Conversation

sanket1729
Copy link
Member

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.

@Kixunil
Copy link
Collaborator

Kixunil commented Dec 16, 2022

Oh, yeah, I wanted to open #1481 before but didn't have time and forgot. It should completely resolve the issue you found.

Copy link
Collaborator

@Kixunil Kixunil left a 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 {
}
Copy link
Collaborator

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

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.

@apoelstra
Copy link
Member

This is really cool! It's a lot cleaner, both conceptually and code-wise, than I'd feared from the discussion in #1393.


/// 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())
Copy link
Member

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.

Copy link
Member

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().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adressed

Copy link
Collaborator

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?

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
Copy link
Member

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"

@sanket1729
Copy link
Member Author

Rebased and ready for review

Copy link
Collaborator

@Kixunil Kixunil left a 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.

);
#[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
Copy link
Collaborator

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?


/// 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())
Copy link
Collaborator

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?

@@ -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 {
Copy link
Collaborator

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.)

Copy link
Member Author

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

@sanket1729 sanket1729 force-pushed the tap_updates branch 2 times, most recently from 4bfad2f to c6e4454 Compare January 9, 2023 20:48
Copy link
Member Author

@sanket1729 sanket1729 left a 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) => {
Copy link
Member Author

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
Copy link
Collaborator

@Kixunil Kixunil left a 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
Copy link
Collaborator

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.

Copy link
Member

@tcharding tcharding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK f39cd88

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TapTweak API for a single script path spending case
4 participants