Skip to content

Commit 9f6a4eb

Browse files
committed
Merge pull request #649 from sipa/comprpubkey
Compressed pubkeys
2 parents 476e6d1 + 3eab85a commit 9f6a4eb

File tree

8 files changed

+228
-53
lines changed

8 files changed

+228
-53
lines changed

src/base58.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -359,22 +359,25 @@ class CBitcoinAddress : public CBase58Data
359359
class CBitcoinSecret : public CBase58Data
360360
{
361361
public:
362-
void SetSecret(const CSecret& vchSecret)
363-
{
362+
void SetSecret(const CSecret& vchSecret, bool fCompressed)
363+
{
364+
assert(vchSecret.size() == 32);
364365
SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size());
366+
if (fCompressed)
367+
vchData.push_back(1);
365368
}
366369

367-
CSecret GetSecret()
370+
CSecret GetSecret(bool &fCompressedOut)
368371
{
369372
CSecret vchSecret;
370-
vchSecret.resize(vchData.size());
371-
memcpy(&vchSecret[0], &vchData[0], vchData.size());
373+
vchSecret.resize(32);
374+
memcpy(&vchSecret[0], &vchData[0], 32);
375+
fCompressedOut = vchData.size() == 33;
372376
return vchSecret;
373377
}
374378

375379
bool IsValid() const
376380
{
377-
int nExpectedSize = 32;
378381
bool fExpectTestNet = false;
379382
switch(nVersion)
380383
{
@@ -388,12 +391,12 @@ class CBitcoinSecret : public CBase58Data
388391
default:
389392
return false;
390393
}
391-
return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
394+
return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1));
392395
}
393396

394-
CBitcoinSecret(const CSecret& vchSecret)
397+
CBitcoinSecret(const CSecret& vchSecret, bool fCompressed)
395398
{
396-
SetSecret(vchSecret);
399+
SetSecret(vchSecret, fCompressed);
397400
}
398401

399402
CBitcoinSecret()

src/bitcoinrpc.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,9 @@ Value validateaddress(const Array& params, bool fHelp)
17011701
ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
17021702
std::string strPubKey(vchPubKey.begin(), vchPubKey.end());
17031703
ret.push_back(Pair("pubkey58", EncodeBase58(vchPubKey)));
1704+
CKey key;
1705+
key.SetPubKey(vchPubKey);
1706+
ret.push_back(Pair("iscompressed", key.IsCompressed()));
17041707
}
17051708
else if (pwalletMain->HaveCScript(address.GetHash160()))
17061709
{

src/db.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,12 +860,14 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
860860
{
861861
CPrivKey pkey;
862862
ssValue >> pkey;
863+
key.SetPubKey(vchPubKey);
863864
key.SetPrivKey(pkey);
864865
}
865866
else
866867
{
867868
CWalletKey wkey;
868869
ssValue >> wkey;
870+
key.SetPubKey(vchPubKey);
869871
key.SetPrivKey(wkey.vchPrivKey);
870872
}
871873
if (!pwallet->LoadKey(key))

src/key.h

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,30 @@ class CKey
5959
protected:
6060
EC_KEY* pkey;
6161
bool fSet;
62+
bool fCompressedPubKey;
63+
64+
void SetCompressedPubKey()
65+
{
66+
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
67+
fCompressedPubKey = true;
68+
}
6269

6370
public:
64-
CKey()
71+
72+
void Reset()
6573
{
74+
fCompressedPubKey = false;
6675
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
6776
if (pkey == NULL)
6877
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
6978
fSet = false;
7079
}
7180

81+
CKey()
82+
{
83+
Reset();
84+
}
85+
7286
CKey(const CKey& b)
7387
{
7488
pkey = EC_KEY_dup(b.pkey);
@@ -95,10 +109,17 @@ class CKey
95109
return !fSet;
96110
}
97111

98-
void MakeNewKey()
112+
bool IsCompressed() const
113+
{
114+
return fCompressedPubKey;
115+
}
116+
117+
void MakeNewKey(bool fCompressed = true)
99118
{
100119
if (!EC_KEY_generate_key(pkey))
101120
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
121+
if (fCompressed)
122+
SetCompressedPubKey();
102123
fSet = true;
103124
}
104125

@@ -111,7 +132,7 @@ class CKey
111132
return true;
112133
}
113134

114-
bool SetSecret(const CSecret& vchSecret)
135+
bool SetSecret(const CSecret& vchSecret, bool fCompressed = false)
115136
{
116137
EC_KEY_free(pkey);
117138
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
@@ -126,10 +147,12 @@ class CKey
126147
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
127148
BN_clear_free(bn);
128149
fSet = true;
150+
if (fCompressed || fCompressedPubKey)
151+
SetCompressedPubKey();
129152
return true;
130153
}
131154

132-
CSecret GetSecret() const
155+
CSecret GetSecret(bool &fCompressed) const
133156
{
134157
CSecret vchRet;
135158
vchRet.resize(32);
@@ -140,6 +163,7 @@ class CKey
140163
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
141164
if (n != nBytes)
142165
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
166+
fCompressed = fCompressedPubKey;
143167
return vchRet;
144168
}
145169

@@ -161,6 +185,8 @@ class CKey
161185
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
162186
return false;
163187
fSet = true;
188+
if (vchPubKey.size() == 33)
189+
SetCompressedPubKey();
164190
return true;
165191
}
166192

@@ -210,6 +236,8 @@ class CKey
210236
{
211237
CKey keyRec;
212238
keyRec.fSet = true;
239+
if (fCompressedPubKey)
240+
keyRec.SetCompressedPubKey();
213241
if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
214242
if (keyRec.GetPubKey() == this->GetPubKey())
215243
{
@@ -221,7 +249,7 @@ class CKey
221249
if (nRecId == -1)
222250
throw key_error("CKey::SignCompact() : unable to construct recoverable key");
223251

224-
vchSig[0] = nRecId+27;
252+
vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
225253
BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
226254
BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
227255
fOk = true;
@@ -238,15 +266,21 @@ class CKey
238266
{
239267
if (vchSig.size() != 65)
240268
return false;
241-
if (vchSig[0]<27 || vchSig[0]>=31)
269+
int nV = vchSig[0];
270+
if (nV<27 || nV>=35)
242271
return false;
243272
ECDSA_SIG *sig = ECDSA_SIG_new();
244273
BN_bin2bn(&vchSig[1],32,sig->r);
245274
BN_bin2bn(&vchSig[33],32,sig->s);
246275

247276
EC_KEY_free(pkey);
248277
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
249-
if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), vchSig[0] - 27, 0) == 1)
278+
if (nV >= 31)
279+
{
280+
SetCompressedPubKey();
281+
nV -= 4;
282+
}
283+
if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
250284
{
251285
fSet = true;
252286
ECDSA_SIG_free(sig);

src/keystore.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned c
2929

3030
bool CBasicKeyStore::AddKey(const CKey& key)
3131
{
32+
bool fCompressed = false;
33+
CSecret secret = key.GetSecret(fCompressed);
3234
CRITICAL_BLOCK(cs_KeyStore)
33-
mapKeys[CBitcoinAddress(key.GetPubKey())] = key.GetSecret();
35+
mapKeys[CBitcoinAddress(key.GetPubKey())] = make_pair(secret, fCompressed);
3436
return true;
3537
}
3638

@@ -77,16 +79,6 @@ bool CCryptoKeyStore::SetCrypted()
7779
return true;
7880
}
7981

80-
std::vector<unsigned char> CCryptoKeyStore::GenerateNewKey()
81-
{
82-
RandAddSeedPerfmon();
83-
CKey key;
84-
key.MakeNewKey();
85-
if (!AddKey(key))
86-
throw std::runtime_error("CCryptoKeyStore::GenerateNewKey() : AddKey failed");
87-
return key.GetPubKey();
88-
}
89-
9082
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
9183
{
9284
CRITICAL_BLOCK(cs_KeyStore)
@@ -103,6 +95,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
10395
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
10496
return false;
10597
CKey key;
98+
key.SetPubKey(vchPubKey);
10699
key.SetSecret(vchSecret);
107100
if (key.GetPubKey() == vchPubKey)
108101
break;
@@ -125,7 +118,8 @@ bool CCryptoKeyStore::AddKey(const CKey& key)
125118

126119
std::vector<unsigned char> vchCryptedSecret;
127120
std::vector<unsigned char> vchPubKey = key.GetPubKey();
128-
if (!EncryptSecret(vMasterKey, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
121+
bool fCompressed;
122+
if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
129123
return false;
130124

131125
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
@@ -147,19 +141,24 @@ bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey,
147141
return true;
148142
}
149143

150-
bool CCryptoKeyStore::GetSecret(const CBitcoinAddress &address, CSecret& vchSecretOut) const
144+
bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const
151145
{
152146
CRITICAL_BLOCK(cs_KeyStore)
153147
{
154148
if (!IsCrypted())
155-
return CBasicKeyStore::GetSecret(address, vchSecretOut);
149+
return CBasicKeyStore::GetKey(address, keyOut);
156150

157151
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
158152
if (mi != mapCryptedKeys.end())
159153
{
160154
const std::vector<unsigned char> &vchPubKey = (*mi).second.first;
161155
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
162-
return DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecretOut);
156+
CSecret vchSecret;
157+
if (!DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
158+
return false;
159+
keyOut.SetPubKey(vchPubKey);
160+
keyOut.SetSecret(vchSecret);
161+
return true;
163162
}
164163
}
165164
return false;
@@ -190,14 +189,15 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
190189
return false;
191190

192191
fUseCrypto = true;
193-
CKey key;
194192
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
195193
{
196-
if (!key.SetSecret(mKey.second))
194+
CKey key;
195+
if (!key.SetSecret(mKey.second.first, false))
197196
return false;
198197
const std::vector<unsigned char> vchPubKey = key.GetPubKey();
199198
std::vector<unsigned char> vchCryptedSecret;
200-
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
199+
bool fCompressed;
200+
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
201201
return false;
202202
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
203203
return false;

src/keystore.h

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,7 @@ class CKeyStore
2020

2121
// Check whether a key corresponding to a given address is present in the store.
2222
virtual bool HaveKey(const CBitcoinAddress &address) const =0;
23-
virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const
24-
{
25-
CSecret vchSecret;
26-
if (!GetSecret(address, vchSecret))
27-
return false;
28-
if (!keyOut.SetSecret(vchSecret))
29-
return false;
30-
return true;
31-
}
23+
virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0;
3224
virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0;
3325
virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
3426

@@ -39,17 +31,17 @@ class CKeyStore
3931

4032
// Generate a new key, and add it to the store
4133
virtual std::vector<unsigned char> GenerateNewKey();
42-
virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const
34+
virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const
4335
{
4436
CKey key;
4537
if (!GetKey(address, key))
4638
return false;
47-
vchSecret = key.GetSecret();
39+
vchSecret = key.GetSecret(fCompressed);
4840
return true;
4941
}
5042
};
5143

52-
typedef std::map<CBitcoinAddress, CSecret> KeyMap;
44+
typedef std::map<CBitcoinAddress, std::pair<CSecret, bool> > KeyMap;
5345
typedef std::map<uint160, CScript > ScriptMap;
5446

5547
// Basic key store, that keeps keys in an address->secret map
@@ -81,14 +73,15 @@ class CBasicKeyStore : public CKeyStore
8173
}
8274
}
8375
}
84-
bool GetSecret(const CBitcoinAddress &address, CSecret &vchSecret) const
76+
bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const
8577
{
8678
CRITICAL_BLOCK(cs_KeyStore)
8779
{
8880
KeyMap::const_iterator mi = mapKeys.find(address);
8981
if (mi != mapKeys.end())
9082
{
91-
vchSecret = (*mi).second;
83+
keyOut.Reset();
84+
keyOut.SetSecret((*mi).second.first, (*mi).second.second);
9285
return true;
9386
}
9487
}
@@ -154,7 +147,6 @@ class CCryptoKeyStore : public CBasicKeyStore
154147
}
155148

156149
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
157-
std::vector<unsigned char> GenerateNewKey();
158150
bool AddKey(const CKey& key);
159151
bool HaveKey(const CBitcoinAddress &address) const
160152
{
@@ -166,7 +158,7 @@ class CCryptoKeyStore : public CBasicKeyStore
166158
}
167159
return false;
168160
}
169-
bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const;
161+
bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const;
170162
bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
171163
void GetKeys(std::set<CBitcoinAddress> &setAddress) const
172164
{

src/rpcdump.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ Value importprivkey(const Array& params, bool fHelp)
6262
if (!fGood) throw JSONRPCError(-5,"Invalid private key");
6363

6464
CKey key;
65-
key.SetSecret(vchSecret.GetSecret());
65+
bool fCompressed;
66+
CSecret secret = vchSecret.GetSecret(fCompressed);
67+
key.SetSecret(secret, fCompressed);
6668
CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey());
6769

6870
CRITICAL_BLOCK(cs_main)
@@ -95,7 +97,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
9597
if (!address.SetString(strAddress))
9698
throw JSONRPCError(-5, "Invalid bitcoin address");
9799
CSecret vchSecret;
98-
if (!pwalletMain->GetSecret(address, vchSecret))
100+
bool fCompressed;
101+
if (!pwalletMain->GetSecret(address, vchSecret, fCompressed))
99102
throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known");
100-
return CBitcoinSecret(vchSecret).ToString();
103+
return CBitcoinSecret(vchSecret, fCompressed).ToString();
101104
}

0 commit comments

Comments
 (0)