Skip to content

Commit

Permalink
Merge pull request #649 from sipa/comprpubkey
Browse files Browse the repository at this point in the history
Compressed pubkeys
  • Loading branch information
sipa committed Jan 10, 2012
2 parents 476e6d1 + 3eab85a commit 9f6a4eb
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 53 deletions.
21 changes: 12 additions & 9 deletions src/base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,22 +359,25 @@ class CBitcoinAddress : public CBase58Data
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)
{
Expand All @@ -388,12 +391,12 @@ class CBitcoinSecret : public CBase58Data
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()
Expand Down
3 changes: 3 additions & 0 deletions src/bitcoinrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
{
Expand Down
2 changes: 2 additions & 0 deletions src/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
48 changes: 41 additions & 7 deletions src/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -95,10 +109,17 @@ class CKey
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;
}

Expand All @@ -111,7 +132,7 @@ class CKey
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);
Expand All @@ -126,10 +147,12 @@ class CKey
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);
Expand All @@ -140,6 +163,7 @@ class CKey
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
if (n != nBytes)
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
fCompressed = fCompressedPubKey;
return vchRet;
}

Expand All @@ -161,6 +185,8 @@ class CKey
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
return false;
fSet = true;
if (vchPubKey.size() == 33)
SetCompressedPubKey();
return true;
}

Expand Down Expand Up @@ -210,6 +236,8 @@ class CKey
{
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())
{
Expand All @@ -221,7 +249,7 @@ class CKey
if (nRecId == -1)
throw key_error("CKey::SignCompact() : unable to construct recoverable key");

vchSig[0] = nRecId+27;
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;
Expand All @@ -238,15 +266,21 @@ class CKey
{
if (vchSig.size() != 65)
return false;
if (vchSig[0]<27 || vchSig[0]>=31)
int nV = vchSig[0];
if (nV<27 || nV>=35)
return false;
ECDSA_SIG *sig = ECDSA_SIG_new();
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 (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), vchSig[0] - 27, 0) == 1)
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);
Expand Down
36 changes: 18 additions & 18 deletions src/keystore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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))
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
24 changes: 8 additions & 16 deletions src/keystore.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,7 @@ class CKeyStore

// 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;

Expand All @@ -39,17 +31,17 @@ class CKeyStore

// 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
Expand Down Expand Up @@ -81,14 +73,15 @@ class CBasicKeyStore : public CKeyStore
}
}
}
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;
}
}
Expand Down Expand Up @@ -154,7 +147,6 @@ class CCryptoKeyStore : public CBasicKeyStore
}

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
{
Expand All @@ -166,7 +158,7 @@ class CCryptoKeyStore : public CBasicKeyStore
}
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
{
Expand Down
9 changes: 6 additions & 3 deletions src/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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

0 comments on commit 9f6a4eb

Please sign in to comment.