mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-04 18:22:57 +02:00
Merge #17577: refactor: deduplicate the message sign/verify code
e193a84fb2Refactor message hashing into a utility function (Jeffrey Czyz)f8f0d9893dDeduplicate the message signing code (Vasil Dimov)2ce3447eb1Deduplicate 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-ACKe193a84fb2achow101: ACKe193a84fb2instagibbs: utACKe193a84fb2meshcollider: utACKe193a84fb2Tree-SHA512: b0e02a7d4623a98c8f8c77627af1725e6df07700de4630c2f75da6beacdf55414c38ba147bc6d2a757491ab07c827dddf93e8632fe600478760e255714ddab88
This commit is contained in:
78
src/util/message.cpp
Normal file
78
src/util/message.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// 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.h> // For CKey
|
||||
#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>
|
||||
|
||||
/**
|
||||
* Text used to signify that a signed message follows and to prevent
|
||||
* inadvertently signing a transaction.
|
||||
*/
|
||||
const std::string MESSAGE_MAGIC = "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;
|
||||
}
|
||||
|
||||
CPubKey pubkey;
|
||||
if (!pubkey.RecoverCompact(MessageHash(message), signature_bytes)) {
|
||||
return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
|
||||
}
|
||||
|
||||
if (!(CTxDestination(PKHash(pubkey)) == destination)) {
|
||||
return MessageVerificationResult::ERR_NOT_SIGNED;
|
||||
}
|
||||
|
||||
return MessageVerificationResult::OK;
|
||||
}
|
||||
|
||||
bool MessageSign(
|
||||
const CKey& privkey,
|
||||
const std::string& message,
|
||||
std::string& signature)
|
||||
{
|
||||
std::vector<unsigned char> signature_bytes;
|
||||
|
||||
if (!privkey.SignCompact(MessageHash(message), signature_bytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
signature = EncodeBase64(signature_bytes.data(), signature_bytes.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint256 MessageHash(const std::string& message)
|
||||
{
|
||||
CHashWriter hasher(SER_GETHASH, 0);
|
||||
hasher << MESSAGE_MAGIC << message;
|
||||
|
||||
return hasher.GetHash();
|
||||
}
|
||||
68
src/util/message.h
Normal file
68
src/util/message.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// 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 <key.h> // For CKey
|
||||
#include <uint256.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
extern const std::string MESSAGE_MAGIC;
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Sign a message.
|
||||
* @param[in] privkey Private key to sign with.
|
||||
* @param[in] message The message to sign.
|
||||
* @param[out] signature Signature, base64 encoded, only set if true is returned.
|
||||
* @return true if signing was successful. */
|
||||
bool MessageSign(
|
||||
const CKey& privkey,
|
||||
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
|
||||
@@ -21,5 +21,3 @@ std::string FormatStateMessage(const ValidationState &state)
|
||||
|
||||
return state.GetRejectReason();
|
||||
}
|
||||
|
||||
const std::string strMessageMagic = "Bitcoin Signed Message:\n";
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user