// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEY_H
// 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) */
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);
return !fSet;
}
- void MakeNewKey()
+ bool IsCompressed() const
+ {
+ return fCompressedPubKey;
+ }
+
+ void MakeNewKey(bool fCompressed)
{
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);
if (vchSecret.size() != 32)
throw key_error("CKey::SetSecret() : secret must be 32 bytes");
BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
- if (bn == NULL)
+ if (bn == NULL)
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 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 Sign(uint256 hash, std::vector<unsigned char>& vchSig)
{
- vchSig.clear();
- unsigned char pchSig[10000];
- unsigned int nSize = 0;
- if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey))
+ unsigned int nSize = ECDSA_size(pkey);
+ vchSig.resize(nSize); // Make sure it is big enough
+ if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
+ {
+ vchSig.clear();
return false;
- vchSig.resize(nSize);
- memcpy(&vchSig[0], pchSig, nSize);
+ }
+ vchSig.resize(nSize); // Shrink to fit actual size
return true;
}
{
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())
{
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;
{
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);
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);
return false;
return true;
}
+
+ bool IsValid()
+ {
+ if (!fSet)
+ return false;
+
+ bool fCompr;
+ CSecret secret = GetSecret(fCompr);
+ CKey key2;
+ key2.SetSecret(secret, fCompr);
+ return GetPubKey() == key2.GetPubKey();
+ }
};
#endif