Incorporate pubkey in signature, check based on address

Include the public key in the signature string, to allow verification
based on address.
This commit is contained in:
Pieter Wuille 2011-09-19 20:03:03 +02:00
parent cc2567e32f
commit b53d6284eb
1 changed files with 49 additions and 37 deletions

View File

@ -526,6 +526,8 @@ Value sendtoaddress(const Array& params, bool fHelp)
return wtx.GetHash().GetHex(); return wtx.GetHash().GetHex();
} }
static const string strMessageMagic = "Bitcoin Signed Message:\n";
Value signmessage(const Array& params, bool fHelp) Value signmessage(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 2) if (fHelp || params.size() != 2)
@ -533,61 +535,71 @@ Value signmessage(const Array& params, bool fHelp)
"signmessage <bitcoinaddress> <message>\n" "signmessage <bitcoinaddress> <message>\n"
"Sign a message with the private key of an address"); "Sign a message with the private key of an address");
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
string strMessage = params[1].get_str(); string strMessage = params[1].get_str();
strMessage.insert(0, "Padding text - ");
CBitcoinAddress addr(strAddress);
uint160 hash160; if (!addr.IsValid())
if(!AddressToHash160(strAddress, hash160))
throw JSONRPCError(-3, "Invalid address"); throw JSONRPCError(-3, "Invalid address");
vector<unsigned char>& vchPubKey = mapPubKeys[hash160];
CKey key; CKey key;
if(!key.SetPubKey(vchPubKey)) if (!pwalletMain->GetKey(addr, key))
throw JSONRPCError(-3, "Public key not found"); throw JSONRPCError(-4, "Private key not available");
strMessage.insert(0, HexStr(vchPubKey.begin(), vchPubKey.end()).c_str());
CDataStream ss(SER_GETHASH);
ss << strMessageMagic;
ss << strMessage;
vector<unsigned char> vchMsg(strMessage.begin(), strMessage.end());
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
if (!CKey::Sign(mapKeys[vchPubKey], Hash(vchMsg.begin(), vchMsg.end()), vchSig)) if (!key.Sign(Hash(ss.begin(), ss.end()), vchSig))
throw JSONRPCError(-3, "Sign failed"); throw JSONRPCError(-5, "Sign failed");
Object obj; CDataStream sres(SER_NETWORK);
obj.push_back(Pair("address", strAddress)); sres << key.GetPubKey(); // public key
obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end()).c_str())); sres << vchSig; // signature;
obj.push_back(Pair("sign", HexStr(vchSig.begin(), vchSig.end()).c_str()));
return obj; return HexStr(sres.begin(), sres.end());
} }
Value verifymessage(const Array& params, bool fHelp) Value verifymessage(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 3) if (fHelp || params.size() != 3)
throw runtime_error( throw runtime_error(
"verifymessage <pubkey> <sign> <message>\n" "verifymessage <bitcoinaddress> <signature> <message>\n"
"Verify a signed message with the public key"); "Verify a signed message");
string strPubKey = params[0].get_str(); string strAddress = params[0].get_str();
string strSign = params[1].get_str(); string strSign = params[1].get_str();
string strMessage = params[2].get_str(); string strMessage = params[2].get_str();
strMessage.insert(0, "Padding text - ");
strMessage.insert(0, strPubKey.c_str());
vector<unsigned char> vchPubKey = ParseHex(strPubKey); CBitcoinAddress addr(strAddress);
vector<unsigned char> vchSig = ParseHex(strSign); if (!addr.IsValid())
vector<unsigned char> vchMsg(strMessage.begin(), strMessage.end()); throw JSONRPCError(-3, "Invalid address");
vector<unsigned char> vchResult = ParseHex(strSign);
CDataStream sres(vchResult);
std::vector<unsigned char> vchPubKey;
sres >> vchPubKey;
std::vector<unsigned char> vchSig;
sres >> vchSig;
CKey key; CKey key;
if(!key.SetPubKey(vchPubKey)) if (!key.SetPubKey(vchPubKey))
throw JSONRPCError(-3, "Invalid pubkey"); throw JSONRPCError(-5, "Invalid public key in signature");
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) if (key.GetAddress() == addr)
throw JSONRPCError(-3, "Verify failed"); {
CDataStream ss(SER_GETHASH);
Object obj; ss << strMessageMagic;
obj.push_back(Pair("address", PubKeyToAddress(vchPubKey))); ss << strMessage;
obj.push_back(Pair("pubkey", strPubKey.c_str())); return key.Verify(Hash(ss.begin(), ss.end()), vchSig);
return obj; }
else
return false;
} }