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

taproot: add TapNodeHash getter method on TapTree and NodeInfo #2467

Merged
merged 1 commit into from Feb 13, 2024

Conversation

conduition
Copy link
Contributor

@conduition conduition commented Feb 11, 2024

Submitting this to fix what I think is an API hole. Please correct me if I'm mistaken here and there is an easier way to do what I'm after.

Problem

From what I can tell of the existing 0.31.1 API, there doesn't seem to be any way for a consumer to build a taproot tree using TaprootBuilder and then simply output the resulting tap tree merkle root TapNodeHash.

Instead, the API forces me to do TaprootBuilder::finalize(secp_ctx, internal_key) first to get a TaprootSpendInfo, and then call TaprootSpendInfo::merkle_root() to get the root TapNodehash. This requires ECC point addition/multiplication for the tweak operation (inside TaprootBuilder::finalize), so it is a lot less performant than the simple hashing operations needed to build a taproot tree.

Obviously if I want to spend the taproot tree, I'll need to tweak an internal key. But if all I want is to examine the merkle root hashes of taproot trees (e.g. for quick validation), there should be a faster and more direct option for me.

Suggested Solution

My suggestion, demonstrated in this PR, would be to add a couple of simple getter methods:

  • TapTree::node_hash() -> TapNodeHash
  • NodeInfo::node_hash() -> TapNodeHash

These rhyme with the existing LeafNode::node_hash() method. These provide a roundabout way for downstream consumers to extract a taptree merkle root TapNodeHash while still using the safe API provided by TaprootBuilder. I would simply use TaprootBuilder to build a TapTree or NodeInfo, and then invoke the node_hash method on that object. No point addition required.

Footguns

This does open up more opportunities for consumers to footgun themselves by, for example, committing a P2TR script pubkey to a leaf node by accident, instead of the root node. I'd argue this possibility already exists in the form of LeafNode::node_hash(). We're not making that problem much worse here.

If the caller is using TaprootBuilder to construct their tree, the only way they'll be able to get a NodeInfo or TapTree in the first place would be to finalize the builder into it, which seems like an acceptable and intuitive-enough usage path to me.

@github-actions github-actions bot added the C-bitcoin PRs modifying the bitcoin crate label Feb 11, 2024
@coveralls
Copy link

coveralls commented Feb 11, 2024

Pull Request Test Coverage Report for Build 7879485491

Details

  • -2 of 2 (0.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.007%) to 84.038%

Changes Missing Coverage Covered Lines Changed/Added Lines %
bitcoin/src/taproot/mod.rs 0 2 0.0%
Totals Coverage Status
Change from base Build 7879164707: -0.007%
Covered Lines: 19433
Relevant Lines: 23124

💛 - Coveralls

@apoelstra
Copy link
Member

I think the method on TapTree should be called root_hash, since the hash has to be the hash of the root of the tree. (You can't compose or modify TapTrees once they're created.)

But I think you're correct that this is an API gap. I agree there's a mild footgun in the NodeInfo::node_hash method but realistically people can stick all sorts of wrong hashes into wrong places, and since this doesn't affect the normal API I think it's fine.

@Kixunil
Copy link
Collaborator

Kixunil commented Feb 12, 2024

Concept ACK.

Maybe root_node would be better? Anyway, I agree with having root in the name.

Fixes a gap in the API of the taproot module. Callers can now use
TapTree::root_hash or NodeInfo::node_hash to extract the taproot
tree merkle root hash for fast validation without any ECC overhead.
@conduition
Copy link
Contributor Author

I renamed node_hash to root_hash on TapTree. I left the method on NodeInfo alone.

Then squashed, rebased, and added a more detailed commit message.

Copy link
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

ACK 1384330

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 1384330

@apoelstra apoelstra merged commit 668df1d into rust-bitcoin:master Feb 13, 2024
165 checks passed
@conduition conduition deleted the tap-node-hash branch February 13, 2024 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bitcoin PRs modifying the bitcoin crate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants