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

Add taproot checks to Address::from_script #1029

Closed
wants to merge 4 commits into from

Conversation

tcharding
Copy link
Member

@tcharding tcharding commented Jun 1, 2022

Draft because includes #1021

#1021 adds segwit v0 checks to Address::from_script. This PR adds taproot checks and documentation on why we do the checks.

This was done while I was attempting to write a decent issue. Is related to #1021 (obviously) and also to (#995).

cc @nlanson

nlanson and others added 4 commits May 31, 2022 18:13
Recently we added segwit v0 script checks to the `Address::from_script`
method, following the principle that we want to provide some safety for
users in the 'main' rust-bitcoin API.

At the time we did not add taproot checks because doing so broke one of
the test vector unit tests. Turns out the unit test was doing
roundtripping of an address -> scipt_pubkey() -> address which is not
strictly required by BIP-350 (where the test vector comes from).

Modify the unit test by adding a boolean flag indicating whether the
address should roundtrip and only roundtrip test such addresses.

Add taproot script validity check to the `Address::from_script` method.
We recently decided to provide additional safety for users by not
creating addresses from certain invalid scripts.

Add rustdocs describing the return value and the safety guarantees we
are explicitly providing so as not to surprise users.

(See GitHub issue rust-bitcoin#955 for more context.)
Creating an address from an invalid taproot script should fail. Add a
unit test to verify it does.
Copy link
Contributor

@nlanson nlanson left a comment

Choose a reason for hiding this comment

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

LGTM.
V1 checks and tests are the similar to what I was experimenting with yesterday and I like the documentation that really makes it clear on when Address::from_script() should be used.

@nlanson
Copy link
Contributor

nlanson commented Jun 1, 2022

Maybe in another PR, but I think Address::from_str() should contain checks for Taproot program lengths and return an error on invalid v1 scripts, similar to how it does it with v0 scripts.

// Specific segwit v0 check.
if version == WitnessVersion::V0 && (program.len() != 20 && program.len() != 32) {
return Err(Error::InvalidSegwitV0ProgramLength(program.len()));
}

@tcharding
Copy link
Member Author

Addresses can come from other places (outside of this library) so I think we still want to support parsing unspendable addresses. @apoelstra can you confirm please?

Copy link
Member

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

Sorry for the absence. We don't need anything special for the taproot addresses. In fact, removing the non 32-byte witness v1 address would be incorrect.

From BIP341

Any other outputs, including version 1 outputs with lengths other than 32 bytes, or P2SH-wrapped version 1 outputs[3], remain unencumbered.

@@ -676,6 +676,10 @@ impl Address {
if script.witness_version() == Some(WitnessVersion::V0) && !(script.is_v0_p2wpkh() || script.is_v0_p2wsh()) {
return None
}

if script.witness_version() == Some(WitnessVersion::V1) && !script.is_v1_p2tr() {
Copy link
Member

Choose a reason for hiding this comment

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

This was discussed extensively previously. I will try to dig up references. Doing this is wrong because non-32 bytes WitnessVersion::V1 address types are still available for future usage.

@sanket1729
Copy link
Member

sanket1729 commented Jun 1, 2022

Maybe in another PR, but I think Address::from_str() should contain checks for Taproot program lengths and return an error on invalid v1 scripts, similar to how it does it with v0 scripts.

@nlanson, this is incorrect. See the above comment. There is a difference between segwitv0 addresses and taproot addresses. Non 20/32 byte programs segwitv0 programs are invalid. But non-32 byte taproot programs are still valid programs and can used in future upgrades.

@tcharding, if we really want to do safe guard the user. We can check whether the 32 byte program is actually a point on the curve. But I am not entirely sure about this because there may be use cases for representing non-curve points as addresses and it is probably not worth the effort.

See a related previous attempt #668 and a discussion issue #648

@nlanson
Copy link
Contributor

nlanson commented Jun 1, 2022

Thanks for the info @sanket1729. Just reread the relevant part of BIP341 and now understand why this is not necessary for Taproot scripts. It was a detail that completely slipped through my mind.

@Kixunil
Copy link
Collaborator

Kixunil commented Jun 1, 2022

Agree, the difference is one is anyone can spend, the other is nobody can spend. Adding the check would also conflict with the documentation which describes unspendable addresses but doesn't mention anyone can spend.

I wouldn't mind having a method from_script_strict() or simply is_known() method on existing address if people want extra check it but the documentation should discourage it in user-facing inputs because it'd break upgrades. It is probably only useful in tests or internally-generated scripts/addresses.

@tcharding
Copy link
Member Author

Closing this one, thanks for the reviews and info. from_script could probably do with some docs improvements still though ...

@tcharding tcharding closed this Jun 1, 2022
@tcharding tcharding deleted the 06-01-from-script branch August 5, 2022 02:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants