8000 fix: Throw Error on unsuported addresses in `is_signed_by_address()` by Shatnerz · Pull Request #819 · rust-bitcoin/rust-bitcoin · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

fix: Throw Error on unsuported addresses in is_signed_by_address() #819

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

Merged

Conversation

Shatnerz
Copy link
Contributor
@Shatnerz Shatnerz commented Feb 5, 2022

This is a direct response to this comment: #684 (comment)

Currently unsupported addresses simply return false which is highly misleading as it is entirely possible that the keys related to a given address were used to sign the message.

If this is successful I can follow up with

a method to check if a PublicKey is associated with an address

@Shatnerz Shatnerz force-pushed the fix/error-on-unsupported-addresses branch 4 times, most recently from c271b83 to 782182e Compare February 5, 2022 22:27
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.

Nice PR, thanks!

src/util/misc.rs Outdated
@@ -63,6 +67,8 @@ mod message_signing {
MessageSignatureError::InvalidLength => write!(f, "length not 65 bytes"),
MessageSignatureError::InvalidEncoding(ref e) => write!(f, "invalid encoding: {}", e),
MessageSignatureError::InvalidBase64 => write!(f, "invalid base64"),
MessageSignatureError::UnableToRecoverPubKey(ref e) => write!(f, "error recovering public key: {}", e),
MessageSignatureError::UnsupportedAddressType(ref e) => write!(f, "unsupported address type: {}", e),
Copy link
Member

Choose a reason for hiding this comment

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

The inner type is not an error but an AddressType, perhaps ty or addr would be better than e?

This comment was marked as resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes good catch. I hope an explicit address_type is acceptable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Kixunil I was distracted and posted my reply to a different comment here. You can ignore. I immediately deleted the comment, but you are too fast.

src/util/misc.rs Outdated
Comment on lines 154 to 155
let msg = secp256k1::Message::from_slice(&msg_hash[..])
.map_err(MessageSignatureError::UnableToRecoverPubKey)?;
Copy link
Member

Choose a reason for hiding this comment

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

No need for the explicit map_err here, the ? does the conversion for us because there is only one variant of MessageSignatureError with an inner secp error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wouldn't an explicit map be better here? It helps differentiate between InvalidEncoding(secp256k1::Error) and UnableToRecoverPubKey(secp256k1::Error)

Copy link
Collaborator

Choose a reason for hiding this comment

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

There are two actually.

Copy link
Member

Choose a reason for hiding this comment

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

Message::from_slice cannot fail. This should actually be an .expect but ? was shorter to type and it doesn't matter anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can add the expect and then remove UnableToRecoverPublicKey is so desired.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What the hell, it only takes a second. Changed in 1be1bb72d1a

Copy link
Member

Choose a reason for hiding this comment

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

Excluding the fact that I was too blind to see the second variant I cannot work out why this works. If I purposefully break the call to from_slice the compiler returns InvalidEncoding even though the error conversion is ambiguous. I did not think this sort of ambiguity would get past rustc?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tcharding There exists a conversion from secp256k1::Error for MessageSignatureError::InvalidEncoding so this can happen implicitly since there is only one path as there was no conversion of the same error into MessageSignatureError::UnableToRecoverPubKey

    impl From<secp256k1::Error> for MessageSignatureError {
        fn from(e: secp256k1::Error) -> MessageSignatureError {
            MessageSignatureError::InvalidEncoding(e)
        }
    }

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for pointing this out and not telling me to read the code more carefully, twice in one review thread :)

src/util/misc.rs Outdated
@@ -314,6 +318,10 @@ mod tests {
use core::str::FromStr;
use secp256k1;

use util::address::AddressType;

use super::MessageSignatureError;
Copy link
Member

Choose a reason for hiding this comment

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

We could use use super::* at the top of the tests module and then wouldn't need this import statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@Shatnerz Shatnerz force-pushed the fix/error-on-unsupported-addresses branch 2 times, most recently from 13deba9 to 2f34b8e Compare February 7, 2022 12:06
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.

Looks good so far. I have trouble focusing rn so I will need to check again later to be confident I didn't miss anything.

Some(AddressType::P2tr) => false,
None => false,
})
Some(address_type) => Err(MessageSignatureError::UnsupportedAddressType(address_type)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Some(ty @ AddressType::P2sh) | Some(ty @ AddressType::P2wpkh) | Some(ty @ AddressType::P2wsh) | Some(ty @ AddressType::P2tr) would be more refactor-proof but I guess it's unlikely a new address will be introduced together with a signature scheme?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we base the current behaviour off of this comment: #684 (comment)

There is no signmessage standard for non-pkh address types.

Then all other address types would be unsupported and we wouldn't need to explicitly list each. I can go either way. No strong opinions from my end.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it is very unlikely that any new signature schemes are going to show up which support onlly specific address types.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@Shatnerz I meant a hypothetical scenario when a new address is added and a signature scheme too. Since this is unlikely, let's keep it as is.

@Shatnerz Shatnerz force-pushed the fix/error-on-unsupported-addresses branch from 2f34b8e to 2bc9115 Compare February 7, 2022 12:35
Kixunil
Kixunil previously approved these changes Feb 8, 2022
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 1be1bb72d1abba4d2addaee8c208ab1f8c650fd4

I think it'd be best to address my comments in new PRs. Especially for conversions we could inspect the whole crate for these and improve them together.

@tcharding am I guessing correctly that this would be well-suited for you?

let msg = secp256k1::Message::from_slice(&msg_hash[..])?;
) -> Result<PublicKey, MessageSignatureError> {
let msg = secp256k1::Message::from_slice(&msg_hash[..])
.expect("cannot fail");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually just let msg = secp256k1::Message::from(msg_hash); should be possible if we activate bitcoin_hashes feature of secp256k1 .

Copy link
Member

Choose a reason for hiding this comment

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

Oh nice, I forgot that we finally added that feature. Yes, let's do this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Opened #824 for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch. I was looking for the fewest changes possible but this is definitely an improvement.

@apoelstra @Kixunil I pushed the changes in 8a05ca042d4e8

@@ -335,9 +338,14 @@ mod tests {
let p2pkh = ::Address::p2pkh(&pubkey, ::Network::Bitcoin);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not relevant to this PR but I noticed we don't have Ok(false) test for broken signatures.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Kixunil I created #825 to test broken signatures

@tcharding
Copy link
Member

@tcharding am I guessing correctly that this would be well-suited for you?

I don't have anything specific in mind at the moment but I'm starting to get the feeling that our error handling needs a bit of love. After MSRV bump though I'd say because of Rust 1.34 changes to the error trait.

@Kixunil
Copy link
Collaborator
Kixunil commented Feb 8, 2022

@tcharding yes it does need love but these cases don't require MSRV bump (unless ThirtyTwoByteHash got introduced in MSRV-breaking secp256k1, which I didn't check and guess is not the case).

@tcharding
Copy link
Member

Oh cool, thanks, so we can start thinking about this right away.

Kixunil
Kixunil previously approved these changes Feb 9, 2022
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 8a05ca042d4e8e28a60efecaf7b542ef3232ec52

@apoelstra
Copy link
Member

Can you rearrange the code so that the expensive pubkey recovery step is not done unless the result will actually be used?

Can you also squash all these commits? It is hard to read PRs that introduce code in one commit and then remove them in the next.

@Shatnerz
Copy link
Contributor Author
Shatnerz commented Feb 9, 2022

Can you rearrange the code so that the expensive pubkey recovery step is not done unless the result will actually be used?

Yeah, no problem

Can you also squash all these commits? It is hard to read PRs that introduce code in one commit and then remove them in the next.

Yeah no problem. I'm use to gitlab squashing commits. If I'm not sure a change will be accepted I leave the commit so its easy to revert. Squashing at the end only takes a moment

@Shatnerz Shatnerz force-pushed the fix/error-on-unsupported-addresses branch from 8a05ca0 to 31ec64d Compare February 9, 2022 21:16
@apoelstra
Copy link
Member

@Shatnerz makes sense re "not sure if it'll be reverted or not". In this case I think the changes are good, and the extra commits make reviewing harder for new reviewers.

apoelstra
apoelstra previously approved these changes Feb 9, 2022
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 31ec64d

@apoelstra
Copy link
Member

Looks like core2 has broken somehow in the last 15 minutes :(.

@Shatnerz
Copy link
Contributor Author
Shatnerz commented Feb 9, 2022

Looks like core2 has broken somehow in the last 15 minutes :(.

@apoelstra This is a bit outside my domain so it will likely take me awhile and I can't seem to reproduce locally. Advice on how to reproduce locally would be great.

Is this breakage related to enabled the bitcoin_hashes feature? Should I just revert that change?

@apoelstra
Copy link
Member

@Shatnerz yeah, let's try dropping that (lol, sorry, and after I said "just squash stuff, we won't revert"..) But I suspect that things have broken unrelatedly to your PR.

@Shatnerz Shatnerz force-pushed the fix/error-on-unsupported-addresses branch from 31ec64d to 79cee4c Compare February 9, 2022 22:06
@Shatnerz
Copy link
Contributor Author
Shatnerz commented Feb 9, 2022

yeah, let's try dropping that (lol, sorry, and after I said "just squash stuff, we won't revert"..) But I suspect that things have broken unrelatedly to your PR.

@apoelstra yes, just tested it out in my fork. 79cee4c should solve the CI issues

@apoelstra
Copy link
Member

It does seem to be working. Quite concerning that the bitcoin_hashes feature seems to blow up CI like that.

@Shatnerz
Copy link
Contributor Author
Shatnerz commented Feb 9, 2022

It does seem to be working. Quite concerning that the bitcoin_hashes feature seems to blow up CI like that.

A bigger change for another day. At least the CI pipeline is catching these. It'll be nice to clean up implicit side effects like this eventually so its easier to make changes.

Shall we create an issue for this? I'm not sure how to label it, "Enable secp256k1 feature bitcoin_hashes without breaking CI"? You can link to https://github.com/rust-bitcoin/rust-bitcoin/actions/runs/1820479684 as an example of what failures it introduces.

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 79cee4c

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 79cee4c

@Kixunil
Copy link
Collaborator
Kixunil commented Feb 21, 2022

The failure seems to be related to #758 and I'm not sure reexporting everything but a kitchen sink is a good approach. Sadly, probably the best solution requires yet-to-be-released cargo version.

dr-orlovsky added a commit that referenced this pull request Mar 12, 2022
…igned_by_address`

e391ce9 test: Add a test for incorrect message signature (Andrew Ahlers)

Pull request description:

  In response to this comment: #819 (comment)

  This should be straightforward. Let me know if there are any style issues. I tried to keep things similar to the existing test while cutting out any extra cruft to keep things small.

ACKs for top commit:
  apoelstra:
    ACK e391ce9
  Kixunil:
    ACK e391ce9
  dr-orlovsky:
    ACK e391ce9

Tree-SHA512: 47296a7e0b2f45d5e50f507727ae4360686730a386f37dedfd1360b8cdf4b9dd3ce3bb5d05ea630177379ce4109059b6924fa362396b984ebab0ed1754318627
apoelstra added a commit that referenced this pull request Mar 28, 2022
51fef76 feat: Add Address.is_related_to_pubkey() (Andrew Ahlers)

Pull request description:

  ## Motivation

  This is addressing the second half of this comment: #684 (comment)

  > but would accept a PR (or two PRs) that returns Result<bool, UnsupportedAddress> and a method to check if a PublicKey is associated with an address.

  (The first half was addressed [here](#819))

  These changes will help build out and improve message signature verification. We don't necessarily need to add it to this crate but it allows for easy verification with something such as:
  1. recovering a pubkey
  2. checking if that pubkey relates to the given address

  ## Possible Improvements

  - There is likely a better name than `is_related_to_secp256k1_key()`
  - This could drop the `secp256k1` part of the name and take in a Pubkey enum that also supports Schnorr pubkeys and then this could be used for taproot addresses as well. This felt like a much larger change that will likely get turned down. Verifying taproot is simple enough and if absolutely desired, similar functions can be added for schnorr keys (tweaked and untweaked)

ACKs for top commit:
  Kixunil:
    ACK 51fef76 for merging after TR
  apoelstra:
    ACK 51fef76

Tree-SHA512: c9ab8c0f101fb4c647713e7f500656617025d8741676e8eb8a3132009dde9937d50cf9ac3d8055feb14452324a292397e46639cbaca71cac77af4b06dc42d09d
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.

4 participants
0