-
Notifications
You must be signed in to change notification settings - Fork 831
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
fix: Throw Error on unsuported addresses in is_signed_by_address()
#819
Conversation
c271b83
to
782182e
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.
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), |
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.
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.
This comment was marked as resolved.
Sorry, something went wrong.
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.
Yes good catch. I hope an explicit address_type
is acceptable.
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.
@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
let msg = secp256k1::Message::from_slice(&msg_hash[..]) | ||
.map_err(MessageSignatureError::UnableToRecoverPubKey)?; |
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.
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.
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.
Wouldn't an explicit map be better here? It helps differentiate between InvalidEncoding(secp256k1::Error) and UnableToRecoverPubKey(secp256k1::Error)
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.
There are two actually.
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.
Message::from_slice
cannot fail. This should actually be an .expect
but ?
was shorter to type and it doesn't matter anyway.
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 can add the expect
and then remove UnableToRecoverPublicKey
is so desired.
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.
What the hell, it only takes a second. Changed in 1be1bb72d1a
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.
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?
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.
@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)
}
}
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.
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; |
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 could use use super::*
at the top of the tests
module and then wouldn't need this import statement.
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.
done
13deba9
to
2f34b8e
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.
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)), |
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.
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?
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.
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.
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.
Yes, it is very unlikely that any new signature schemes are going to show up which support onlly specific address types.
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.
@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.
2f34b8e
to
2bc9115
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 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"); |
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.
Actually just let msg = secp256k1::Message::from(msg_hash);
should be possible if we activate bitcoin_hashes
feature of secp256k1 .
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 nice, I forgot that we finally added that feature. Yes, let's do this.
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.
Opened #824 for that.
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.
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); |
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.
Not relevant to this PR but I noticed we don't have Ok(false)
test for broken signatures.
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 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. |
@tcharding yes it does need love but these cases don't require MSRV bump (unless |
Oh cool, thanks, so we can start thinking about this right away. |
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 8a05ca042d4e8e28a60efecaf7b542ef3232ec52
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. |
Yeah, no problem
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 |
8a05ca0
to
31ec64d
Compare
@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. |
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 31ec64d
Looks like |
@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 |
@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. |
Inspired by this comment: rust-bitcoin#684 (comment)
31ec64d
to
79cee4c
Compare
@apoelstra yes, just tested it out in my fork. 79cee4c should solve the CI issues |
It does seem to be working. Quite concerning that the |
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 |
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 79cee4c
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 79cee4c
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. |
…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
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
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