Skip to content

Commit f8f0d98

Browse files
committed
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.
1 parent 2ce3447 commit f8f0d98

File tree

6 files changed

+87
-23
lines changed

6 files changed

+87
-23
lines changed

src/qt/signverifymessagedialog.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <qt/walletmodel.h>
1212

1313
#include <key_io.h>
14-
#include <util/message.h> // For strMessageMagic, MessageVerify()
14+
#include <util/message.h> // For MessageSign(), MessageVerify()
1515
#include <wallet/wallet.h>
1616

1717
#include <vector>
@@ -141,13 +141,10 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
141141
return;
142142
}
143143

144-
CHashWriter ss(SER_GETHASH, 0);
145-
ss << strMessageMagic;
146-
ss << ui->messageIn_SM->document()->toPlainText().toStdString();
144+
const std::string& message = ui->messageIn_SM->document()->toPlainText().toStdString();
145+
std::string signature;
147146

148-
std::vector<unsigned char> vchSig;
149-
if (!key.SignCompact(ss.GetHash(), vchSig))
150-
{
147+
if (!MessageSign(key, message, signature)) {
151148
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
152149
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>"));
153150
return;
@@ -156,7 +153,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
156153
ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
157154
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));
158155

159-
ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(vchSig.data(), vchSig.size())));
156+
ui->signatureOut_SM->setText(QString::fromStdString(signature));
160157
}
161158

162159
void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()

src/rpc/misc.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <rpc/util.h>
1212
#include <script/descriptor.h>
1313
#include <util/check.h>
14-
#include <util/message.h> // For strMessageMagic, MessageVerify()
14+
#include <util/message.h> // For MessageSign(), MessageVerify()
1515
#include <util/strencodings.h>
1616
#include <util/system.h>
1717

@@ -322,15 +322,13 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
322322
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
323323
}
324324

325-
CHashWriter ss(SER_GETHASH, 0);
326-
ss << strMessageMagic;
327-
ss << strMessage;
325+
std::string signature;
328326

329-
std::vector<unsigned char> vchSig;
330-
if (!key.SignCompact(ss.GetHash(), vchSig))
327+
if (!MessageSign(key, strMessage, signature)) {
331328
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
329+
}
332330

333-
return EncodeBase64(vchSig.data(), vchSig.size());
331+
return signature;
334332
}
335333

336334
static UniValue setmocktime(const JSONRPCRequest& request)

src/test/util_tests.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@
55
#include <util/system.h>
66

77
#include <clientversion.h>
8+
#include <key.h> // For CKey
89
#include <optional.h>
910
#include <sync.h>
1011
#include <test/util/setup_common.h>
1112
#include <test/util/str.h>
12-
#include <util/message.h> // For MessageVerify()
13+
#include <util/message.h> // For MessageSign(), MessageVerify()
1314
#include <util/moneystr.h>
1415
#include <util/strencodings.h>
1516
#include <util/string.h>
1617
#include <util/time.h>
1718
#include <util/spanparsing.h>
1819
#include <util/vector.h>
1920

21+
#include <array>
2022
#include <stdint.h>
2123
#include <thread>
2224
#include <univalue.h>
@@ -2026,6 +2028,42 @@ BOOST_AUTO_TEST_CASE(test_tracked_vector)
20262028
BOOST_CHECK_EQUAL(v8[2].copies, 0);
20272029
}
20282030

2031+
BOOST_AUTO_TEST_CASE(message_sign)
2032+
{
2033+
const std::array<unsigned char, 32> privkey_bytes = {
2034+
// just some random data
2035+
// derived address from this private key: 15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs
2036+
0xD9, 0x7F, 0x51, 0x08, 0xF1, 0x1C, 0xDA, 0x6E,
2037+
0xEE, 0xBA, 0xAA, 0x42, 0x0F, 0xEF, 0x07, 0x26,
2038+
0xB1, 0xF8, 0x98, 0x06, 0x0B, 0x98, 0x48, 0x9F,
2039+
0xA3, 0x09, 0x84, 0x63, 0xC0, 0x03, 0x28, 0x66
2040+
};
2041+
2042+
const std::string message = "Trust no one";
2043+
2044+
const std::string expected_signature =
2045+
"IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=";
2046+
2047+
CKey privkey;
2048+
std::string generated_signature;
2049+
2050+
BOOST_REQUIRE_MESSAGE(!privkey.IsValid(),
2051+
"Confirm the private key is invalid");
2052+
2053+
BOOST_CHECK_MESSAGE(!MessageSign(privkey, message, generated_signature),
2054+
"Sign with an invalid private key");
2055+
2056+
privkey.Set(privkey_bytes.begin(), privkey_bytes.end(), true);
2057+
2058+
BOOST_REQUIRE_MESSAGE(privkey.IsValid(),
2059+
"Confirm the private key is valid");
2060+
2061+
BOOST_CHECK_MESSAGE(MessageSign(privkey, message, generated_signature),
2062+
"Sign with a valid private key");
2063+
2064+
BOOST_CHECK_EQUAL(expected_signature, generated_signature);
2065+
}
2066+
20292067
BOOST_AUTO_TEST_CASE(message_verify)
20302068
{
20312069
BOOST_CHECK_EQUAL(

src/util/message.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

66
#include <hash.h> // For CHashWriter
7+
#include <key.h> // For CKey
78
#include <key_io.h> // For DecodeDestination()
89
#include <pubkey.h> // For CPubKey
910
#include <script/standard.h> // For CTxDestination, IsValidDestination(), PKHash
@@ -51,3 +52,23 @@ MessageVerificationResult MessageVerify(
5152

5253
return MessageVerificationResult::OK;
5354
}
55+
56+
bool MessageSign(
57+
const CKey& privkey,
58+
const std::string& message,
59+
std::string& signature)
60+
{
61+
CHashWriter ss(SER_GETHASH, 0);
62+
ss << strMessageMagic;
63+
ss << message;
64+
65+
std::vector<unsigned char> signature_bytes;
66+
67+
if (!privkey.SignCompact(ss.GetHash(), signature_bytes)) {
68+
return false;
69+
}
70+
71+
signature = EncodeBase64(signature_bytes.data(), signature_bytes.size());
72+
73+
return true;
74+
}

src/util/message.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#ifndef BITCOIN_UTIL_MESSAGE_H
77
#define BITCOIN_UTIL_MESSAGE_H
88

9+
#include <key.h> // For CKey
10+
911
#include <string>
1012

1113
extern const std::string strMessageMagic;
@@ -46,4 +48,14 @@ MessageVerificationResult MessageVerify(
4648
const std::string& signature,
4749
const std::string& message);
4850

51+
/** Sign a message.
52+
* @param[in] privkey Private key to sign with.
53+
* @param[in] message The message to sign.
54+
* @param[out] signature Signature, base64 encoded, only set if true is returned.
55+
* @return true if signing was successful. */
56+
bool MessageSign(
57+
const CKey& privkey,
58+
const std::string& message,
59+
std::string& signature);
60+
4961
#endif // BITCOIN_UTIL_MESSAGE_H

src/wallet/rpcwallet.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include <script/sign.h>
2020
#include <util/bip32.h>
2121
#include <util/fees.h>
22-
#include <util/message.h> // For strMessageMagic
22+
#include <util/message.h> // For MessageSign()
2323
#include <util/moneystr.h>
2424
#include <util/string.h>
2525
#include <util/system.h>
@@ -576,15 +576,13 @@ static UniValue signmessage(const JSONRPCRequest& request)
576576
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
577577
}
578578

579-
CHashWriter ss(SER_GETHASH, 0);
580-
ss << strMessageMagic;
581-
ss << strMessage;
579+
std::string signature;
582580

583-
std::vector<unsigned char> vchSig;
584-
if (!key.SignCompact(ss.GetHash(), vchSig))
581+
if (!MessageSign(key, strMessage, signature)) {
585582
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
583+
}
586584

587-
return EncodeBase64(vchSig.data(), vchSig.size());
585+
return signature;
588586
}
589587

590588
static UniValue getreceivedbyaddress(const JSONRPCRequest& request)

0 commit comments

Comments
 (0)