mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
merge bitcoin#17577: deduplicate the message sign/verify code
This commit is contained in:
parent
0e58b340e6
commit
d155f13c76
@ -303,6 +303,7 @@ BITCOIN_CORE_H = \
|
||||
util/getuniquepath.h \
|
||||
util/macros.h \
|
||||
util/memory.h \
|
||||
util/message.h \
|
||||
util/moneystr.h \
|
||||
util/ranges.h \
|
||||
util/ref.h \
|
||||
@ -702,13 +703,14 @@ libbitcoin_util_a_SOURCES = \
|
||||
support/cleanse.cpp \
|
||||
sync.cpp \
|
||||
threadinterrupt.cpp \
|
||||
util/asmap.cpp \
|
||||
util/bip32.cpp \
|
||||
util/bytevectorhash.cpp \
|
||||
util/error.cpp \
|
||||
util/fees.cpp \
|
||||
util/getuniquepath.cpp \
|
||||
util/system.cpp \
|
||||
util/asmap.cpp \
|
||||
util/message.cpp \
|
||||
util/moneystr.cpp \
|
||||
util/settings.cpp \
|
||||
util/spanparsing.cpp \
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <key_io.h>
|
||||
#include <hash.h>
|
||||
#include <util/validation.h> // For strMessageMagic
|
||||
#include <util/message.h> // For MESSAGE_MAGIC
|
||||
#include <messagesigner.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -23,7 +23,7 @@ bool CMessageSigner::GetKeysFromSecret(const std::string& strSecret, CKey& keyRe
|
||||
bool CMessageSigner::SignMessage(const std::string& strMessage, std::vector<unsigned char>& vchSigRet, const CKey& key)
|
||||
{
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << MESSAGE_MAGIC;
|
||||
ss << strMessage;
|
||||
|
||||
return CHashSigner::SignHash(ss.GetHash(), key, vchSigRet);
|
||||
@ -37,7 +37,7 @@ bool CMessageSigner::VerifyMessage(const CPubKey& pubkey, const std::vector<unsi
|
||||
bool CMessageSigner::VerifyMessage(const CKeyID& keyID, const std::vector<unsigned char>& vchSig, const std::string& strMessage, std::string& strErrorRet)
|
||||
{
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << MESSAGE_MAGIC;
|
||||
ss << strMessage;
|
||||
|
||||
return CHashSigner::VerifyHash(ss.GetHash(), keyID, vchSig, strErrorRet);
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <key_io.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/validation.h> // For strMessageMagic
|
||||
#include <util/message.h> // For MessageSign(), MessageVerify()
|
||||
#include <validation.h>
|
||||
|
||||
#include <vector>
|
||||
@ -169,13 +169,10 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << ui->messageIn_SM->document()->toPlainText().toStdString();
|
||||
const std::string& message = ui->messageIn_SM->document()->toPlainText().toStdString();
|
||||
std::string signature;
|
||||
|
||||
std::vector<unsigned char> vchSig;
|
||||
if (!key.SignCompact(ss.GetHash(), vchSig))
|
||||
{
|
||||
if (!MessageSign(key, message, signature)) {
|
||||
ui->statusLabel_SM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR));
|
||||
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>"));
|
||||
return;
|
||||
@ -184,7 +181,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
|
||||
ui->statusLabel_SM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_SUCCESS));
|
||||
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));
|
||||
|
||||
ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(vchSig)));
|
||||
ui->signatureOut_SM->setText(QString::fromStdString(signature));
|
||||
}
|
||||
|
||||
void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
|
||||
@ -217,51 +214,57 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
|
||||
|
||||
void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
|
||||
{
|
||||
CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString());
|
||||
if (!IsValidDestination(destination)) {
|
||||
const std::string& address = ui->addressIn_VM->text().toStdString();
|
||||
const std::string& signature = ui->signatureIn_VM->text().toStdString();
|
||||
const std::string& message = ui->messageIn_VM->document()->toPlainText().toStdString();
|
||||
|
||||
const auto result = MessageVerify(address, signature, message);
|
||||
|
||||
if (result == MessageVerificationResult::OK) {
|
||||
ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_SUCCESS));
|
||||
} else {
|
||||
ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR));
|
||||
ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
|
||||
return;
|
||||
}
|
||||
if (!boost::get<CKeyID>(&destination)) {
|
||||
|
||||
switch (result) {
|
||||
case MessageVerificationResult::OK:
|
||||
ui->statusLabel_VM->setText(
|
||||
QString("<nobr>") + tr("Message verified.") + QString("</nobr>")
|
||||
);
|
||||
return;
|
||||
case MessageVerificationResult::ERR_INVALID_ADDRESS:
|
||||
ui->statusLabel_VM->setText(
|
||||
tr("The entered address is invalid.") + QString(" ") +
|
||||
tr("Please check the address and try again.")
|
||||
);
|
||||
return;
|
||||
case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
|
||||
ui->addressIn_VM->setValid(false);
|
||||
ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR));
|
||||
ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
|
||||
ui->statusLabel_VM->setText(
|
||||
tr("The entered address does not refer to a key.") + QString(" ") +
|
||||
tr("Please check the address and try again.")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
bool fInvalid = false;
|
||||
std::vector<unsigned char> vchSig = DecodeBase64(ui->signatureIn_VM->text().toStdString().c_str(), &fInvalid);
|
||||
|
||||
if (fInvalid)
|
||||
{
|
||||
case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
|
||||
ui->signatureIn_VM->setValid(false);
|
||||
ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR));
|
||||
ui->statusLabel_VM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again."));
|
||||
ui->statusLabel_VM->setText(
|
||||
tr("The signature could not be decoded.") + QString(" ") +
|
||||
tr("Please check the signature and try again.")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << ui->messageIn_VM->document()->toPlainText().toStdString();
|
||||
|
||||
CPubKey pubkey;
|
||||
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
|
||||
{
|
||||
case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
|
||||
ui->signatureIn_VM->setValid(false);
|
||||
ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR));
|
||||
ui->statusLabel_VM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again."));
|
||||
ui->statusLabel_VM->setText(
|
||||
tr("The signature did not match the message digest.") + QString(" ") +
|
||||
tr("Please check the signature and try again.")
|
||||
);
|
||||
return;
|
||||
case MessageVerificationResult::ERR_NOT_SIGNED:
|
||||
ui->statusLabel_VM->setText(
|
||||
QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(CTxDestination(pubkey.GetID()) == destination)) {
|
||||
ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR));
|
||||
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
|
||||
return;
|
||||
}
|
||||
|
||||
ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_SUCCESS));
|
||||
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verified.") + QString("</nobr>"));
|
||||
}
|
||||
|
||||
void SignVerifyMessageDialog::on_clearButton_VM_clicked()
|
||||
|
@ -20,11 +20,11 @@
|
||||
#include <script/descriptor.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/check.h>
|
||||
#include <util/message.h> // For MessageSign(), MessageVerify()
|
||||
#include <util/ref.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/system.h>
|
||||
#include <validation.h>
|
||||
#include <util/validation.h>
|
||||
|
||||
#include <masternode/sync.h>
|
||||
#include <spork.h>
|
||||
@ -443,31 +443,21 @@ static UniValue verifymessage(const JSONRPCRequest& request)
|
||||
std::string strSign = request.params[1].get_str();
|
||||
std::string strMessage = request.params[2].get_str();
|
||||
|
||||
CTxDestination destination = DecodeDestination(strAddress);
|
||||
if (!IsValidDestination(destination)) {
|
||||
switch (MessageVerify(strAddress, strSign, strMessage)) {
|
||||
case MessageVerificationResult::ERR_INVALID_ADDRESS:
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
|
||||
}
|
||||
|
||||
const CKeyID *keyID = boost::get<CKeyID>(&destination);
|
||||
if (!keyID) {
|
||||
case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
|
||||
case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
|
||||
case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
|
||||
case MessageVerificationResult::ERR_NOT_SIGNED:
|
||||
return false;
|
||||
case MessageVerificationResult::OK:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fInvalid = false;
|
||||
std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
|
||||
|
||||
if (fInvalid)
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
|
||||
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << strMessage;
|
||||
|
||||
CPubKey pubkey;
|
||||
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
|
||||
return false;
|
||||
|
||||
return (pubkey.GetID() == *keyID);
|
||||
return false;
|
||||
}
|
||||
|
||||
static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
|
||||
@ -499,15 +489,13 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
|
||||
}
|
||||
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << strMessage;
|
||||
std::string signature;
|
||||
|
||||
std::vector<unsigned char> vchSig;
|
||||
if (!key.SignCompact(ss.GetHash(), vchSig))
|
||||
if (!MessageSign(key, strMessage, signature)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
|
||||
}
|
||||
|
||||
return EncodeBase64(vchSig);
|
||||
return signature;
|
||||
}
|
||||
|
||||
static UniValue setmocktime(const JSONRPCRequest& request)
|
||||
|
@ -16,8 +16,8 @@
|
||||
#include <protocol.h>
|
||||
#include <script/standard.h>
|
||||
#include <timedata.h>
|
||||
#include <util/message.h> // for MESSAGE_MAGIC
|
||||
#include <util/ranges.h>
|
||||
#include <util/validation.h> // for strMessageMagic
|
||||
#include <validation.h>
|
||||
|
||||
#include <string>
|
||||
@ -422,7 +422,7 @@ bool CSporkMessage::GetSignerKeyID(CKeyID& retKeyidSporkSigner) const
|
||||
} else {
|
||||
std::string strMessage = std::to_string(nSporkID) + std::to_string(nValue) + std::to_string(nTimeSigned);
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << MESSAGE_MAGIC;
|
||||
ss << strMessage;
|
||||
if (!pubkeyFromSig.RecoverCompact(ss.GetHash(), vchSig)) {
|
||||
return false;
|
||||
|
@ -5,18 +5,23 @@
|
||||
#include <util/system.h>
|
||||
|
||||
#include <clientversion.h>
|
||||
#include <hash.h> // For Hash()
|
||||
#include <key.h> // For CKey
|
||||
#include <sync.h>
|
||||
#include <test/util/logging.h>
|
||||
#include <test/util.h>
|
||||
#include <uint256.h>
|
||||
#include <util/getuniquepath.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
|
||||
#include <util/moneystr.h>
|
||||
#include <util/time.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <util/vector.h>
|
||||
#include <util/spanparsing.h>
|
||||
|
||||
#include <array>
|
||||
#include <stdint.h>
|
||||
#include <thread>
|
||||
#include <univalue.h>
|
||||
@ -1911,4 +1916,109 @@ BOOST_AUTO_TEST_CASE(test_LogEscapeMessage)
|
||||
BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage(NUL), R"(O\x00O)");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(message_sign)
|
||||
{
|
||||
const std::array<unsigned char, 32> privkey_bytes = {
|
||||
// just some random data
|
||||
// derived address from this private key: XetGnWHsPXV9VSkWzB6Wn2KhZLD24gqa5j
|
||||
0xD9, 0x7F, 0x51, 0x08, 0xF1, 0x1C, 0xDA, 0x6E,
|
||||
0xEE, 0xBA, 0xAA, 0x42, 0x0F, 0xEF, 0x07, 0x26,
|
||||
0xB1, 0xF8, 0x98, 0x06, 0x0B, 0x98, 0x48, 0x9F,
|
||||
0xA3, 0x09, 0x84, 0x63, 0xC0, 0x03, 0x28, 0x66
|
||||
};
|
||||
|
||||
const std::string message = "Trust no one";
|
||||
|
||||
const std::string expected_signature =
|
||||
"IIOzMDkvw3GtLWXkeEYRRRH53MOLHM44sJ428Nu4NNacTPJTGcKesMJ+3s3OadYK34tpSQIhu922EviNNWTsiQg=";
|
||||
|
||||
CKey privkey;
|
||||
std::string generated_signature;
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(!privkey.IsValid(),
|
||||
"Confirm the private key is invalid");
|
||||
|
||||
BOOST_CHECK_MESSAGE(!MessageSign(privkey, message, generated_signature),
|
||||
"Sign with an invalid private key");
|
||||
|
||||
privkey.Set(privkey_bytes.begin(), privkey_bytes.end(), true);
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(privkey.IsValid(),
|
||||
"Confirm the private key is valid");
|
||||
|
||||
BOOST_CHECK_MESSAGE(MessageSign(privkey, message, generated_signature),
|
||||
"Sign with a valid private key");
|
||||
|
||||
BOOST_CHECK_EQUAL(expected_signature, generated_signature);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(message_verify)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(
|
||||
MessageVerify(
|
||||
"invalid address",
|
||||
"signature should be irrelevant",
|
||||
"message too"),
|
||||
MessageVerificationResult::ERR_INVALID_ADDRESS);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
MessageVerify(
|
||||
"7iRPy8FEHBzbChrktsG85YbDZ3SuiCxsNq",
|
||||
"signature should be irrelevant",
|
||||
"message too"),
|
||||
MessageVerificationResult::ERR_ADDRESS_NO_KEY);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
MessageVerify(
|
||||
"XuXS24zs2xP1vPynvNt14kWLa64csH8Mur",
|
||||
"invalid signature, not in base64 encoding",
|
||||
"message should be irrelevant"),
|
||||
MessageVerificationResult::ERR_MALFORMED_SIGNATURE);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
MessageVerify(
|
||||
"XuXS24zs2xP1vPynvNt14kWLa64csH8Mur",
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"message should be irrelevant"),
|
||||
MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
MessageVerify(
|
||||
"XetGnWHsPXV9VSkWzB6Wn2KhZLD24gqa5j",
|
||||
"IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=",
|
||||
"I never signed this"),
|
||||
MessageVerificationResult::ERR_NOT_SIGNED);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
MessageVerify(
|
||||
"XetGnWHsPXV9VSkWzB6Wn2KhZLD24gqa5j",
|
||||
"IIOzMDkvw3GtLWXkeEYRRRH53MOLHM44sJ428Nu4NNacTPJTGcKesMJ+3s3OadYK34tpSQIhu922EviNNWTsiQg=",
|
||||
"Trust no one"),
|
||||
MessageVerificationResult::OK);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
MessageVerify(
|
||||
"XenV77v8QQ3rwjyCb3j2fCwfvgbkC4Vwaj",
|
||||
"IOACalWiJTLJ2U7wTKICx5mQ2tOAJ3to8dko8FMb2XSYbmvL+yMWedyfSfaK6V8jwoociyYx628nkXXnrOhPFIY=",
|
||||
"Trust me"),
|
||||
MessageVerificationResult::OK);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(message_hash)
|
||||
{
|
||||
const std::string unsigned_tx = "...";
|
||||
const std::string prefixed_message =
|
||||
std::string(1, (char)MESSAGE_MAGIC.length()) +
|
||||
MESSAGE_MAGIC +
|
||||
std::string(1, (char)unsigned_tx.length()) +
|
||||
unsigned_tx;
|
||||
|
||||
const uint256 signature_hash = Hash(unsigned_tx.begin(), unsigned_tx.end());
|
||||
const uint256 message_hash1 = Hash(prefixed_message.begin(), prefixed_message.end());
|
||||
const uint256 message_hash2 = MessageHash(unsigned_tx);
|
||||
|
||||
BOOST_CHECK_EQUAL(message_hash1, message_hash2);
|
||||
BOOST_CHECK_NE(message_hash1, signature_hash);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
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(), CKeyID
|
||||
#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 = "DarkCoin 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<CKeyID>(&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(pubkey.GetID()) == 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);
|
||||
|
||||
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
|
@ -16,5 +16,3 @@ std::string FormatStateMessage(const CValidationState &state)
|
||||
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
|
||||
state.GetRejectCode());
|
||||
}
|
||||
|
||||
const std::string strMessageMagic = "DarkCoin Signed Message:\n";
|
||||
|
@ -13,6 +13,4 @@ class CValidationState;
|
||||
/** Convert CValidationState to a human-readable message for logging */
|
||||
std::string FormatStateMessage(const CValidationState &state);
|
||||
|
||||
extern const std::string strMessageMagic;
|
||||
|
||||
#endif // BITCOIN_UTIL_VALIDATION_H
|
||||
|
@ -19,13 +19,13 @@
|
||||
#include <script/descriptor.h>
|
||||
#include <util/bip32.h>
|
||||
#include <util/fees.h>
|
||||
#include <util/message.h> // For MessageSign()
|
||||
#include <util/system.h>
|
||||
#include <util/moneystr.h>
|
||||
#include <util/ref.h>
|
||||
#include <util/string.h>
|
||||
#include <util/translation.h>
|
||||
#include <util/url.h>
|
||||
#include <util/validation.h>
|
||||
#include <util/vector.h>
|
||||
#include <validation.h>
|
||||
#include <wallet/coincontrol.h>
|
||||
@ -596,15 +596,13 @@ static UniValue signmessage(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
|
||||
}
|
||||
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
ss << strMessageMagic;
|
||||
ss << strMessage;
|
||||
std::string signature;
|
||||
|
||||
std::vector<unsigned char> vchSig;
|
||||
if (!key.SignCompact(ss.GetHash(), vchSig))
|
||||
if (!MessageSign(key, strMessage, signature)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
|
||||
}
|
||||
|
||||
return EncodeBase64(vchSig);
|
||||
return signature;
|
||||
}
|
||||
|
||||
static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
|
||||
|
Loading…
Reference in New Issue
Block a user