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.
This commit is contained in:
Vasil Dimov
2019-11-19 15:49:35 +01:00
parent 470664f2b7
commit 2ce3447eb1
9 changed files with 213 additions and 64 deletions

53
src/util/message.cpp Normal file
View File

@@ -0,0 +1,53 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <hash.h> // For CHashWriter
#include <key_io.h> // For DecodeDestination()
#include <pubkey.h> // For CPubKey
#include <script/standard.h> // For CTxDestination, IsValidDestination(), PKHash
#include <serialize.h> // For SER_GETHASH
#include <util/message.h>
#include <util/strencodings.h> // For DecodeBase64()
#include <string>
#include <vector>
const std::string strMessageMagic = "Bitcoin Signed Message:\n";
MessageVerificationResult MessageVerify(
const std::string& address,
const std::string& signature,
const std::string& message)
{
CTxDestination destination = DecodeDestination(address);
if (!IsValidDestination(destination)) {
return MessageVerificationResult::ERR_INVALID_ADDRESS;
}
if (boost::get<PKHash>(&destination) == nullptr) {
return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
}
bool invalid = false;
std::vector<unsigned char> signature_bytes = DecodeBase64(signature.c_str(), &invalid);
if (invalid) {
return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
}
CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << message;
CPubKey pubkey;
if (!pubkey.RecoverCompact(ss.GetHash(), signature_bytes)) {
return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
}
if (!(CTxDestination(PKHash(pubkey)) == destination)) {
return MessageVerificationResult::ERR_NOT_SIGNED;
}
return MessageVerificationResult::OK;
}

49
src/util/message.h Normal file
View File

@@ -0,0 +1,49 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_MESSAGE_H
#define BITCOIN_UTIL_MESSAGE_H
#include <string>
extern const std::string strMessageMagic;
/** The result of a signed message verification.
* Message verification takes as an input:
* - address (with whose private key the message is supposed to have been signed)
* - signature
* - message
*/
enum class MessageVerificationResult {
//! The provided address is invalid.
ERR_INVALID_ADDRESS,
//! The provided address is valid but does not refer to a public key.
ERR_ADDRESS_NO_KEY,
//! The provided signature couldn't be parsed (maybe invalid base64).
ERR_MALFORMED_SIGNATURE,
//! A public key could not be recovered from the provided signature and message.
ERR_PUBKEY_NOT_RECOVERED,
//! The message was not signed with the private key of the provided address.
ERR_NOT_SIGNED,
//! The message verification was successful.
OK
};
/** Verify a signed message.
* @param[in] address Signer's bitcoin address, it must refer to a public key.
* @param[in] signature The signature in base64 format.
* @param[in] message The message that was signed.
* @return result code */
MessageVerificationResult MessageVerify(
const std::string& address,
const std::string& signature,
const std::string& message);
#endif // BITCOIN_UTIL_MESSAGE_H

View File

@@ -21,5 +21,3 @@ std::string FormatStateMessage(const ValidationState &state)
return state.GetRejectReason();
}
const std::string strMessageMagic = "Bitcoin Signed Message:\n";

View File

@@ -13,6 +13,4 @@ class ValidationState;
/** Convert ValidationState to a human-readable message for logging */
std::string FormatStateMessage(const ValidationState &state);
extern const std::string strMessageMagic;
#endif // BITCOIN_UTIL_VALIDATION_H