Merge pull request #2600 from sipa/keyrefactor

Refactor key.cpp/.h
This commit is contained in:
Jeff Garzik 2013-05-30 07:55:25 -07:00
commit e2f42142a0
28 changed files with 655 additions and 609 deletions

View File

@ -144,9 +144,7 @@ bool CAlert::RelayTo(CNode* pnode) const
bool CAlert::CheckSignature() const bool CAlert::CheckSignature() const
{ {
CKey key; CPubKey key(ParseHex(fTestNet ? pszTestKey : pszMainKey));
if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey)))
return error("CAlert::CheckSignature() : SetPubKey failed");
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
return error("CAlert::CheckSignature() : verify signature failed"); return error("CAlert::CheckSignature() : verify signature failed");

View File

@ -176,6 +176,19 @@ private:
{} {}
}; };
//
// Functions for directly locking/unlocking memory objects.
// Intended for non-dynamically allocated structures.
//
template<typename T> void LockObject(const T &t) {
LockedPageManager::instance.LockRange((void*)(&t), sizeof(T));
}
template<typename T> void UnlockObject(const T &t) {
OPENSSL_cleanse((void*)(&t), sizeof(T));
LockedPageManager::instance.UnlockRange((void*)(&t), sizeof(T));
}
// //
// Allocator that locks its contents from being paged // Allocator that locks its contents from being paged
// out of memory and clears its contents before deletion. // out of memory and clears its contents before deletion.

View File

@ -398,21 +398,19 @@ bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const {
class CBitcoinSecret : public CBase58Data class CBitcoinSecret : public CBase58Data
{ {
public: public:
void SetSecret(const CSecret& vchSecret, bool fCompressed) void SetKey(const CKey& vchSecret)
{ {
assert(vchSecret.size() == 32); assert(vchSecret.IsValid());
SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size()); SetData(fTestNet ? 239 : 128, vchSecret.begin(), vchSecret.size());
if (fCompressed) if (vchSecret.IsCompressed())
vchData.push_back(1); vchData.push_back(1);
} }
CSecret GetSecret(bool &fCompressedOut) CKey GetKey()
{ {
CSecret vchSecret; CKey ret;
vchSecret.resize(32); ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1);
memcpy(&vchSecret[0], &vchData[0], 32); return ret;
fCompressedOut = vchData.size() == 33;
return vchSecret;
} }
bool IsValid() const bool IsValid() const
@ -443,9 +441,9 @@ public:
return SetString(strSecret.c_str()); return SetString(strSecret.c_str());
} }
CBitcoinSecret(const CSecret& vchSecret, bool fCompressed) CBitcoinSecret(const CKey& vchSecret)
{ {
SetSecret(vchSecret, fCompressed); SetKey(vchSecret);
} }
CBitcoinSecret() CBitcoinSecret()

View File

@ -100,17 +100,17 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
} }
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext) bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{ {
CCrypter cKeyCrypter; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV)) if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false; return false;
return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext); return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
} }
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext) bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{ {
CCrypter cKeyCrypter; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);

View File

@ -101,7 +101,7 @@ public:
} }
}; };
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext); bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char> &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext); bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
#endif #endif

View File

@ -105,15 +105,22 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
return ss.GetHash(); return ss.GetHash();
} }
inline uint160 Hash160(const std::vector<unsigned char>& vch) template<typename T1>
inline uint160 Hash160(const T1 pbegin, const T1 pend)
{ {
static unsigned char pblank[1];
uint256 hash1; uint256 hash1;
SHA256(&vch[0], vch.size(), (unsigned char*)&hash1); SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
uint160 hash2; uint160 hash2;
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2; return hash2;
} }
inline uint160 Hash160(const std::vector<unsigned char>& vch)
{
return Hash160(vch.begin(), vch.end());
}
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash); unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
#endif #endif

View File

@ -2,13 +2,16 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <map>
#include <openssl/ecdsa.h> #include <openssl/ecdsa.h>
#include <openssl/rand.h>
#include <openssl/obj_mac.h> #include <openssl/obj_mac.h>
#include "key.h" #include "key.h"
// anonymous namespace with local implementation code (OpenSSL interaction)
namespace {
// Generate a private key from just the secret parameter // Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{ {
@ -120,291 +123,273 @@ err:
return ret; return ret;
} }
void CKey::SetCompressedPubKey(bool fCompressed) // RAII Wrapper around OpenSSL's EC_KEY
{ class CECKey {
EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); private:
fCompressedPubKey = true; EC_KEY *pkey;
}
void CKey::Reset() public:
{ CECKey() {
fCompressedPubKey = false; pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (pkey != NULL) assert(pkey != NULL);
}
~CECKey() {
EC_KEY_free(pkey); EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1); }
if (pkey == NULL)
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
fSet = false;
}
CKey::CKey() void GetSecretBytes(unsigned char vch[32]) const {
{ const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
pkey = NULL; assert(bn);
Reset(); int nBytes = BN_num_bytes(bn);
} int n=BN_bn2bin(bn,&vch[32 - nBytes]);
assert(n == nBytes);
memset(vch, 0, 32 - nBytes);
}
CKey::CKey(const CKey& b) void SetSecretBytes(const unsigned char vch[32]) {
{ BIGNUM bn;
pkey = EC_KEY_dup(b.pkey); BN_init(&bn);
if (pkey == NULL) assert(BN_bin2bn(vch, 32, &bn));
throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); assert(EC_KEY_regenerate_key(pkey, &bn));
fSet = b.fSet; BN_clear_free(&bn);
} }
CKey& CKey::operator=(const CKey& b) void GetPrivKey(CPrivKey &privkey) {
{ int nSize = i2d_ECPrivateKey(pkey, NULL);
if (!EC_KEY_copy(pkey, b.pkey)) assert(nSize);
throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); privkey.resize(nSize);
fSet = b.fSet; unsigned char* pbegin = &privkey[0];
return (*this); int nSize2 = i2d_ECPrivateKey(pkey, &pbegin);
} assert(nSize == nSize2);
}
CKey::~CKey() bool SetPrivKey(const CPrivKey &privkey) {
{ const unsigned char* pbegin = &privkey[0];
EC_KEY_free(pkey); if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
} // d2i_ECPrivateKey returns true if parsing succeeds.
// This doesn't necessarily mean the key is valid.
bool CKey::IsNull() const if (EC_KEY_check_key(pkey))
{ return true;
return !fSet;
}
bool CKey::IsCompressed() const
{
return fCompressedPubKey;
}
void CKey::MakeNewKey(bool fCompressed)
{
if (!EC_KEY_generate_key(pkey))
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
if (fCompressed)
SetCompressedPubKey();
fSet = true;
}
bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
{
const unsigned char* pbegin = &vchPrivKey[0];
if (d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
{
// In testing, d2i_ECPrivateKey can return true
// but fill in pkey with a key that fails
// EC_KEY_check_key, so:
if (EC_KEY_check_key(pkey))
{
fSet = true;
return true;
} }
return false;
} }
// If vchPrivKey data is bad d2i_ECPrivateKey() can
// leave pkey in a state where calling EC_KEY_free()
// crashes. To avoid that, set pkey to NULL and
// leak the memory (a leak is better than a crash)
pkey = NULL;
Reset();
return false;
}
bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed) void GetPubKey(CPubKey &pubkey, bool fCompressed) {
{ EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
EC_KEY_free(pkey); int nSize = i2o_ECPublicKey(pkey, NULL);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1); assert(nSize);
if (pkey == NULL) assert(nSize <= 65);
throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); unsigned char c[65];
if (vchSecret.size() != 32) unsigned char *pbegin = c;
throw key_error("CKey::SetSecret() : secret must be 32 bytes"); int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); assert(nSize == nSize2);
if (bn == NULL) pubkey.Set(&c[0], &c[nSize]);
throw key_error("CKey::SetSecret() : BN_bin2bn failed");
if (!EC_KEY_regenerate_key(pkey,bn))
{
BN_clear_free(bn);
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
} }
BN_clear_free(bn);
fSet = true;
if (fCompressed || fCompressedPubKey)
SetCompressedPubKey();
return true;
}
CSecret CKey::GetSecret(bool &fCompressed) const bool SetPubKey(const CPubKey &pubkey) {
{ const unsigned char* pbegin = pubkey.begin();
CSecret vchRet; return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size());
vchRet.resize(32); }
const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
int nBytes = BN_num_bytes(bn);
if (bn == NULL)
throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
if (n != nBytes)
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
fCompressed = fCompressedPubKey;
return vchRet;
}
CPrivKey CKey::GetPrivKey() const bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) {
{ unsigned int nSize = ECDSA_size(pkey);
int nSize = i2d_ECPrivateKey(pkey, NULL); vchSig.resize(nSize); // Make sure it is big enough
if (!nSize) assert(ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey));
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); vchSig.resize(nSize); // Shrink to fit actual size
CPrivKey vchPrivKey(nSize, 0);
unsigned char* pbegin = &vchPrivKey[0];
if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
return vchPrivKey;
}
bool CKey::SetPubKey(const CPubKey& vchPubKey)
{
const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
{
fSet = true;
if (vchPubKey.vchPubKey.size() == 33)
SetCompressedPubKey();
return true; return true;
} }
pkey = NULL;
Reset();
return false;
}
CPubKey CKey::GetPubKey() const bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
{ // -1 = error, 0 = bad sig, 1 = good
int nSize = i2o_ECPublicKey(pkey, NULL); if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
if (!nSize) return false;
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); return true;
std::vector<unsigned char> vchPubKey(nSize, 0); }
unsigned char* pbegin = &vchPubKey[0];
if (i2o_ECPublicKey(pkey, &pbegin) != nSize) bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec) {
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); bool fOk = false;
return CPubKey(vchPubKey); ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
} if (sig==NULL)
return false;
bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig) memset(p64, 0, 64);
{ int nBitsR = BN_num_bits(sig->r);
unsigned int nSize = ECDSA_size(pkey); int nBitsS = BN_num_bits(sig->s);
vchSig.resize(nSize); // Make sure it is big enough if (nBitsR <= 256 && nBitsS <= 256) {
if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)) CPubKey pubkey;
{ GetPubKey(pubkey, true);
vchSig.clear(); for (int i=0; i<4; i++) {
return false; CECKey keyRec;
if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
CPubKey pubkeyRec;
keyRec.GetPubKey(pubkeyRec, true);
if (pubkeyRec == pubkey) {
rec = i;
fOk = true;
break;
}
}
}
assert(fOk);
BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
}
ECDSA_SIG_free(sig);
return fOk;
}
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool Recover(const uint256 &hash, const unsigned char *p64, int rec)
{
if (rec<0 || rec>=3)
return false;
ECDSA_SIG *sig = ECDSA_SIG_new();
BN_bin2bn(&p64[0], 32, sig->r);
BN_bin2bn(&p64[32], 32, sig->s);
bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
ECDSA_SIG_free(sig);
return ret;
}
};
}; // end of anonymous namespace
bool CKey::Check(const unsigned char *vch) {
// Do not convert to OpenSSL's data structures for range-checking keys,
// it's easy enough to do directly.
static const unsigned char vchMax[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
bool fIsZero = true;
for (int i=0; i<32 && fIsZero; i++)
if (vch[i] != 0)
fIsZero = false;
if (fIsZero)
return false;
for (int i=0; i<32; i++) {
if (vch[i] < vchMax[i])
return true;
if (vch[i] > vchMax[i])
return false;
} }
vchSig.resize(nSize); // Shrink to fit actual size
return true; return true;
} }
// create a compact signature (65 bytes), which allows reconstructing the used public key void CKey::MakeNewKey(bool fCompressedIn) {
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values. do {
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, RAND_bytes(vch, sizeof(vch));
// 0x1D = second key with even y, 0x1E = second key with odd y } while (!Check(vch));
bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig) fValid = true;
{ fCompressed = fCompressedIn;
bool fOk = false;
ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
if (sig==NULL)
return false;
vchSig.clear();
vchSig.resize(65,0);
int nBitsR = BN_num_bits(sig->r);
int nBitsS = BN_num_bits(sig->s);
if (nBitsR <= 256 && nBitsS <= 256)
{
int nRecId = -1;
for (int i=0; i<4; i++)
{
CKey keyRec;
keyRec.fSet = true;
if (fCompressedPubKey)
keyRec.SetCompressedPubKey();
if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
if (keyRec.GetPubKey() == this->GetPubKey())
{
nRecId = i;
break;
}
}
if (nRecId == -1)
{
ECDSA_SIG_free(sig);
throw key_error("CKey::SignCompact() : unable to construct recoverable key");
}
vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
fOk = true;
}
ECDSA_SIG_free(sig);
return fOk;
} }
// reconstruct public key from a compact signature bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
// This is only slightly more CPU intensive than just verifying it. CECKey key;
// If this function succeeds, the recovered public key is guaranteed to be valid if (!key.SetPrivKey(privkey))
// (the signature is a valid signature of the given data for that key) return false;
bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig) key.GetSecretBytes(vch);
{ fCompressed = fCompressedIn;
fValid = true;
return true;
}
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CECKey key;
key.SetSecretBytes(vch);
CPrivKey privkey;
key.GetPrivKey(privkey);
return privkey;
}
CPubKey CKey::GetPubKey() const {
assert(fValid);
CECKey key;
key.SetSecretBytes(vch);
CPubKey pubkey;
key.GetPubKey(pubkey, fCompressed);
return pubkey;
}
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
CECKey key;
key.SetSecretBytes(vch);
return key.Sign(hash, vchSig);
}
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
CECKey key;
key.SetSecretBytes(vch);
vchSig.resize(65);
int rec = -1;
if (!key.SignCompact(hash, &vchSig[1], rec))
return false;
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
return true;
}
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;
CECKey key;
if (!key.SetPubKey(*this))
return false;
if (!key.Verify(hash, vchSig))
return false;
return true;
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
if (vchSig.size() != 65) if (vchSig.size() != 65)
return false; return false;
int nV = vchSig[0]; CECKey key;
if (nV<27 || nV>=35) if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
return false; return false;
ECDSA_SIG *sig = ECDSA_SIG_new(); key.GetPubKey(*this, (vchSig[0] - 27) & 4);
BN_bin2bn(&vchSig[1],32,sig->r);
BN_bin2bn(&vchSig[33],32,sig->s);
EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (nV >= 31)
{
SetCompressedPubKey();
nV -= 4;
}
if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
{
fSet = true;
ECDSA_SIG_free(sig);
return true;
}
ECDSA_SIG_free(sig);
return false;
}
bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
{
// -1 = error, 0 = bad sig, 1 = good
if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
return false;
return true; return true;
} }
bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig) bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
{ if (!IsValid())
CKey key;
if (!key.SetCompactSignature(hash, vchSig))
return false; return false;
if (GetPubKey() != key.GetPubKey()) if (vchSig.size() != 65)
return false;
CECKey key;
if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
return false;
CPubKey pubkeyRec;
key.GetPubKey(pubkeyRec, IsCompressed());
if (*this != pubkeyRec)
return false; return false;
return true; return true;
} }
bool CKey::IsValid() bool CPubKey::IsFullyValid() const {
{ if (!IsValid())
if (!fSet)
return false; return false;
CECKey key;
if (!EC_KEY_check_key(pkey)) if (!key.SetPubKey(*this))
return false; return false;
return true;
bool fCompr; }
CSecret secret = GetSecret(fCompr);
CKey key2; bool CPubKey::Decompress() {
key2.SetSecret(secret, fCompr); if (!IsValid())
return GetPubKey() == key2.GetPubKey(); return false;
CECKey key;
if (!key.SetPubKey(*this))
return false;
key.GetPubKey(*this, false);
return true;
} }

255
src/key.h
View File

@ -1,11 +1,10 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers // Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEY_H #ifndef BITCOIN_KEY_H
#define BITCOIN_KEY_H #define BITCOIN_KEY_H
#include <stdexcept>
#include <vector> #include <vector>
#include "allocators.h" #include "allocators.h"
@ -13,23 +12,6 @@
#include "uint256.h" #include "uint256.h"
#include "hash.h" #include "hash.h"
#include <openssl/ec.h> // for EC_KEY definition
// secp160k1
// const unsigned int PRIVATE_KEY_SIZE = 192;
// const unsigned int PUBLIC_KEY_SIZE = 41;
// const unsigned int SIGNATURE_SIZE = 48;
//
// secp192k1
// const unsigned int PRIVATE_KEY_SIZE = 222;
// const unsigned int PUBLIC_KEY_SIZE = 49;
// const unsigned int SIGNATURE_SIZE = 57;
//
// secp224k1
// const unsigned int PRIVATE_KEY_SIZE = 250;
// const unsigned int PUBLIC_KEY_SIZE = 57;
// const unsigned int SIGNATURE_SIZE = 66;
//
// secp256k1: // secp256k1:
// const unsigned int PRIVATE_KEY_SIZE = 279; // const unsigned int PRIVATE_KEY_SIZE = 279;
// const unsigned int PUBLIC_KEY_SIZE = 65; // const unsigned int PUBLIC_KEY_SIZE = 65;
@ -38,12 +20,6 @@
// see www.keylength.com // see www.keylength.com
// script supports up to 75 for single byte push // script supports up to 75 for single byte push
class key_error : public std::runtime_error
{
public:
explicit key_error(const std::string& str) : std::runtime_error(str) {}
};
/** A reference to a CKey: the Hash160 of its serialized public key */ /** A reference to a CKey: the Hash160 of its serialized public key */
class CKeyID : public uint160 class CKeyID : public uint160
{ {
@ -63,99 +39,218 @@ public:
/** An encapsulated public key. */ /** An encapsulated public key. */
class CPubKey { class CPubKey {
private: private:
std::vector<unsigned char> vchPubKey; // Just store the serialized data.
friend class CKey; // Its length can very cheaply be computed from the first byte.
unsigned char vch[65];
// Compute the length of a pubkey with a given first byte.
unsigned int static GetLen(unsigned char chHeader) {
if (chHeader == 2 || chHeader == 3)
return 33;
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
return 65;
return 0;
}
// Set this key data to be invalid
void Invalidate() {
vch[0] = 0xFF;
}
public: public:
CPubKey() { } // Construct an invalid public key.
CPubKey(const std::vector<unsigned char> &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { } CPubKey() {
friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; } Invalidate();
friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; } }
friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; }
IMPLEMENT_SERIALIZE( // Initialize a public key using begin/end iterators to byte data.
READWRITE(vchPubKey); template<typename T>
) void Set(const T pbegin, const T pend) {
int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
if (len && len == (pend-pbegin))
memcpy(vch, (unsigned char*)&pbegin[0], len);
else
Invalidate();
}
// Construct a public key using begin/end iterators to byte data.
template<typename T>
CPubKey(const T pbegin, const T pend) {
Set(pbegin, pend);
}
// Construct a public key from a byte vector.
CPubKey(const std::vector<unsigned char> &vch) {
Set(vch.begin(), vch.end());
}
// Simple read-only vector-like interface to the pubkey data.
unsigned int size() const { return GetLen(vch[0]); }
const unsigned char *begin() const { return vch; }
const unsigned char *end() const { return vch+size(); }
const unsigned char &operator[](unsigned int pos) const { return vch[pos]; }
// Comparator implementation.
friend bool operator==(const CPubKey &a, const CPubKey &b) {
return a.vch[0] == b.vch[0] &&
memcmp(a.vch, b.vch, a.size()) == 0;
}
friend bool operator!=(const CPubKey &a, const CPubKey &b) {
return !(a == b);
}
friend bool operator<(const CPubKey &a, const CPubKey &b) {
return a.vch[0] < b.vch[0] ||
(a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);
}
// Implement serialization, as if this was a byte vector.
unsigned int GetSerializeSize(int nType, int nVersion) const {
return size() + 1;
}
template<typename Stream> void Serialize(Stream &s, int nType, int nVersion) const {
unsigned int len = size();
::WriteCompactSize(s, len);
s.write((char*)vch, len);
}
template<typename Stream> void Unserialize(Stream &s, int nType, int nVersion) {
unsigned int len = ::ReadCompactSize(s);
if (len <= 65) {
s.read((char*)vch, len);
} else {
// invalid pubkey, skip available data
char dummy;
while (len--)
s.read(&dummy, 1);
Invalidate();
}
}
// Get the KeyID of this public key (hash of its serialization)
CKeyID GetID() const { CKeyID GetID() const {
return CKeyID(Hash160(vchPubKey)); return CKeyID(Hash160(vch, vch+size()));
} }
// Get the 256-bit hash of this public key.
uint256 GetHash() const { uint256 GetHash() const {
return Hash(vchPubKey.begin(), vchPubKey.end()); return Hash(vch, vch+size());
} }
// just check syntactic correctness.
bool IsValid() const { bool IsValid() const {
return vchPubKey.size() == 33 || vchPubKey.size() == 65; return size() > 0;
} }
// fully validate whether this is a valid public key (more expensive than IsValid())
bool IsFullyValid() const;
// Check whether this is a compressed public key.
bool IsCompressed() const { bool IsCompressed() const {
return vchPubKey.size() == 33; return size() == 33;
} }
std::vector<unsigned char> Raw() const { // Verify a DER signature (~72 bytes).
return vchPubKey; // If this public key is not fully valid, the return value will be false.
} bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
// Verify a compact signature (~65 bytes).
// See CKey::SignCompact.
bool VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
// Recover a public key from a compact signature.
bool RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig);
// Turn this public key into an uncompressed public key.
bool Decompress();
}; };
// secure_allocator is defined in allocators.h // secure_allocator is defined in allocators.h
// CPrivKey is a serialized private key, with all parameters included (279 bytes) // CPrivKey is a serialized private key, with all parameters included (279 bytes)
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey; typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
// CSecret is a serialization of just the secret parameter (32 bytes)
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */ /** An encapsulated private key. */
class CKey class CKey {
{ private:
protected: // Whether this private key is valid. We check for correctness when modifying the key
EC_KEY* pkey; // data, so fValid should always correspond to the actual state.
bool fSet; bool fValid;
bool fCompressedPubKey;
// Whether the public key corresponding to this private key is (to be) compressed.
bool fCompressed;
// The actual byte data
unsigned char vch[32];
// Check whether the 32-byte array pointed to be vch is valid keydata.
bool static Check(const unsigned char *vch);
public: public:
void SetCompressedPubKey(bool fCompressed = true);
void Reset(); // Construct an invalid private key.
CKey() : fValid(false) {
LockObject(vch);
}
CKey(); // Copy constructor. This is necessary because of memlocking.
CKey(const CKey& b); CKey(const CKey &secret) : fValid(secret.fValid), fCompressed(secret.fCompressed) {
LockObject(vch);
memcpy(vch, secret.vch, sizeof(vch));
}
CKey& operator=(const CKey& b); // Destructor (again necessary because of memlocking).
~CKey() {
UnlockObject(vch);
}
~CKey(); // Initialize using begin and end iterators to byte data.
template<typename T>
void Set(const T pbegin, const T pend, bool fCompressedIn) {
if (pend - pbegin != 32) {
fValid = false;
return;
}
if (Check(&pbegin[0])) {
memcpy(vch, (unsigned char*)&pbegin[0], 32);
fValid = true;
fCompressed = fCompressedIn;
} else {
fValid = false;
}
}
bool IsNull() const; // Simple read-only vector-like interface.
bool IsCompressed() const; unsigned int size() const { return (fValid ? 32 : 0); }
const unsigned char *begin() const { return vch; }
const unsigned char *end() const { return vch + size(); }
// Check whether this private key is valid.
bool IsValid() const { return fValid; }
// Check whether the public key corresponding to this private key is (to be) compressed.
bool IsCompressed() const { return fCompressed; }
// Initialize from a CPrivKey (serialized OpenSSL private key data).
bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompressed);
// Generate a new private key using a cryptographic PRNG.
void MakeNewKey(bool fCompressed); void MakeNewKey(bool fCompressed);
bool SetPrivKey(const CPrivKey& vchPrivKey);
bool SetSecret(const CSecret& vchSecret, bool fCompressed = false); // Convert the private key to a CPrivKey (serialized OpenSSL private key data).
CSecret GetSecret(bool &fCompressed) const; // This is expensive.
CPrivKey GetPrivKey() const; CPrivKey GetPrivKey() const;
bool SetPubKey(const CPubKey& vchPubKey);
// Compute the public key from a private key.
// This is expensive.
CPubKey GetPubKey() const; CPubKey GetPubKey() const;
bool Sign(uint256 hash, std::vector<unsigned char>& vchSig); // Create a DER-serialized signature.
bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
// create a compact signature (65 bytes), which allows reconstructing the used public key // Create a compact signature (65 bytes), which allows reconstructing the used public key.
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values. // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
// 0x1D = second key with even y, 0x1E = second key with odd y // 0x1D = second key with even y, 0x1E = second key with odd y,
bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig); // add 0x04 for compressed keys.
bool SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig);
bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig);
// Verify a compact signature
bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig);
bool IsValid();
}; };
#endif #endif

View File

@ -15,61 +15,50 @@ bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
return true; return true;
} }
bool CBasicKeyStore::AddKey(const CKey& key) bool CKeyStore::AddKey(const CKey &key) {
return AddKeyPubKey(key, key.GetPubKey());
}
bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{ {
bool fCompressed = false; LOCK(cs_KeyStore);
CSecret secret = key.GetSecret(fCompressed); mapKeys[pubkey.GetID()] = key;
{
LOCK(cs_KeyStore);
mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed);
}
return true; return true;
} }
bool CBasicKeyStore::AddCScript(const CScript& redeemScript) bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{ {
{ LOCK(cs_KeyStore);
LOCK(cs_KeyStore); mapScripts[redeemScript.GetID()] = redeemScript;
mapScripts[redeemScript.GetID()] = redeemScript;
}
return true; return true;
} }
bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
{ {
bool result; LOCK(cs_KeyStore);
{ return mapScripts.count(hash) > 0;
LOCK(cs_KeyStore);
result = (mapScripts.count(hash) > 0);
}
return result;
} }
bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
{ {
LOCK(cs_KeyStore);
ScriptMap::const_iterator mi = mapScripts.find(hash);
if (mi != mapScripts.end())
{ {
LOCK(cs_KeyStore); redeemScriptOut = (*mi).second;
ScriptMap::const_iterator mi = mapScripts.find(hash); return true;
if (mi != mapScripts.end())
{
redeemScriptOut = (*mi).second;
return true;
}
} }
return false; return false;
} }
bool CCryptoKeyStore::SetCrypted() bool CCryptoKeyStore::SetCrypted()
{ {
{ LOCK(cs_KeyStore);
LOCK(cs_KeyStore); if (fUseCrypto)
if (fUseCrypto) return true;
return true; if (!mapKeys.empty())
if (!mapKeys.empty()) return false;
return false; fUseCrypto = true;
fUseCrypto = true;
}
return true; return true;
} }
@ -99,14 +88,13 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{ {
const CPubKey &vchPubKey = (*mi).second.first; const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second; const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CSecret vchSecret; CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false; return false;
if (vchSecret.size() != 32) if (vchSecret.size() != 32)
return false; return false;
CKey key; CKey key;
key.SetPubKey(vchPubKey); key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
key.SetSecret(vchSecret);
if (key.GetPubKey() == vchPubKey) if (key.GetPubKey() == vchPubKey)
break; break;
return false; return false;
@ -117,23 +105,22 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
return true; return true;
} }
bool CCryptoKeyStore::AddKey(const CKey& key) bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
if (!IsCrypted()) if (!IsCrypted())
return CBasicKeyStore::AddKey(key); return CBasicKeyStore::AddKeyPubKey(key, pubkey);
if (IsLocked()) if (IsLocked())
return false; return false;
std::vector<unsigned char> vchCryptedSecret; std::vector<unsigned char> vchCryptedSecret;
CPubKey vchPubKey = key.GetPubKey(); CKeyingMaterial vchSecret(key.begin(), key.end());
bool fCompressed; if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
return false; return false;
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) if (!AddCryptedKey(pubkey, vchCryptedSecret))
return false; return false;
} }
return true; return true;
@ -164,13 +151,12 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{ {
const CPubKey &vchPubKey = (*mi).second.first; const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second; const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CSecret vchSecret; CKeyingMaterial vchSecret;
if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false; return false;
if (vchSecret.size() != 32) if (vchSecret.size() != 32)
return false; return false;
keyOut.SetPubKey(vchPubKey); keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
keyOut.SetSecret(vchSecret);
return true; return true;
} }
} }
@ -204,13 +190,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
fUseCrypto = true; fUseCrypto = true;
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys) BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
{ {
CKey key; const CKey &key = mKey.second;
if (!key.SetSecret(mKey.second.first, mKey.second.second)) CPubKey vchPubKey = key.GetPubKey();
return false; CKeyingMaterial vchSecret(key.begin(), key.end());
const CPubKey vchPubKey = key.GetPubKey();
std::vector<unsigned char> vchCryptedSecret; std::vector<unsigned char> vchCryptedSecret;
bool fCompressed; if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
return false; return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false; return false;

View File

@ -21,7 +21,8 @@ public:
virtual ~CKeyStore() {} virtual ~CKeyStore() {}
// Add a key to the store. // Add a key to the store.
virtual bool AddKey(const CKey& key) =0; virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
virtual bool AddKey(const CKey &key);
// Check whether a key corresponding to a given address is present in the store. // Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CKeyID &address) const =0; virtual bool HaveKey(const CKeyID &address) const =0;
@ -33,18 +34,9 @@ public:
virtual bool AddCScript(const CScript& redeemScript) =0; virtual bool AddCScript(const CScript& redeemScript) =0;
virtual bool HaveCScript(const CScriptID &hash) const =0; virtual bool HaveCScript(const CScriptID &hash) const =0;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0; virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const
{
CKey key;
if (!GetKey(address, key))
return false;
vchSecret = key.GetSecret(fCompressed);
return true;
}
}; };
typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap; typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap; typedef std::map<CScriptID, CScript > ScriptMap;
/** Basic key store, that keeps keys in an address->secret map */ /** Basic key store, that keeps keys in an address->secret map */
@ -55,7 +47,7 @@ protected:
ScriptMap mapScripts; ScriptMap mapScripts;
public: public:
bool AddKey(const CKey& key); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
bool HaveKey(const CKeyID &address) const bool HaveKey(const CKeyID &address) const
{ {
bool result; bool result;
@ -85,8 +77,7 @@ public:
KeyMap::const_iterator mi = mapKeys.find(address); KeyMap::const_iterator mi = mapKeys.find(address);
if (mi != mapKeys.end()) if (mi != mapKeys.end())
{ {
keyOut.Reset(); keyOut = mi->second;
keyOut.SetSecret((*mi).second.first, (*mi).second.second);
return true; return true;
} }
} }
@ -146,7 +137,7 @@ public:
bool Lock(); bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKey(const CKey& key); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
bool HaveKey(const CKeyID &address) const bool HaveKey(const CKeyID &address) const
{ {
{ {

View File

@ -218,8 +218,8 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
ss << strMessageMagic; ss << strMessageMagic;
ss << ui->messageIn_VM->document()->toPlainText().toStdString(); ss << ui->messageIn_VM->document()->toPlainText().toStdString();
CKey key; CPubKey pubkey;
if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig))
{ {
ui->signatureIn_VM->setValid(false); ui->signatureIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
@ -227,7 +227,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return; return;
} }
if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr)) if (!(CBitcoinAddress(pubkey.GetID()) == addr))
{ {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")); ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));

View File

@ -54,20 +54,18 @@ Value importprivkey(const Array& params, bool fHelp)
if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
CKey key; CKey key = vchSecret.GetKey();
bool fCompressed; CPubKey pubkey = key.GetPubKey();
CSecret secret = vchSecret.GetSecret(fCompressed); CKeyID vchAddress = pubkey.GetID();
key.SetSecret(secret, fCompressed);
CKeyID vchAddress = key.GetPubKey().GetID();
{ {
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->MarkDirty(); pwalletMain->MarkDirty();
pwalletMain->SetAddressBookName(vchAddress, strLabel); pwalletMain->SetAddressBookName(vchAddress, strLabel);
if (!pwalletMain->AddKey(key)) if (!pwalletMain->AddKeyPubKey(key, pubkey))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
if (fRescan) { if (fRescan) {
pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
pwalletMain->ReacceptWalletTransactions(); pwalletMain->ReacceptWalletTransactions();
@ -91,9 +89,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
CKeyID keyID; CKeyID keyID;
if (!address.GetKeyID(keyID)) if (!address.GetKeyID(keyID))
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
CSecret vchSecret; CKey vchSecret;
bool fCompressed; if (!pwalletMain->GetKey(keyID, vchSecret))
if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
return CBitcoinSecret(vchSecret, fCompressed).ToString(); return CBitcoinSecret(vchSecret).ToString();
} }

View File

@ -407,10 +407,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGood = vchSecret.SetString(k.get_str()); bool fGood = vchSecret.SetString(k.get_str());
if (!fGood) if (!fGood)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
CKey key; CKey key = vchSecret.GetKey();
bool fCompressed;
CSecret secret = vchSecret.GetSecret(fCompressed);
key.SetSecret(secret, fCompressed);
tempKeystore.AddKey(key); tempKeystore.AddKey(key);
} }
} }

View File

@ -374,11 +374,11 @@ Value verifymessage(const Array& params, bool fHelp)
ss << strMessageMagic; ss << strMessageMagic;
ss << strMessage; ss << strMessage;
CKey key; CPubKey pubkey;
if (!key.SetCompactSignature(ss.GetHash(), vchSig)) if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false; return false;
return (key.GetPubKey().GetID() == keyID); return (pubkey.GetID() == keyID);
} }
@ -719,7 +719,7 @@ static CScript _createmultisig(const Array& params)
throw runtime_error( throw runtime_error(
strprintf("not enough keys supplied " strprintf("not enough keys supplied "
"(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
std::vector<CKey> pubkeys; std::vector<CPubKey> pubkeys;
pubkeys.resize(keys.size()); pubkeys.resize(keys.size());
for (unsigned int i = 0; i < keys.size(); i++) for (unsigned int i = 0; i < keys.size(); i++)
{ {
@ -737,16 +737,18 @@ static CScript _createmultisig(const Array& params)
if (!pwalletMain->GetPubKey(keyID, vchPubKey)) if (!pwalletMain->GetPubKey(keyID, vchPubKey))
throw runtime_error( throw runtime_error(
strprintf("no full public key for address %s",ks.c_str())); strprintf("no full public key for address %s",ks.c_str()));
if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) if (!vchPubKey.IsFullyValid())
throw runtime_error(" Invalid public key: "+ks); throw runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
} }
// Case 2: hex public key // Case 2: hex public key
else if (IsHex(ks)) else if (IsHex(ks))
{ {
CPubKey vchPubKey(ParseHex(ks)); CPubKey vchPubKey(ParseHex(ks));
if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) if (!vchPubKey.IsFullyValid())
throw runtime_error(" Invalid public key: "+ks); throw runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
} }
else else
{ {
@ -1457,7 +1459,7 @@ public:
CPubKey vchPubKey; CPubKey vchPubKey;
pwalletMain->GetPubKey(keyID, vchPubKey); pwalletMain->GetPubKey(keyID, vchPubKey);
obj.push_back(Pair("isscript", false)); obj.push_back(Pair("isscript", false));
obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw()))); obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
return obj; return obj;
} }

View File

@ -16,7 +16,7 @@ using namespace boost;
#include "sync.h" #include "sync.h"
#include "util.h" #include "util.h"
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
@ -1033,13 +1033,13 @@ class CSignatureCache
{ {
private: private:
// sigdata_type is (signature hash, signature, public key): // sigdata_type is (signature hash, signature, public key):
typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type; typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
std::set< sigdata_type> setValid; std::set< sigdata_type> setValid;
boost::shared_mutex cs_sigcache; boost::shared_mutex cs_sigcache;
public: public:
bool bool
Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey) Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
{ {
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
@ -1050,7 +1050,7 @@ public:
return false; return false;
} }
void Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey) void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
{ {
// DoS prevention: limit cache size to less than 10MB // DoS prevention: limit cache size to less than 10MB
// (~200 bytes per cache entry times 50,000 entries) // (~200 bytes per cache entry times 50,000 entries)
@ -1081,11 +1081,15 @@ public:
} }
}; };
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode,
const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) const CTransaction& txTo, unsigned int nIn, int nHashType, int flags)
{ {
static CSignatureCache signatureCache; static CSignatureCache signatureCache;
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;
// Hash type is one byte tacked on to the end of the signature // Hash type is one byte tacked on to the end of the signature
if (vchSig.empty()) if (vchSig.empty())
return false; return false;
@ -1097,18 +1101,14 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
if (signatureCache.Get(sighash, vchSig, vchPubKey)) if (signatureCache.Get(sighash, vchSig, pubkey))
return true; return true;
CKey key; if (!pubkey.Verify(sighash, vchSig))
if (!key.SetPubKey(vchPubKey))
return false;
if (!key.Verify(sighash, vchSig))
return false; return false;
if (!(flags & SCRIPT_VERIFY_NOCACHE)) if (!(flags & SCRIPT_VERIFY_NOCACHE))
signatureCache.Set(sighash, vchSig, vchPubKey); signatureCache.Set(sighash, vchSig, pubkey);
return true; return true;
} }
@ -1770,13 +1770,13 @@ void CScript::SetDestination(const CTxDestination& dest)
boost::apply_visitor(CScriptVisitor(this), dest); boost::apply_visitor(CScriptVisitor(this), dest);
} }
void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys) void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
{ {
this->clear(); this->clear();
*this << EncodeOP_N(nRequired); *this << EncodeOP_N(nRequired);
BOOST_FOREACH(const CKey& key, keys) BOOST_FOREACH(const CPubKey& key, keys)
*this << key.GetPubKey(); *this << key;
*this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
} }
@ -1801,20 +1801,17 @@ bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
return false; return false;
} }
bool CScriptCompressor::IsToPubKey(std::vector<unsigned char> &pubkey) const bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
{ {
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
&& (script[1] == 0x02 || script[1] == 0x03)) { && (script[1] == 0x02 || script[1] == 0x03)) {
pubkey.resize(33); pubkey.Set(&script[1], &script[34]);
memcpy(&pubkey[0], &script[1], 33);
return true; return true;
} }
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
&& script[1] == 0x04) { && script[1] == 0x04) {
pubkey.resize(65); pubkey.Set(&script[1], &script[66]);
memcpy(&pubkey[0], &script[1], 65); return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
CKey key;
return (key.SetPubKey(CPubKey(pubkey))); // SetPubKey fails if this is not a valid public key, a case that would not be compressible
} }
return false; return false;
} }
@ -1835,7 +1832,7 @@ bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
memcpy(&out[1], &scriptID, 20); memcpy(&out[1], &scriptID, 20);
return true; return true;
} }
std::vector<unsigned char> pubkey; CPubKey pubkey;
if (IsToPubKey(pubkey)) { if (IsToPubKey(pubkey)) {
out.resize(33); out.resize(33);
memcpy(&out[1], &pubkey[1], 32); memcpy(&out[1], &pubkey[1], 32);
@ -1888,17 +1885,16 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
return true; return true;
case 0x04: case 0x04:
case 0x05: case 0x05:
std::vector<unsigned char> vch(33, 0x00); unsigned char vch[33] = {};
vch[0] = nSize - 2; vch[0] = nSize - 2;
memcpy(&vch[1], &in[0], 32); memcpy(&vch[1], &in[0], 32);
CKey key; CPubKey pubkey(&vch[0], &vch[33]);
if (!key.SetPubKey(CPubKey(vch))) if (!pubkey.Decompress())
return false; return false;
key.SetCompressedPubKey(false); // Decompress public key assert(pubkey.size() == 65);
CPubKey pubkey = key.GetPubKey();
script.resize(67); script.resize(67);
script[0] = 65; script[0] = 65;
memcpy(&script[1], &pubkey.Raw()[0], 65); memcpy(&script[1], pubkey.begin(), 65);
script[66] = OP_CHECKSIG; script[66] = OP_CHECKSIG;
return true; return true;
} }

View File

@ -348,8 +348,10 @@ public:
CScript& operator<<(const CPubKey& key) CScript& operator<<(const CPubKey& key)
{ {
std::vector<unsigned char> vchKey = key.Raw(); assert(key.size() < OP_PUSHDATA1);
return (*this) << vchKey; insert(end(), (unsigned char)key.size());
insert(end(), key.begin(), key.end());
return *this;
} }
CScript& operator<<(const CBigNum& b) CScript& operator<<(const CBigNum& b)
@ -548,7 +550,7 @@ public:
void SetDestination(const CTxDestination& address); void SetDestination(const CTxDestination& address);
void SetMultisig(int nRequired, const std::vector<CKey>& keys); void SetMultisig(int nRequired, const std::vector<CPubKey>& keys);
void PrintHex() const void PrintHex() const
@ -619,7 +621,7 @@ protected:
// form). // form).
bool IsToKeyID(CKeyID &hash) const; bool IsToKeyID(CKeyID &hash) const;
bool IsToScriptID(CScriptID &hash) const; bool IsToScriptID(CScriptID &hash) const;
bool IsToPubKey(std::vector<unsigned char> &pubkey) const; bool IsToPubKey(CPubKey &pubkey) const;
bool Compress(std::vector<unsigned char> &out) const; bool Compress(std::vector<unsigned char> &out) const;
unsigned int GetSpecialSize(unsigned int nSize) const; unsigned int GetSpecialSize(unsigned int nSize) const;

View File

@ -133,9 +133,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
// Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not! // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
bool fCompressedOut = false; CKey privkey = secret.GetKey();
CSecret privkey = secret.GetSecret(fCompressedOut); BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
BOOST_CHECK_MESSAGE(fCompressedOut == isCompressed, "compressed mismatch:" + strTest);
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
// Private key must be invalid public key // Private key must be invalid public key
@ -187,8 +186,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
if(isPrivkey) if(isPrivkey)
{ {
bool isCompressed = find_value(metadata, "isCompressed").get_bool(); bool isCompressed = find_value(metadata, "isCompressed").get_bool();
CKey key;
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
assert(key.IsValid());
CBitcoinSecret secret; CBitcoinSecret secret;
secret.SetSecret(CSecret(exp_payload.begin(), exp_payload.end()), isCompressed); secret.SetKey(key);
BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest); BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
} }
else else

View File

@ -73,14 +73,13 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
CBitcoinSecret vchSecret; CBitcoinSecret vchSecret;
BOOST_CHECK(vchSecret.SetString(strSecret)); BOOST_CHECK(vchSecret.SetString(strSecret));
CKey key; CKey key = vchSecret.GetKey();
bool fCompressed; CPubKey pubkey = key.GetPubKey();
CSecret secret = vchSecret.GetSecret(fCompressed); vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
key.SetSecret(secret, fCompressed);
CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL);
filter.insert(key.GetPubKey().Raw()); filter.insert(vchPubKey);
uint160 hash = key.GetPubKey().GetID(); uint160 hash = pubkey.GetID();
filter.insert(vector<unsigned char>(hash.begin(), hash.end())); filter.insert(vector<unsigned char>(hash.begin(), hash.end()));
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);

View File

@ -26,8 +26,8 @@ static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
#ifdef KEY_TESTS_DUMPINFO #ifdef KEY_TESTS_DUMPINFO
void dumpKeyInfo(uint256 privkey) void dumpKeyInfo(uint256 privkey)
{ {
CSecret secret; CKey key;
secret.resize(32); key.resize(32);
memcpy(&secret[0], &privkey, 32); memcpy(&secret[0], &privkey, 32);
vector<unsigned char> sec; vector<unsigned char> sec;
sec.resize(32); sec.resize(32);
@ -62,29 +62,24 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK( bsecret2C.SetString(strSecret2C)); BOOST_CHECK( bsecret2C.SetString(strSecret2C));
BOOST_CHECK(!baddress1.SetString(strAddressBad)); BOOST_CHECK(!baddress1.SetString(strAddressBad));
bool fCompressed; CKey key1 = bsecret1.GetKey();
CSecret secret1 = bsecret1.GetSecret (fCompressed); BOOST_CHECK(key1.IsCompressed() == false);
BOOST_CHECK(fCompressed == false); CKey key2 = bsecret2.GetKey();
CSecret secret2 = bsecret2.GetSecret (fCompressed); BOOST_CHECK(key2.IsCompressed() == false);
BOOST_CHECK(fCompressed == false); CKey key1C = bsecret1C.GetKey();
CSecret secret1C = bsecret1C.GetSecret(fCompressed); BOOST_CHECK(key1C.IsCompressed() == true);
BOOST_CHECK(fCompressed == true); CKey key2C = bsecret2C.GetKey();
CSecret secret2C = bsecret2C.GetSecret(fCompressed); BOOST_CHECK(key1C.IsCompressed() == true);
BOOST_CHECK(fCompressed == true);
BOOST_CHECK(secret1 == secret1C); CPubKey pubkey1 = key1. GetPubKey();
BOOST_CHECK(secret2 == secret2C); CPubKey pubkey2 = key2. GetPubKey();
CPubKey pubkey1C = key1C.GetPubKey();
CPubKey pubkey2C = key2C.GetPubKey();
CKey key1, key2, key1C, key2C; BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
key1.SetSecret(secret1, false); BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
key2.SetSecret(secret2, false); BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
key1C.SetSecret(secret1, true); BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
key2C.SetSecret(secret2, true);
BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID()));
BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID()));
BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID()));
BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID()));
for (int n=0; n<16; n++) for (int n=0; n<16; n++)
{ {
@ -100,25 +95,25 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(key1C.Sign(hashMsg, sign1C)); BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
BOOST_CHECK(key2C.Sign(hashMsg, sign2C)); BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
BOOST_CHECK( key1.Verify(hashMsg, sign1)); BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));
BOOST_CHECK(!key1.Verify(hashMsg, sign2)); BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
BOOST_CHECK( key1.Verify(hashMsg, sign1C)); BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
BOOST_CHECK(!key1.Verify(hashMsg, sign2C)); BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
BOOST_CHECK(!key2.Verify(hashMsg, sign1)); BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
BOOST_CHECK( key2.Verify(hashMsg, sign2)); BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
BOOST_CHECK(!key2.Verify(hashMsg, sign1C)); BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
BOOST_CHECK( key2.Verify(hashMsg, sign2C)); BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
BOOST_CHECK( key1C.Verify(hashMsg, sign1)); BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
BOOST_CHECK(!key1C.Verify(hashMsg, sign2)); BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
BOOST_CHECK( key1C.Verify(hashMsg, sign1C)); BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
BOOST_CHECK(!key1C.Verify(hashMsg, sign2C)); BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
BOOST_CHECK(!key2C.Verify(hashMsg, sign1)); BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
BOOST_CHECK( key2C.Verify(hashMsg, sign2)); BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
BOOST_CHECK(!key2C.Verify(hashMsg, sign1C)); BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
BOOST_CHECK( key2C.Verify(hashMsg, sign2C)); BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));
// compact signatures (with key recovery) // compact signatures (with key recovery)
@ -129,18 +124,17 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C)); BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C)); BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
CKey rkey1, rkey2, rkey1C, rkey2C; CPubKey rkey1, rkey2, rkey1C, rkey2C;
BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1)); BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2)); BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C)); BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C)); BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
BOOST_CHECK(rkey1 == pubkey1);
BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey()); BOOST_CHECK(rkey2 == pubkey2);
BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey()); BOOST_CHECK(rkey1C == pubkey1C);
BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey()); BOOST_CHECK(rkey2C == pubkey2C);
BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey());
} }
} }

View File

@ -30,7 +30,7 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
CScript result; CScript result;
result << OP_0; // CHECKMULTISIG bug workaround result << OP_0; // CHECKMULTISIG bug workaround
BOOST_FOREACH(CKey key, keys) BOOST_FOREACH(const CKey &key, keys)
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig)); BOOST_CHECK(key.Sign(hash, vchSig));

View File

@ -145,19 +145,19 @@ BOOST_AUTO_TEST_CASE(set)
// Test the CScript::Set* methods // Test the CScript::Set* methods
CBasicKeyStore keystore; CBasicKeyStore keystore;
CKey key[4]; CKey key[4];
std::vector<CKey> keys; std::vector<CPubKey> keys;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
key[i].MakeNewKey(true); key[i].MakeNewKey(true);
keystore.AddKey(key[i]); keystore.AddKey(key[i]);
keys.push_back(key[i]); keys.push_back(key[i].GetPubKey());
} }
CScript inner[4]; CScript inner[4];
inner[0].SetDestination(key[0].GetPubKey().GetID()); inner[0].SetDestination(key[0].GetPubKey().GetID());
inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2)); inner[1].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2)); inner[2].SetMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3)); inner[3].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3));
CScript outer[4]; CScript outer[4];
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -248,12 +248,12 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CCoinsViewCache coins(coinsDummy); CCoinsViewCache coins(coinsDummy);
CBasicKeyStore keystore; CBasicKeyStore keystore;
CKey key[3]; CKey key[3];
vector<CKey> keys; vector<CPubKey> keys;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
key[i].MakeNewKey(true); key[i].MakeNewKey(true);
keystore.AddKey(key[i]); keystore.AddKey(key[i]);
keys.push_back(key[i]); keys.push_back(key[i].GetPubKey());
} }
CTransaction txFrom; CTransaction txFrom;

View File

@ -211,7 +211,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
// and vice-versa) // and vice-versa)
// //
result << OP_0; result << OP_0;
BOOST_FOREACH(CKey key, keys) BOOST_FOREACH(const CKey &key, keys)
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig)); BOOST_CHECK(key.Sign(hash, vchSig));
@ -221,7 +221,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
return result; return result;
} }
CScript CScript
sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction) sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)
{ {
std::vector<CKey> keys; std::vector<CKey> keys;
keys.push_back(key); keys.push_back(key);
@ -333,11 +333,13 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
// Test the CombineSignatures function // Test the CombineSignatures function
CBasicKeyStore keystore; CBasicKeyStore keystore;
vector<CKey> keys; vector<CKey> keys;
vector<CPubKey> pubkeys;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
CKey key; CKey key;
key.MakeNewKey(i%2 == 1); key.MakeNewKey(i%2 == 1);
keys.push_back(key); keys.push_back(key);
pubkeys.push_back(key.GetPubKey());
keystore.AddKey(key); keystore.AddKey(key);
} }
@ -390,7 +392,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(combined == scriptSig); BOOST_CHECK(combined == scriptSig);
// Hardest case: Multisig 2-of-3 // Hardest case: Multisig 2-of-3
scriptPubKey.SetMultisig(2, keys); scriptPubKey.SetMultisig(2, pubkeys);
keystore.AddCScript(scriptPubKey); keystore.AddCScript(scriptPubKey);
SignSignature(keystore, txFrom, txTo, 0); SignSignature(keystore, txFrom, txTo, 0);
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);

View File

@ -37,12 +37,12 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
scriptSig << OP_0 << Serialize(s1); scriptSig << OP_0 << Serialize(s1);
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U);
std::vector<CKey> keys; std::vector<CPubKey> keys;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
CKey k; CKey k;
k.MakeNewKey(true); k.MakeNewKey(true);
keys.push_back(k); keys.push_back(k.GetPubKey());
} }
CScript s2; CScript s2;
s2.SetMultisig(1, keys); s2.SetMultisig(1, keys);

View File

@ -300,7 +300,8 @@ std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
return rv; return rv;
} }
inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false) template<typename T>
inline std::string HexStr(const T& vch, bool fSpaces=false)
{ {
return HexStr(vch.begin(), vch.end(), fSpaces); return HexStr(vch.begin(), vch.end(), fSpaces);
} }

View File

@ -32,26 +32,28 @@ CPubKey CWallet::GenerateNewKey()
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
RandAddSeedPerfmon(); RandAddSeedPerfmon();
CKey key; CKey secret;
key.MakeNewKey(fCompressed); secret.MakeNewKey(fCompressed);
// Compressed public keys were introduced in version 0.6.0 // Compressed public keys were introduced in version 0.6.0
if (fCompressed) if (fCompressed)
SetMinVersion(FEATURE_COMPRPUBKEY); SetMinVersion(FEATURE_COMPRPUBKEY);
if (!AddKey(key)) CPubKey pubkey = secret.GetPubKey();
if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
return key.GetPubKey(); return pubkey;
} }
bool CWallet::AddKey(const CKey& key) bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{ {
if (!CCryptoKeyStore::AddKey(key)) if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false; return false;
if (!fFileBacked) if (!fFileBacked)
return true; return true;
if (!IsCrypted()) if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey()); return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey());
}
return true; return true;
} }

View File

@ -136,9 +136,9 @@ public:
// Generate a new key // Generate a new key
CPubKey GenerateNewKey(); CPubKey GenerateNewKey();
// Adds a key to the store, and saves it to disk. // Adds a key to the store, and saves it to disk.
bool AddKey(const CKey& key); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
// Adds a key to the store, without saving it to disk (used by LoadWallet) // Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); } bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }

View File

@ -262,52 +262,33 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} }
else if (strType == "key" || strType == "wkey") else if (strType == "key" || strType == "wkey")
{ {
vector<unsigned char> vchPubKey; CPubKey vchPubKey;
ssKey >> vchPubKey; ssKey >> vchPubKey;
CKey key; if (!vchPubKey.IsValid())
if (strType == "key")
{ {
CPrivKey pkey; strErr = "Error reading wallet database: CPubKey corrupt";
ssValue >> pkey; return false;
key.SetPubKey(vchPubKey);
if (!key.SetPrivKey(pkey))
{
strErr = "Error reading wallet database: CPrivKey corrupt";
return false;
}
if (key.GetPubKey() != vchPubKey)
{
strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
return false;
}
if (!key.IsValid())
{
strErr = "Error reading wallet database: invalid CPrivKey";
return false;
}
} }
else CKey key;
{ CPrivKey pkey;
if (strType == "key")
ssValue >> pkey;
else {
CWalletKey wkey; CWalletKey wkey;
ssValue >> wkey; ssValue >> wkey;
key.SetPubKey(vchPubKey); pkey = wkey.vchPrivKey;
if (!key.SetPrivKey(wkey.vchPrivKey))
{
strErr = "Error reading wallet database: CPrivKey corrupt";
return false;
}
if (key.GetPubKey() != vchPubKey)
{
strErr = "Error reading wallet database: CWalletKey pubkey inconsistency";
return false;
}
if (!key.IsValid())
{
strErr = "Error reading wallet database: invalid CWalletKey";
return false;
}
} }
if (!pwallet->LoadKey(key)) if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed()))
{
strErr = "Error reading wallet database: CPrivKey corrupt";
return false;
}
if (key.GetPubKey() != vchPubKey)
{
strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
return false;
}
if (!pwallet->LoadKey(key, vchPubKey))
{ {
strErr = "Error reading wallet database: LoadKey failed"; strErr = "Error reading wallet database: LoadKey failed";
return false; return false;

View File

@ -53,18 +53,18 @@ public:
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey) bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey)
{ {
nWalletDBUpdated++; nWalletDBUpdated++;
return Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false); return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
} }
bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true) bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
{ {
nWalletDBUpdated++; nWalletDBUpdated++;
if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false)) if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
return false; return false;
if (fEraseUnencryptedKey) if (fEraseUnencryptedKey)
{ {
Erase(std::make_pair(std::string("key"), vchPubKey.Raw())); Erase(std::make_pair(std::string("key"), vchPubKey));
Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw())); Erase(std::make_pair(std::string("wkey"), vchPubKey));
} }
return true; return true;
} }
@ -101,7 +101,7 @@ public:
bool WriteDefaultKey(const CPubKey& vchPubKey) bool WriteDefaultKey(const CPubKey& vchPubKey)
{ {
nWalletDBUpdated++; nWalletDBUpdated++;
return Write(std::string("defaultkey"), vchPubKey.Raw()); return Write(std::string("defaultkey"), vchPubKey);
} }
bool ReadPool(int64 nPool, CKeyPool& keypool) bool ReadPool(int64 nPool, CKeyPool& keypool)