Compressed pubkeys
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.
This commit is contained in:
parent
1684f98b27
commit
11529c6e4f
7 changed files with 79 additions and 50 deletions
21
src/base58.h
21
src/base58.h
|
@ -359,22 +359,25 @@ public:
|
|||
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)
|
||||
{
|
||||
|
@ -388,12 +391,12 @@ public:
|
|||
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()
|
||||
|
|
|
@ -1701,6 +1701,9 @@ Value validateaddress(const Array& params, bool fHelp)
|
|||
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()))
|
||||
{
|
||||
|
|
|
@ -860,12 +860,14 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
{
|
||||
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))
|
||||
|
|
34
src/key.h
34
src/key.h
|
@ -59,16 +59,30 @@ class CKey
|
|||
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);
|
||||
|
@ -95,10 +109,17 @@ public:
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -111,7 +132,7 @@ public:
|
|||
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);
|
||||
|
@ -126,10 +147,12 @@ public:
|
|||
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);
|
||||
|
@ -140,6 +163,7 @@ public:
|
|||
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
|
||||
if (n != nBytes)
|
||||
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
|
||||
fCompressed = fCompressedPubKey;
|
||||
return vchRet;
|
||||
}
|
||||
|
||||
|
@ -161,6 +185,8 @@ public:
|
|||
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
|
||||
return false;
|
||||
fSet = true;
|
||||
if (vchPubKey.size() == 33)
|
||||
SetCompressedPubKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,10 @@ bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned c
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -77,16 +79,6 @@ bool CCryptoKeyStore::SetCrypted()
|
|||
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)
|
||||
|
@ -103,6 +95,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
|||
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;
|
||||
|
@ -125,7 +118,8 @@ bool CCryptoKeyStore::AddKey(const CKey& key)
|
|||
|
||||
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))
|
||||
|
@ -147,19 +141,24 @@ bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey,
|
|||
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;
|
||||
|
@ -190,14 +189,15 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
|||
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;
|
||||
|
|
|
@ -20,15 +20,7 @@ public:
|
|||
|
||||
// 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;
|
||||
|
||||
|
@ -39,17 +31,17 @@ public:
|
|||
|
||||
// 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
|
||||
|
@ -81,14 +73,15 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +147,6 @@ public:
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -166,7 +158,7 @@ public:
|
|||
}
|
||||
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
|
||||
{
|
||||
|
|
|
@ -62,7 +62,9 @@ Value importprivkey(const Array& params, bool fHelp)
|
|||
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)
|
||||
|
@ -95,7 +97,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
|
|||
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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue