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
refactor: deduplicate the message sign/verify code #17577
Conversation
3f17b4d
to
fcb1d27
Compare
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
Looks like this is going to overlap with #17557. |
This comment has been minimized.
This comment has been minimized.
fcb1d27
to
38e24d7
Compare
I have #17557 based on an outstanding PR (#17399), though I suppose it didn't have to be. The former resulted from a comment in the latter. I deliberately kept the change small so it could hopefully be merged quicker. Though I wanted to add a test to clarify why the "magic" string is needed. That said, from a design perspective, I prefer your PR as it hides the complexity around signing a message. |
All of the above conflicts are mechanical, small and easy to resolve. |
concept ACK, though I'd probably be more pedantic in calling it "Bitcoin Signed Message Protocol" or something. Unfortunately there's no BIP to refer to. |
e3d85bc
to
1a00fb8
Compare
@instagibbs Thanks for the review! Where would you put the "Bitcoin Signed Message Protocol" label? We do message signing and verification now. What about encryption and decryption? Would that be useful feature or just a bloat that is rarely used? If encryption may be added in the future then maybe just "Bitcoin Message Protocol" would be a better name, or "Bitcoin Text Message Protocol". |
I don't think encryption / decryption in bitcoind is a good idea. It is best to avoid using keys for multiple purposes (e.g. use a signing key for encryption, and vice versa). Also it's scope creep: Bitcoin core is a validating full node. It should do that well, and not try to make a GPG-ish mess of it that tries to do everything with a mash-up of features but nothing particularly well… |
@Sjors thanks for the notice! This PR (#17577) deduplicates message signing and message verification code. I peeked at #18115 and among other things it deduplicates the message signing code from 2 of 3 places and does not deduplicate the message verification code. Assuming it also fixes the 3rd place where message signing code is repeated, then it will achieve half of this PR. Should #18115 hit |
That was fixed and now #18115 deduplicates all 3 message signing repetitions. MessageSign() from #17577 is equivalent to SignMessage() from #18115. The former has unit tests added in #17577. |
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.
Couple of nits. otherwise ACK 1a00fb8
src/qt/signverifymessagedialog.cpp
Outdated
|
||
switch (MessageVerify(address, signature, message)) { | ||
case MessageVerificationResult::ERR_INVALID_ADDRESS: | ||
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); |
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.
These ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
s could be moved out of the switch
to further reduce duplication.
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.
src/util/message.cpp
Outdated
bool MessageSign( | ||
const CKey& privkey, | ||
const std::string& message, | ||
std::string* signature) |
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.
This should be a reference (std::string&
) instead of pointer.
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.
src/test/util_tests.cpp
Outdated
const uint256 signature_hash = Hash(unsigned_tx.begin(), unsigned_tx.end()); | ||
|
||
const uint256 message_hash = MessageHash(unsigned_tx); | ||
BOOST_CHECK_NE(message_hash, signature_hash); |
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 think you should have on additional check here with the full hashed message. i.e. also hash Bitcoin Signed Message:\n...
and compare that with message_hash
.
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.
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.
Notice: assuming CHashWriter hasher(SER_GETHASH, 0);
, then:
hasher << "ab" << "cd";
would produce a different result than:
hasher << "abcd";
src/util/message.cpp
Outdated
@@ -14,7 +15,27 @@ | |||
#include <string> | |||
#include <vector> | |||
|
|||
const std::string strMessageMagic = "Bitcoin Signed Message:\n"; | |||
static const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n"; |
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.
Renaming this should probably go in the next commit?
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.
1a00fb8
to
ad39c8f
Compare
tACK ad39c8f, thanks for adding tests as well |
I'm seeing a new compiler warning:
|
case MessageVerificationResult::ERR_NOT_SIGNED: | ||
return false; | ||
case MessageVerificationResult::OK: | ||
return true; | ||
} |
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.
You need another return false
statement after this switch
.
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'm not getting that -Wreturn-type
warning on macOS. Only one of the Travis machines noticed it: https://travis-ci.org/bitcoin/bitcoin/jobs/649943882?utm_medium=notification&utm_source=github_status
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.
Added return false;
, thanks!
The logic of verifying a message was duplicated in 2 places: src/qt/signverifymessagedialog.cpp SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() src/rpc/misc.cpp verifymessage() with the only difference being the result handling. Move the logic into a dedicated src/util/message.cpp MessageVerify() which returns a set of result codes, call it from the 2 places and just handle the results differently in the callers.
The logic of signing a message was duplicated in 3 places: src/qt/signverifymessagedialog.cpp SignVerifyMessageDialog::on_signMessageButton_SM_clicked() src/rpc/misc.cpp signmessagewithprivkey() src/wallet/rpcwallet.cpp signmessage() Move the logic into src/util/message.cpp MessageSign() and call it from all the 3 places.
And add unit test for it. The purpose of using a preamble or "magic" text as part of signing and verifying a message was not given when the code was repeated in a few locations. Make a test showing how it is used to prevent inadvertently signing a transaction.
ad39c8f
to
e193a84
Compare
re-ACK e193a84 |
ACK e193a84 |
…Travis machines c98c26e ci: use --enable-werror on more hosts (Sjors Provoost) 6ba617d build: add Wreturn-type to Werror flags (Sjors Provoost) Pull request description: I overlooked a missing `return false` in #17577 (comment) and the warning only showed up on one Travis machine (`warning: control reaches end of non-void function [-Wreturn-type]`). This PR promotes `Wreturn-type` to an error when configured with `--enable-werror`. I also added `--enable-werror` to the Travis machine that happened to catch this particular instance. ACKs for top commit: vasild: ACK c98c26e. practicalswift: ACK c98c26e Tree-SHA512: 64e86c67fef2c5048aab201a8400b7e4a6f27b93d626159ba0b2807b5f119d2b0a83e3372db88f692cb4b0d059722d6a642d130c74a4f991a27f3a6b21780b5f
@meshcollider some of this touches the wallet - and #18115 that builds on top of this definitely does - so maybe you can take a look? |
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.
utACK e193a84
* @param[in] signature The signature in base64 format. | ||
* @param[in] message The message that was signed. | ||
* @return result code */ | ||
MessageVerificationResult MessageVerify( |
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.
nit: I'd prefer actual types used instead of strings for all args.
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.
this is a non-blocking comment :) let's get this merged
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.
utACK e193a84
Nice cleanup, thanks!
e193a84 Refactor message hashing into a utility function (Jeffrey Czyz) f8f0d98 Deduplicate the message signing code (Vasil Dimov) 2ce3447 Deduplicate the message verifying code (Vasil Dimov) Pull request description: The message signing and verifying logic was replicated in a few places in the code. Consolidate in a newly introduced `MessageSign()` and `MessageVerify()` and add unit tests for them. ACKs for top commit: Sjors: re-ACK e193a84 achow101: ACK e193a84 instagibbs: utACK bitcoin@e193a84 meshcollider: utACK e193a84 Tree-SHA512: b0e02a7d4623a98c8f8c77627af1725e6df07700de4630c2f75da6beacdf55414c38ba147bc6d2a757491ab07c827dddf93e8632fe600478760e255714ddab88
Summary: * Deduplicate the message verifying code The logic of verifying a message was duplicated in 2 places: src/qt/signverifymessagedialog.cpp SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() src/rpc/misc.cpp verifymessage() with the only difference being the result handling. Move the logic into a dedicated src/util/message.cpp MessageVerify() which returns a set of result codes, call it from the 2 places and just handle the results differently in the callers. * Deduplicate the message signing code The logic of signing a message was duplicated in 3 places: src/qt/signverifymessagedialog.cpp SignVerifyMessageDialog::on_signMessageButton_SM_clicked() src/rpc/misc.cpp signmessagewithprivkey() src/wallet/rpcwallet.cpp signmessage() Move the logic into src/util/message.cpp MessageSign() and call it from all the 3 places. * Refactor message hashing into a utility function And add unit test for it. The purpose of using a preamble or "magic" text as part of signing and verifying a message was not given when the code was repeated in a few locations. Make a test showing how it is used to prevent inadvertently signing a transaction. Backport of Core [[bitcoin/bitcoin#17577 | PR17577]] Test Plan: ninja all check-all Reviewers: #bitcoin_abc, majcosta Reviewed By: #bitcoin_abc, majcosta Subscribers: majcosta Differential Revision: https://reviews.bitcoinabc.org/D8098
e193a84 Refactor message hashing into a utility function (Jeffrey Czyz) f8f0d98 Deduplicate the message signing code (Vasil Dimov) 2ce3447 Deduplicate the message verifying code (Vasil Dimov) Pull request description: The message signing and verifying logic was replicated in a few places in the code. Consolidate in a newly introduced `MessageSign()` and `MessageVerify()` and add unit tests for them. ACKs for top commit: Sjors: re-ACK e193a84 achow101: ACK e193a84 instagibbs: utACK bitcoin@e193a84 meshcollider: utACK e193a84 Tree-SHA512: b0e02a7d4623a98c8f8c77627af1725e6df07700de4630c2f75da6beacdf55414c38ba147bc6d2a757491ab07c827dddf93e8632fe600478760e255714ddab88
The message signing and verifying logic was replicated in a few places
in the code. Consolidate in a newly introduced
MessageSign()
andMessageVerify()
and add unit tests for them.