This patch enabled compressed pubkeys when -compressedpubkeys is passed.
These are 33 bytes instead of 65, and require only marginally more CPU
power when verifying. Compressed pubkeys have a different corresponding
address, so it is determined at generation. When -compressedpubkeys is
given, all newly generated addresses will use a compressed key, while
older/other addresses keep using normal keys. Unpatched clients will
relay and verify these transactions.
class CBitcoinSecret : public CBase58Data
{
public:
- void SetSecret(const CSecret& vchSecret)
- {
+ void SetSecret(const CSecret& vchSecret, bool fCompressed)
+ {
+ assert(vchSecret.size() == 32);
SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size());
+ if (fCompressed)
+ vchData.push_back(1);
}
- CSecret GetSecret()
+ CSecret GetSecret(bool &fCompressedOut)
{
CSecret vchSecret;
- vchSecret.resize(vchData.size());
- memcpy(&vchSecret[0], &vchData[0], vchData.size());
+ vchSecret.resize(32);
+ memcpy(&vchSecret[0], &vchData[0], 32);
+ fCompressedOut = vchData.size() == 33;
return vchSecret;
}
bool IsValid() const
{
- int nExpectedSize = 32;
bool fExpectTestNet = false;
switch(nVersion)
{
default:
return false;
}
- return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
+ return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1));
}
- CBitcoinSecret(const CSecret& vchSecret)
+ CBitcoinSecret(const CSecret& vchSecret, bool fCompressed)
{
- SetSecret(vchSecret);
+ SetSecret(vchSecret, fCompressed);
}
CBitcoinSecret()
ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
std::string strPubKey(vchPubKey.begin(), vchPubKey.end());
ret.push_back(Pair("pubkey58", EncodeBase58(vchPubKey)));
+ CKey key;
+ key.SetPubKey(vchPubKey);
+ ret.push_back(Pair("iscompressed", key.IsCompressed()));
}
else if (pwalletMain->HaveCScript(address.GetHash160()))
{
{
CPrivKey pkey;
ssValue >> pkey;
+ key.SetPubKey(vchPubKey);
key.SetPrivKey(pkey);
}
else
{
CWalletKey wkey;
ssValue >> wkey;
+ key.SetPubKey(vchPubKey);
key.SetPrivKey(wkey.vchPrivKey);
}
if (!pwallet->LoadKey(key))
protected:
EC_KEY* pkey;
bool fSet;
+ bool fCompressedPubKey;
+
+ void SetCompressedPubKey()
+ {
+ EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
+ fCompressedPubKey = true;
+ }
public:
- CKey()
+
+ void Reset()
{
+ fCompressedPubKey = false;
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()
+ {
+ Reset();
+ }
+
CKey(const CKey& b)
{
pkey = EC_KEY_dup(b.pkey);
return !fSet;
}
- void MakeNewKey()
+ bool IsCompressed() const
+ {
+ return fCompressedPubKey;
+ }
+
+ void MakeNewKey(bool fCompressed = true)
{
if (!EC_KEY_generate_key(pkey))
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
+ if (fCompressed)
+ SetCompressedPubKey();
fSet = true;
}
return true;
}
- bool SetSecret(const CSecret& vchSecret)
+ bool SetSecret(const CSecret& vchSecret, bool fCompressed = false)
{
EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
BN_clear_free(bn);
fSet = true;
+ if (fCompressed || fCompressedPubKey)
+ SetCompressedPubKey();
return true;
}
- CSecret GetSecret() const
+ CSecret GetSecret(bool &fCompressed) const
{
CSecret vchRet;
vchRet.resize(32);
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
if (n != nBytes)
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
+ fCompressed = fCompressedPubKey;
return vchRet;
}
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
return false;
fSet = true;
+ if (vchPubKey.size() == 33)
+ SetCompressedPubKey();
return true;
}
bool CBasicKeyStore::AddKey(const CKey& key)
{
+ bool fCompressed = false;
+ CSecret secret = key.GetSecret(fCompressed);
CRITICAL_BLOCK(cs_KeyStore)
- mapKeys[CBitcoinAddress(key.GetPubKey())] = key.GetSecret();
+ mapKeys[CBitcoinAddress(key.GetPubKey())] = make_pair(secret, fCompressed);
return true;
}
return true;
}
-std::vector<unsigned char> CCryptoKeyStore::GenerateNewKey()
-{
- RandAddSeedPerfmon();
- CKey key;
- key.MakeNewKey();
- if (!AddKey(key))
- throw std::runtime_error("CCryptoKeyStore::GenerateNewKey() : AddKey failed");
- return key.GetPubKey();
-}
-
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
CRITICAL_BLOCK(cs_KeyStore)
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
return false;
CKey key;
+ key.SetPubKey(vchPubKey);
key.SetSecret(vchSecret);
if (key.GetPubKey() == vchPubKey)
break;
std::vector<unsigned char> vchCryptedSecret;
std::vector<unsigned char> vchPubKey = key.GetPubKey();
- if (!EncryptSecret(vMasterKey, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
+ bool fCompressed;
+ if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
return false;
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
return true;
}
-bool CCryptoKeyStore::GetSecret(const CBitcoinAddress &address, CSecret& vchSecretOut) const
+bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
- return CBasicKeyStore::GetSecret(address, vchSecretOut);
+ return CBasicKeyStore::GetKey(address, keyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
const std::vector<unsigned char> &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- return DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecretOut);
+ CSecret vchSecret;
+ if (!DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
+ return false;
+ keyOut.SetPubKey(vchPubKey);
+ keyOut.SetSecret(vchSecret);
+ return true;
}
}
return false;
return false;
fUseCrypto = true;
- CKey key;
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
{
- if (!key.SetSecret(mKey.second))
+ CKey key;
+ if (!key.SetSecret(mKey.second.first, false))
return false;
const std::vector<unsigned char> vchPubKey = key.GetPubKey();
std::vector<unsigned char> vchCryptedSecret;
- if (!EncryptSecret(vMasterKeyIn, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
+ bool fCompressed;
+ if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
// Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CBitcoinAddress &address) const =0;
- virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const
- {
- CSecret vchSecret;
- if (!GetSecret(address, vchSecret))
- return false;
- if (!keyOut.SetSecret(vchSecret))
- return false;
- return true;
- }
+ virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0;
virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0;
virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
// Generate a new key, and add it to the store
virtual std::vector<unsigned char> GenerateNewKey();
- virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const
+ virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const
{
CKey key;
if (!GetKey(address, key))
return false;
- vchSecret = key.GetSecret();
+ vchSecret = key.GetSecret(fCompressed);
return true;
}
};
-typedef std::map<CBitcoinAddress, CSecret> KeyMap;
+typedef std::map<CBitcoinAddress, std::pair<CSecret, bool> > KeyMap;
typedef std::map<uint160, CScript > ScriptMap;
// Basic key store, that keeps keys in an address->secret map
}
}
}
- bool GetSecret(const CBitcoinAddress &address, CSecret &vchSecret) const
+ bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
KeyMap::const_iterator mi = mapKeys.find(address);
if (mi != mapKeys.end())
{
- vchSecret = (*mi).second;
+ keyOut.Reset();
+ keyOut.SetSecret((*mi).second.first, (*mi).second.second);
return true;
}
}
}
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
- std::vector<unsigned char> GenerateNewKey();
bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const
{
}
return false;
}
- bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const;
+ bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const;
bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
void GetKeys(std::set<CBitcoinAddress> &setAddress) const
{
if (!fGood) throw JSONRPCError(-5,"Invalid private key");
CKey key;
- key.SetSecret(vchSecret.GetSecret());
+ bool fCompressed;
+ CSecret secret = vchSecret.GetSecret(fCompressed);
+ key.SetSecret(secret, fCompressed);
CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey());
CRITICAL_BLOCK(cs_main)
if (!address.SetString(strAddress))
throw JSONRPCError(-5, "Invalid bitcoin address");
CSecret vchSecret;
- if (!pwalletMain->GetSecret(address, vchSecret))
+ bool fCompressed;
+ if (!pwalletMain->GetSecret(address, vchSecret, fCompressed))
throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known");
- return CBitcoinSecret(vchSecret).ToString();
+ return CBitcoinSecret(vchSecret, fCompressed).ToString();
}