Skip to content

Commit e193a84

Browse files
jkczyzvasild
authored andcommitted
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.
1 parent f8f0d98 commit e193a84

File tree

3 files changed

+43
-13
lines changed

3 files changed

+43
-13
lines changed

src/test/util_tests.cpp

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

77
#include <clientversion.h>
8+
#include <hash.h> // For Hash()
89
#include <key.h> // For CKey
910
#include <optional.h>
1011
#include <sync.h>
1112
#include <test/util/setup_common.h>
1213
#include <test/util/str.h>
13-
#include <util/message.h> // For MessageSign(), MessageVerify()
14+
#include <uint256.h>
15+
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
1416
#include <util/moneystr.h>
1517
#include <util/strencodings.h>
1618
#include <util/string.h>
@@ -2116,4 +2118,21 @@ BOOST_AUTO_TEST_CASE(message_verify)
21162118
MessageVerificationResult::OK);
21172119
}
21182120

2121+
BOOST_AUTO_TEST_CASE(message_hash)
2122+
{
2123+
const std::string unsigned_tx = "...";
2124+
const std::string prefixed_message =
2125+
std::string(1, (char)MESSAGE_MAGIC.length()) +
2126+
MESSAGE_MAGIC +
2127+
std::string(1, (char)unsigned_tx.length()) +
2128+
unsigned_tx;
2129+
2130+
const uint256 signature_hash = Hash(unsigned_tx.begin(), unsigned_tx.end());
2131+
const uint256 message_hash1 = Hash(prefixed_message.begin(), prefixed_message.end());
2132+
const uint256 message_hash2 = MessageHash(unsigned_tx);
2133+
2134+
BOOST_CHECK_EQUAL(message_hash1, message_hash2);
2135+
BOOST_CHECK_NE(message_hash1, signature_hash);
2136+
}
2137+
21192138
BOOST_AUTO_TEST_SUITE_END()

src/util/message.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
#include <string>
1616
#include <vector>
1717

18-
const std::string strMessageMagic = "Bitcoin Signed Message:\n";
18+
/**
19+
* Text used to signify that a signed message follows and to prevent
20+
* inadvertently signing a transaction.
21+
*/
22+
const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
1923

2024
MessageVerificationResult MessageVerify(
2125
const std::string& address,
@@ -37,12 +41,8 @@ MessageVerificationResult MessageVerify(
3741
return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
3842
}
3943

40-
CHashWriter ss(SER_GETHASH, 0);
41-
ss << strMessageMagic;
42-
ss << message;
43-
4444
CPubKey pubkey;
45-
if (!pubkey.RecoverCompact(ss.GetHash(), signature_bytes)) {
45+
if (!pubkey.RecoverCompact(MessageHash(message), signature_bytes)) {
4646
return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
4747
}
4848

@@ -58,17 +58,21 @@ bool MessageSign(
5858
const std::string& message,
5959
std::string& signature)
6060
{
61-
CHashWriter ss(SER_GETHASH, 0);
62-
ss << strMessageMagic;
63-
ss << message;
64-
6561
std::vector<unsigned char> signature_bytes;
6662

67-
if (!privkey.SignCompact(ss.GetHash(), signature_bytes)) {
63+
if (!privkey.SignCompact(MessageHash(message), signature_bytes)) {
6864
return false;
6965
}
7066

7167
signature = EncodeBase64(signature_bytes.data(), signature_bytes.size());
7268

7369
return true;
7470
}
71+
72+
uint256 MessageHash(const std::string& message)
73+
{
74+
CHashWriter hasher(SER_GETHASH, 0);
75+
hasher << MESSAGE_MAGIC << message;
76+
77+
return hasher.GetHash();
78+
}

src/util/message.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
#define BITCOIN_UTIL_MESSAGE_H
88

99
#include <key.h> // For CKey
10+
#include <uint256.h>
1011

1112
#include <string>
1213

13-
extern const std::string strMessageMagic;
14+
extern const std::string MESSAGE_MAGIC;
1415

1516
/** The result of a signed message verification.
1617
* Message verification takes as an input:
@@ -58,4 +59,10 @@ bool MessageSign(
5859
const std::string& message,
5960
std::string& signature);
6061

62+
/**
63+
* Hashes a message for signing and verification in a manner that prevents
64+
* inadvertently signing a transaction.
65+
*/
66+
uint256 MessageHash(const std::string& message);
67+
6168
#endif // BITCOIN_UTIL_MESSAGE_H

0 commit comments

Comments
 (0)