Skip to content

Commit

Permalink
rpc: Switch default MESSAGE_MAGIC from Bitcoin to Particl
Browse files Browse the repository at this point in the history
  • Loading branch information
tecnovert committed Nov 22, 2022
1 parent 2e600f0 commit 656cfeb
Show file tree
Hide file tree
Showing 24 changed files with 102 additions and 58 deletions.
8 changes: 8 additions & 0 deletions doc/release-notes-particl.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ Next Major Version
- Removed duplicate tx info in details section.
- getstakinginfo
- errors -> warnings
- verifymessage
signmessage
signmessagewithprivkey
devicesignmessage
- Switched default message magic string to 'Particl Signed Message:\\n'
- Sign functions accept a message magic parameter.
Note: The ledger firmware will still use the Bitcoin message magic string.



23.0.3
Expand Down
4 changes: 2 additions & 2 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ class Wallet
virtual bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) = 0;

//! Sign message
virtual SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) = 0;
virtual SigningResult signMessage(const std::string& message, const CKeyID256& pkhash, std::string& str_sig) = 0;
virtual SigningResult signMessage(const std::string& message, const PKHash& pkhash, const std::string &message_magic, std::string& str_sig) = 0;
virtual SigningResult signMessage(const std::string& message, const CKeyID256& pkhash, const std::string &message_magic, std::string& str_sig) = 0;

//! Return whether wallet has private key.
virtual bool isSpendable(const CTxDestination& dest) = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/qt/signverifymessagedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()

const std::string& message = ui->messageIn_SM->document()->toPlainText().toStdString();
std::string signature;
SigningResult res = model->wallet().signMessage(message, *pkhash, signature);
SigningResult res = model->wallet().signMessage(message, *pkhash, MESSAGE_MAGIC, signature);

QString error;
switch (res) {
Expand Down
6 changes: 4 additions & 2 deletions src/rpc/signmessage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ static RPCHelpMan verifymessage()
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The particl address to use for the signature."},
{"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."},
{"message_magic", RPCArg::Type::STR, RPCArg::Default{"Bitcoin Signed Message:\\n"}, "The magic string to use."},
{"message_magic", RPCArg::Type::STR, RPCArg::Default{"Particl Signed Message:\\n"}, "The magic string to use."},
},
RPCResult{
RPCResult::Type::BOOL, "", "If the signature is verified or not."
Expand Down Expand Up @@ -70,6 +70,7 @@ static RPCHelpMan signmessagewithprivkey()
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
{"message_magic", RPCArg::Type::STR, RPCArg::Default{"Particl Signed Message:\\n"}, "The magic string to use."},
},
RPCResult{
RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
Expand All @@ -86,6 +87,7 @@ static RPCHelpMan signmessagewithprivkey()
{
std::string strPrivkey = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
std::string message_magic = request.params[2].isNull() ? MESSAGE_MAGIC : request.params[2].get_str();

CKey key = DecodeSecret(strPrivkey);
if (!key.IsValid()) {
Expand All @@ -94,7 +96,7 @@ static RPCHelpMan signmessagewithprivkey()

std::string signature;

if (!MessageSign(key, strMessage, signature)) {
if (!MessageSign(key, strMessage, signature, message_magic)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
}

Expand Down
11 changes: 7 additions & 4 deletions src/test/util_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1582,7 +1582,7 @@ BOOST_AUTO_TEST_CASE(message_sign)
BOOST_REQUIRE_MESSAGE(privkey.IsValid(),
"Confirm the private key is valid");

BOOST_CHECK_MESSAGE(MessageSign(privkey, message, generated_signature),
BOOST_CHECK_MESSAGE(MessageSign(privkey, message, generated_signature, BTC_MESSAGE_MAGIC),
"Sign with a valid private key");

BOOST_CHECK_EQUAL(expected_signature, generated_signature);
Expand Down Expand Up @@ -1622,21 +1622,24 @@ BOOST_AUTO_TEST_CASE(message_verify)
MessageVerify(
"15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs",
"IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=",
"I never signed this"),
"I never signed this",
BTC_MESSAGE_MAGIC),
MessageVerificationResult::ERR_NOT_SIGNED);

BOOST_CHECK_EQUAL(
MessageVerify(
"15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs",
"IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=",
"Trust no one"),
"Trust no one",
BTC_MESSAGE_MAGIC),
MessageVerificationResult::OK);

BOOST_CHECK_EQUAL(
MessageVerify(
"11canuhp9X2NocwCq7xNrQYTmUgZAnLK3",
"IIcaIENoYW5jZWxsb3Igb24gYnJpbmsgb2Ygc2Vjb25kIGJhaWxvdXQgZm9yIGJhbmtzIAaHRtbCeDZINyavx14=",
"Trust me"),
"Trust me",
BTC_MESSAGE_MAGIC),
MessageVerificationResult::OK);
}

Expand Down
8 changes: 2 additions & 6 deletions src/usbdevice/debugdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ int CDebugDevice::GetXPub(const std::vector<uint32_t> &vPath, CExtPubKey &ekp, s
return 0;
};

int CDebugDevice::SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, std::vector<uint8_t> &vchSig, std::string &sError)
int CDebugDevice::SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, const std::string &message_magic, std::vector<uint8_t> &vchSig, std::string &sError)
{
CExtKey vkOut, vkWork = ekv;
for (auto it = vPath.begin(); it != vPath.end(); ++it) {
Expand All @@ -90,11 +90,7 @@ int CDebugDevice::SignMessage(const std::vector<uint32_t> &vPath, const std::str
vkWork = vkOut;
}

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

if (!vkOut.key.SignCompact(ss.GetHash(), vchSig)) {
if (!vkOut.key.SignCompact(MessageHash(sMessage, message_magic), vchSig)) {
return errorN(1, sError, __func__, "Sign failed");
}

Expand Down
2 changes: 1 addition & 1 deletion src/usbdevice/debugdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class CDebugDevice : public CUSBDevice
int GetPubKey(const std::vector<uint32_t> &vPath, CPubKey &pk, bool display, std::string &sError) override;
int GetXPub(const std::vector<uint32_t> &vPath, CExtPubKey &ekp, std::string &sError) override;

int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, std::vector<uint8_t> &vchSig, std::string &sError) override;
int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, const std::string &message_magic, std::vector<uint8_t> &vchSig, std::string &sError) override;

int SignTransaction(const std::vector<uint32_t> &vPath, const std::vector<uint8_t> &vSharedSecret, const CMutableTransaction *tx,
int nIn, const CScript &scriptCode, int hashType, const std::vector<uint8_t> &amount, SigVersion sigversion,
Expand Down
3 changes: 1 addition & 2 deletions src/usbdevice/ledgerdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ int CLedgerDevice::GetXPub(const std::vector<uint32_t> &vPath, CExtPubKey &ekp,
return 0;
};

int CLedgerDevice::SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, std::vector<uint8_t> &vchSig, std::string &sError)
int CLedgerDevice::SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, const std::string &message_magic, std::vector<uint8_t> &vchSig, std::string &sError)
{
if (vPath.size() < 1 || vPath.size() > MAX_BIP32_PATH) {
return errorN(1, sError, __func__, "Path depth out of range.");
Expand Down Expand Up @@ -403,7 +403,6 @@ int CLedgerDevice::SignMessage(const std::vector<uint32_t> &vPath, const std::st
return errorN(1, sError, __func__, "Message signature prepared, please powercycle to get the second factor then proceed with signing");
}


apduSize = 0;
in[apduSize++] = BTCHIP_CLA;
in[apduSize++] = BTCHIP_INS_SIGN_MESSAGE;
Expand Down
2 changes: 1 addition & 1 deletion src/usbdevice/ledgerdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class CLedgerDevice : public CUSBDevice
int GetPubKey(const std::vector<uint32_t> &vPath, CPubKey &pk, bool display, std::string &sError) override;
int GetXPub(const std::vector<uint32_t> &vPath, CExtPubKey &ekp, std::string &sError) override;

int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, std::vector<uint8_t> &vchSig, std::string &sError) override;
int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, const std::string &message_magic, std::vector<uint8_t> &vchSig, std::string &sError) override;

int PrepareTransaction(CMutableTransaction &tx, const CCoinsViewCache &view, const FillableSigningProvider &keystore, int nHashType,
int change_pos, const std::vector<uint32_t> &change_path) override;
Expand Down
7 changes: 5 additions & 2 deletions src/usbdevice/rpcusbdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ static RPCHelpMan devicesignmessage()
" The full path is \"accountpath\"/\"path\"."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to sign for."},
{"accountpath", RPCArg::Type::STR, RPCArg::Default{GetDefaultAccountPath()}, "Account path, set to empty string to ignore."},
{"message_magic", RPCArg::Type::STR, RPCArg::Default{"Particl Signed Message:\\n"}, "The magic string to use."},
},
RPCResult{
RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
Expand All @@ -452,8 +453,9 @@ static RPCHelpMan devicesignmessage()
}

std::string sError, sMessage = request.params[1].get_str();
std::string message_magic = request.params[3].isNull() ? MESSAGE_MAGIC : request.params[3].get_str();
std::vector<uint8_t> vchSig;
if (0 != pDevice->SignMessage(vPath, sMessage, vchSig, sError)) {
if (0 != pDevice->SignMessage(vPath, sMessage, message_magic, vchSig, sError)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("SignMessage failed %s.", sError));
}

Expand Down Expand Up @@ -904,9 +906,10 @@ static RPCHelpMan initaccountfromdevice()
throw JSONRPCError(RPC_INTERNAL_ERROR, "GetFullChainPath failed.");
}

// Use BTC_MESSAGE_MAGIC for backwards compatibility
vSigPath.push_back(0);
uiInterface.NotifyWaitingForDevice(false);
if (0 != pDevice->SignMessage(vSigPath, msg, vchSig, sError)) {
if (0 != pDevice->SignMessage(vSigPath, msg, BTC_MESSAGE_MAGIC, vchSig, sError)) {
sea->FreeChains();
uiInterface.NotifyWaitingForDevice(true);
throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Could not generate scan chain seed from signed message %s.", sError));
Expand Down
17 changes: 14 additions & 3 deletions src/usbdevice/trezordevice.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018-2021 The Particl Core developers
// Copyright (c) 2018-2022 The Particl Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

Expand All @@ -15,6 +15,8 @@
#include <shutdown.h>
#include <univalue.h>

#include <string>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#if defined(__GNUC__) && !defined(__clang__)
Expand Down Expand Up @@ -423,7 +425,7 @@ int CTrezorDevice::GetXPub(const std::vector<uint32_t>& vPath, CExtPubKey& ekp,
return 0;
};

int CTrezorDevice::SignMessage(const std::vector<uint32_t>& vPath, const std::string& sMessage, std::vector<uint8_t>& vchSig, std::string& sError)
int CTrezorDevice::SignMessage(const std::vector<uint32_t>& vPath, const std::string& sMessage, const std::string &message_magic, std::vector<uint8_t>& vchSig, std::string& sError)
{
if (vPath.size() < 1 || vPath.size() > 10) {
return errorN(1, sError, __func__, "Path depth out of range.");
Expand All @@ -436,7 +438,16 @@ int CTrezorDevice::SignMessage(const std::vector<uint32_t>& vPath, const std::st
msg_in.add_address_n(i);
}

msg_in.set_coin_name("Bitcoin");
std::string coin_name;
if (message_magic.find("Bitcoin") != std::string::npos) {
coin_name = "Bitcoin";
} else
if (message_magic.find("Particl") != std::string::npos) {
coin_name = "Particl";
} else {
return errorN(1, sError, __func__, "Unknown message magic string.");
}
msg_in.set_coin_name(coin_name);
msg_in.set_message(sMessage);

std::vector<uint8_t> vec_in, vec_out;
Expand Down
2 changes: 1 addition & 1 deletion src/usbdevice/trezordevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class CTrezorDevice : public CUSBDevice
int GetPubKey(const std::vector<uint32_t> &vPath, CPubKey &pk, bool display, std::string &sError) override;
int GetXPub(const std::vector<uint32_t> &vPath, CExtPubKey &ekp, std::string &sError) override;

int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, std::vector<uint8_t> &vchSig, std::string &sError) override;
int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, const std::string &message_magic, std::vector<uint8_t> &vchSig, std::string &sError) override;

int PrepareTransaction(CMutableTransaction &tx, const CCoinsViewCache &view, const FillableSigningProvider &keystore, int nHashType,
int change_pos, const std::vector<uint32_t> &change_path) override;
Expand Down
2 changes: 1 addition & 1 deletion src/usbdevice/usbdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class CUSBDevice
virtual int GetPubKey(const std::vector<uint32_t> &vPath, CPubKey &pk, bool display, std::string &sError) { return 0; };
virtual int GetXPub(const std::vector<uint32_t> &vPath, CExtPubKey &ekp, std::string &sError) { return 0; };

virtual int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, std::vector<uint8_t> &vchSig, std::string &sError) { return 0; };
virtual int SignMessage(const std::vector<uint32_t> &vPath, const std::string &sMessage, const std::string &message_magic, std::vector<uint8_t> &vchSig, std::string &sError) { return 0; };

virtual int PrepareTransaction(CMutableTransaction &tx, const CCoinsViewCache &view, const FillableSigningProvider &keystore, int nHashType,
int change_pos, const std::vector<uint32_t> &change_path) { return 0; };
Expand Down
8 changes: 5 additions & 3 deletions src/util/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
* 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";
const std::string MESSAGE_MAGIC = "Particl Signed Message:\n";
const std::string BTC_MESSAGE_MAGIC = "Bitcoin Signed Message:\n";

MessageVerificationResult MessageVerify(
const std::string& address,
Expand Down Expand Up @@ -68,11 +69,12 @@ MessageVerificationResult MessageVerify(
bool MessageSign(
const CKey& privkey,
const std::string& message,
std::string& signature)
std::string& signature,
const std::string& message_magic)
{
std::vector<unsigned char> signature_bytes;

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

Expand Down
4 changes: 3 additions & 1 deletion src/util/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
class CKey;

extern const std::string MESSAGE_MAGIC;
extern const std::string BTC_MESSAGE_MAGIC;

/** The result of a signed message verification.
* Message verification takes as an input:
Expand Down Expand Up @@ -65,7 +66,8 @@ MessageVerificationResult MessageVerify(
bool MessageSign(
const CKey& privkey,
const std::string& message,
std::string& signature);
std::string& signature,
const std::string& message_magic = MESSAGE_MAGIC);

/**
* Hashes a message for signing and verification in a manner that prevents
Expand Down
7 changes: 3 additions & 4 deletions src/wallet/hdwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <node/miner.h>
#include <pos/kernel.h>
#include <pos/miner.h>
#include <util/message.h>
#include <util/moneystr.h>
#include <util/translation.h>
#include <script/script.h>
Expand Down Expand Up @@ -8093,10 +8094,8 @@ int CHDWallet::InitAccountStealthV2Chains(CHDWalletDB *pwdb, CExtKeyAccount *sea
std::string msg = "Scan chain secret seed";
std::vector<uint8_t> vData, vchSig;

CHashWriter ss(SER_GETHASH, 0);
ss << MESSAGE_MAGIC;
ss << msg;
if (!vkAcc0_0.key.SignCompact(ss.GetHash(), vchSig)) {
// Use BTC_MESSAGE_MAGIC for backwards wallet compatibility
if (!vkAcc0_0.key.SignCompact(MessageHash(msg, BTC_MESSAGE_MAGIC), vchSig)) {
return werrorN(1, "%s: Sign failed.", __func__);
}

Expand Down
8 changes: 4 additions & 4 deletions src/wallet/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,13 @@ class WalletImpl : public Wallet
}
return false;
}
SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override
SigningResult signMessage(const std::string& message, const PKHash& pkhash, const std::string& message_magic, std::string& str_sig) override
{
return m_wallet->SignMessage(message, pkhash, str_sig);
return m_wallet->SignMessage(message, pkhash, message_magic, str_sig);
}
SigningResult signMessage(const std::string& message, const CKeyID256& pkhash, std::string& str_sig) override
SigningResult signMessage(const std::string& message, const CKeyID256& pkhash, const std::string& message_magic, std::string& str_sig) override
{
return m_wallet->SignMessage(message, pkhash, str_sig);
return m_wallet->SignMessage(message, pkhash, message_magic, str_sig);
}
bool isSpendable(const CTxDestination& dest) override
{
Expand Down
6 changes: 4 additions & 2 deletions src/wallet/rpc/signmessage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ RPCHelpMan signmessage()
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The particl address to use for the private key."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
{"message_magic", RPCArg::Type::STR, RPCArg::Default{"Particl Signed Message:\\n"}, "The magic string to use."},
},
RPCResult{
RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
Expand All @@ -44,6 +45,7 @@ RPCHelpMan signmessage()

std::string strAddress = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
std::string message_magic = request.params[2].isNull() ? MESSAGE_MAGIC : request.params[2].get_str();

CTxDestination dest = DecodeDestination(strAddress);
if (!IsValidDestination(dest)) {
Expand All @@ -58,8 +60,8 @@ RPCHelpMan signmessage()
}

std::string signature;
SigningResult err = keyID256 ? pwallet->SignMessage(strMessage, *keyID256, signature)
: pwallet->SignMessage(strMessage, *pkhash, signature);
SigningResult err = keyID256 ? pwallet->SignMessage(strMessage, *keyID256, message_magic, signature)
: pwallet->SignMessage(strMessage, *pkhash, message_magic, signature);
if (err == SigningResult::SIGNING_FAILED) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err));
} else if (err != SigningResult::OK){
Expand Down
Loading

0 comments on commit 656cfeb

Please sign in to comment.