Skip to content

Commit

Permalink
Refactor message hashing into a utility function
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jkczyz authored and vasild committed Dec 7, 2019
1 parent 640c46d commit e3d85bc
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 10 deletions.
11 changes: 11 additions & 0 deletions src/test/util_tests.cpp
Expand Up @@ -5,10 +5,12 @@
#include <util/system.h>

#include <clientversion.h>
#include <hash.h> // For Hash()
#include <key.h> // For CKey
#include <sync.h>
#include <test/util/setup_common.h>
#include <test/util.h>
#include <uint256.h>
#include <util/message.h> // For MessageSign(), MessageVerify()
#include <util/moneystr.h>
#include <util/strencodings.h>
Expand Down Expand Up @@ -1981,4 +1983,13 @@ BOOST_AUTO_TEST_CASE(message_verify)
MessageVerificationResult::OK);
}

BOOST_AUTO_TEST_CASE(message_hash)
{
const std::string unsigned_tx = "...";
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);
}

BOOST_AUTO_TEST_SUITE_END()
24 changes: 14 additions & 10 deletions src/util/message.cpp
Expand Up @@ -21,20 +21,20 @@
#include <string>
#include <vector>

/**
* Text used to signify that a signed message follows and to prevent
* inadvertently signing a transaction.
*/
static const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";

bool MessageSign(
const CKey& privkey,
const std::string& message,
std::string* signature)
{
CHashWriter ss(SER_GETHASH, 0);
ss << MESSAGE_MAGIC;
ss << message;

std::vector<unsigned char> signature_bytes;

if (!privkey.SignCompact(ss.GetHash(), signature_bytes)) {
if (!privkey.SignCompact(MessageHash(message), signature_bytes)) {
return false;
}

Expand Down Expand Up @@ -63,12 +63,8 @@ MessageVerificationResult MessageVerify(
return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
}

CHashWriter ss(SER_GETHASH, 0);
ss << MESSAGE_MAGIC;
ss << message;

CPubKey pubkey;
if (!pubkey.RecoverCompact(ss.GetHash(), signature_bytes)) {
if (!pubkey.RecoverCompact(MessageHash(message), signature_bytes)) {
return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
}

Expand All @@ -78,3 +74,11 @@ MessageVerificationResult MessageVerify(

return MessageVerificationResult::OK;
}

uint256 MessageHash(const std::string& message)
{
CHashWriter hasher(SER_GETHASH, 0);
hasher << MESSAGE_MAGIC << message;

return hasher.GetHash();
}
7 changes: 7 additions & 0 deletions src/util/message.h
Expand Up @@ -7,6 +7,7 @@
#define BITCOIN_UTIL_MESSAGE_H

#include <key.h> // For CKey
#include <uint256.h>

#include <string>

Expand Down Expand Up @@ -56,4 +57,10 @@ bool MessageSign(
const std::string& message,
std::string* signature);

/**
* Hashes a message for signing and verification in a manner that prevents
* inadvertently signing a transaction.
*/
uint256 MessageHash(const std::string& message);

#endif // BITCOIN_UTIL_MESSAGE_H

0 comments on commit e3d85bc

Please sign in to comment.