src/key.cpp
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "key.h"
#include "eckey.h"
int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len)
{
while (c1len > c2len)
{
if (*c1)
return 1;
c1++;
c1len--;
};
while (c2len > c1len)
{
if (*c2)
return -1;
c2++;
c2len--;
};
while (c1len > 0)
{
if (*c1 > *c2)
return 1;
if (*c2 > *c1)
return -1;
c1++;
c2++;
c1len--;
};
return 0;
}
// Order of secp256k1's generator minus 1.
const unsigned char vchMaxModOrder[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
// Half of the order of secp256k1's generator minus 1.
const unsigned char vchMaxModHalfOrder[32] = {
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D,
0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0
};
const unsigned char vchZero[0] = {};
bool CKey::Check(const unsigned char *vch)
{
// Do not convert to OpenSSL's data structures for range-checking keys,
// it's easy enough to do directly.
static const unsigned char vchMax[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
bool fIsZero = true;
for (int i=0; i<32 && fIsZero; i++)
if (vch[i] != 0)
fIsZero = false;
if (fIsZero)
return false;
for (int i=0; i<32; i++)
{
if (vch[i] < vchMax[i])
return true;
if (vch[i] > vchMax[i])
return false;
}
return true;
}
bool CKey::CheckSignatureElement(const unsigned char *vch, int len, bool half)
{
return CompareBigEndian(vch, len, vchZero, 0) > 0 &&
CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0;
}
void CKey::MakeNewKey(bool fCompressedIn)
{
do {
RAND_bytes(vch, sizeof(vch));
} while (!Check(vch));
fValid = true;
fCompressed = fCompressedIn;
}
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn)
{
CECKey key;
if (!key.SetPrivKey(privkey))
return false;
key.GetSecretBytes(vch);
fCompressed = fCompressedIn;
fValid = true;
return true;
}
CPrivKey CKey::GetPrivKey() const
{
assert(fValid);
CECKey key;
key.SetSecretBytes(vch);
CPrivKey privkey;
key.GetPrivKey(privkey, fCompressed);
return privkey;
}
CPubKey CKey::GetPubKey() const
{
assert(fValid);
CECKey key;
key.SetSecretBytes(vch);
CPubKey pubkey;
key.GetPubKey(pubkey, fCompressed);
return pubkey;
}
CPubKey CKey::GetPubKey(bool fForceCompressed) const
{
assert(fValid);
CECKey key;
key.SetSecretBytes(vch);
CPubKey pubkey;
key.GetPubKey(pubkey, fForceCompressed);
return pubkey;
}
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const
{
if (!fValid)
return false;
CECKey key;
key.SetSecretBytes(vch);
return key.Sign(hash, vchSig);
}
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const
{
if (!fValid)
return false;
CECKey key;
key.SetSecretBytes(vch);
vchSig.resize(65);
int rec = -1;
if (!key.SignCompact(hash, &vchSig[1], rec))
return false;
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
return true;
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false)
{
CECKey key;
if (!key.SetPrivKey(privkey, fSkipCheck))
return false;
key.GetSecretBytes(vch);
fCompressed = vchPubKey.IsCompressed();
fValid = true;
if (fSkipCheck)
return true;
if (GetPubKey() != vchPubKey)
return false;
return true;
}
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const
{
if (!IsValid())
return false;
CECKey key;
if (!key.SetPubKey(*this))
return false;
if (!key.Verify(hash, vchSig))
return false;
return true;
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig)
{
if (vchSig.size() != 65)
return false;
CECKey key;
if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
return false;
key.GetPubKey(*this, (vchSig[0] - 27) & 4);
return true;
}
bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const
{
if (!IsValid())
return false;
if (vchSig.size() != 65)
return false;
CECKey key;
if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
return false;
CPubKey pubkeyRec;
key.GetPubKey(pubkeyRec, IsCompressed());
if (*this != pubkeyRec)
return false;
return true;
}
bool CPubKey::IsFullyValid() const
{
if (!IsValid())
return false;
CECKey key;
if (!key.SetPubKey(*this))
return false;
return true;
}
bool CPubKey::Decompress()
{
if (!IsValid())
return false;
CECKey key;
if (!key.SetPubKey(*this))
return false;
key.GetPubKey(*this, false);
return true;
}
void static BIP32Hash(const unsigned char chainCode[32], unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64])
{
unsigned char num[4];
num[0] = (nChild >> 24) & 0xFF;
num[1] = (nChild >> 16) & 0xFF;
num[2] = (nChild >> 8) & 0xFF;
num[3] = (nChild >> 0) & 0xFF;
HMAC_SHA512_CTX ctx;
HMAC_SHA512_Init(&ctx, chainCode, 32);
HMAC_SHA512_Update(&ctx, &header, 1);
HMAC_SHA512_Update(&ctx, data, 32);
HMAC_SHA512_Update(&ctx, num, 4);
HMAC_SHA512_Final(output, &ctx);
}
bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const
{
assert(IsValid());
assert(IsCompressed());
unsigned char out[64];
LockObject(out);
if ((nChild >> 31) == 0)
{
CPubKey pubkey = GetPubKey();
assert(pubkey.begin() + 33 == pubkey.end());
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out);
} else
{
assert(begin() + 32 == end());
BIP32Hash(cc, nChild, 0, begin(), out);
};
memcpy(ccChild, out+32, 32);
bool ret = TweakSecret((unsigned char*)keyChild.begin(), begin(), out);
UnlockObject(out);
keyChild.fCompressed = true;
keyChild.fValid = ret;
return ret;
}
bool CKey::VerifyPubKey(const CPubKey& pubkey) const
{
if (pubkey.IsCompressed() != fCompressed)
{
return false;
}
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
RAND_bytes(rnd, sizeof(rnd));
uint256 hash = CHashWriter(SER_GETHASH, 0).write((char*)str.data(), str.size()).write((char*)rnd, sizeof(rnd)).GetHash();
std::vector<unsigned char> vchSig;
Sign(hash, vchSig);
return pubkey.Verify(hash, vchSig);
}
bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const
{
assert(IsValid());
assert((nChild >> 31) == 0);
assert(begin() + 33 == end());
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild, out+32, 32);
CECKey key;
bool ret = key.SetPubKey(*this);
ret &= key.TweakPublic(out);
key.GetPubKey(pubkeyChild, true);
return ret;
}
bool CExtKey::Derive(CExtKey &out, unsigned int nChild) const
{
out.nDepth = nDepth + 1;
CKeyID id = key.GetPubKey().GetID();
memcpy(&out.vchFingerprint[0], &id, 4);
out.nChild = nChild;
return key.Derive(out.key, out.vchChainCode, nChild, vchChainCode);
}
void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen)
{
static const char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
HMAC_SHA512_CTX ctx;
HMAC_SHA512_Init(&ctx, hashkey, sizeof(hashkey));
HMAC_SHA512_Update(&ctx, seed, nSeedLen);
unsigned char out[64];
LockObject(out);
HMAC_SHA512_Final(out, &ctx);
key.Set(&out[0], &out[32], true);
memcpy(vchChainCode, &out[32], 32);
UnlockObject(out);
nDepth = 0;
nChild = 0;
memset(vchFingerprint, 0, sizeof(vchFingerprint));
}
int CExtKey::SetKeyCode(const unsigned char *pkey, const unsigned char *pcode)
{
key.Set(pkey, true);
memcpy(vchChainCode, pcode, 32);
nDepth = 0;
nChild = 0;
memset(vchFingerprint, 0, sizeof(vchFingerprint));
return 0;
}
CExtPubKey CExtKey::Neutered() const
{
CExtPubKey ret;
ret.nDepth = nDepth;
memcpy(&ret.vchFingerprint[0], &vchFingerprint[0], 4);
ret.nChild = nChild;
ret.pubkey = key.GetPubKey(true);
memcpy(&ret.vchChainCode[0], &vchChainCode[0], 32);
return ret;
}
void CExtKey::Encode(unsigned char code[74]) const
{
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
memcpy(code+9, vchChainCode, 32);
code[41] = 0;
assert(key.size() == 32);
memcpy(code+42, key.begin(), 32);
}
void CExtKey::Decode(const unsigned char code[74])
{
nDepth = code[0];
memcpy(vchFingerprint, code+1, 4);
nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
memcpy(vchChainCode, code+9, 32);
key.Set(code+42, code+74, true);
}
void CExtPubKey::Encode(unsigned char code[74]) const
{
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
memcpy(code+9, vchChainCode, 32);
assert(pubkey.size() == 33);
memcpy(code+41, pubkey.begin(), 33);
}
void CExtPubKey::Decode(const unsigned char code[74])
{
nDepth = code[0];
memcpy(vchFingerprint, code+1, 4);
nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
memcpy(vchChainCode, code+9, 32);
pubkey.Set(code+41, code+74);
}
bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const
{
out.nDepth = nDepth + 1;
CKeyID id = pubkey.GetID();
memcpy(&out.vchFingerprint[0], &id, 4);
out.nChild = nChild;
return pubkey.Derive(out.pubkey, out.vchChainCode, nChild, vchChainCode);
}
void CExtKeyPair::EncodeV(unsigned char code[74]) const
{
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
memcpy(code+9, vchChainCode, 32);
code[41] = 0;
assert(key.size() == 32);
memcpy(code+42, key.begin(), 32);
};
void CExtKeyPair::DecodeV(const unsigned char code[74])
{
nDepth = code[0];
memcpy(vchFingerprint, code+1, 4);
nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
memcpy(vchChainCode, code+9, 32);
key.Set(code+42, code+74, true);
pubkey = key.GetPubKey(true);
};
void CExtKeyPair::EncodeP(unsigned char code[74]) const
{
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
memcpy(code+9, vchChainCode, 32);
assert(pubkey.size() == 33);
memcpy(code+41, pubkey.begin(), 33);
};
void CExtKeyPair::DecodeP(const unsigned char code[74])
{
nDepth = code[0];
memcpy(vchFingerprint, code+1, 4);
nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
memcpy(vchChainCode, code+9, 32);
pubkey.Set(code+41, code+74);
key.Clear();
};
bool CExtKeyPair::Derive(CExtKey &out, unsigned int nChild) const
{
if (!key.IsValid())
return false;
out.nDepth = nDepth + 1;
CKeyID id = key.GetPubKey().GetID();
memcpy(&out.vchFingerprint[0], &id, 4);
out.nChild = nChild;
return key.Derive(out.key, out.vchChainCode, nChild, vchChainCode);
};
bool CExtKeyPair::Derive(CExtPubKey &out, unsigned int nChild) const
{
if ((nChild >> 31) == 0)
{
out.nDepth = nDepth + 1;
CKeyID id = pubkey.GetID();
memcpy(&out.vchFingerprint[0], &id, 4);
out.nChild = nChild;
return pubkey.Derive(out.pubkey, out.vchChainCode, nChild, vchChainCode);
};
if (!key.IsValid())
return false;
out.nDepth = nDepth + 1;
CKeyID id = pubkey.GetID();
memcpy(&out.vchFingerprint[0], &id, 4);
out.nChild = nChild;
CKey tkey;
if (!key.Derive(tkey, out.vchChainCode, nChild, vchChainCode))
return false;
out.pubkey = tkey.GetPubKey(true);
return true;
};
bool CExtKeyPair::Derive(CKey &out, unsigned int nChild) const
{
if (!key.IsValid())
return false;
unsigned char temp[32];
return key.Derive(out, temp, nChild, vchChainCode);
};
bool CExtKeyPair::Derive(CPubKey &out, unsigned int nChild) const
{
unsigned char temp[32];
if ((nChild >> 31) == 0)
{
return pubkey.Derive(out, temp, nChild, vchChainCode);
};
if (!key.IsValid())
return false;
CKey tkey;
if (!key.Derive(tkey, temp, nChild, vchChainCode))
return false;
out = tkey.GetPubKey(true);
return true;
};
CExtPubKey CExtKeyPair::GetExtPubKey() const
{
CExtPubKey ret;
ret.nDepth = nDepth;
memcpy(&ret.vchFingerprint[0], &vchFingerprint[0], 4);
ret.nChild = nChild;
ret.pubkey = pubkey;
memcpy(&ret.vchChainCode[0], &vchChainCode[0], 32);
return ret;
};
CExtKeyPair CExtKeyPair::Neutered() const
{
CExtKeyPair ret;
ret.nDepth = nDepth;
memcpy(&ret.vchFingerprint[0], &vchFingerprint[0], 4);
ret.nChild = nChild;
ret.pubkey = pubkey;
ret.key.Clear();
memcpy(&ret.vchChainCode[0], &vchChainCode[0], 32);
return ret;
}
void CExtKeyPair::SetMaster(const unsigned char *seed, unsigned int nSeedLen)
{
static const char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
HMAC_SHA512_CTX ctx;
HMAC_SHA512_Init(&ctx, hashkey, sizeof(hashkey));
HMAC_SHA512_Update(&ctx, seed, nSeedLen);
unsigned char out[64];
LockObject(out);
HMAC_SHA512_Final(out, &ctx);
key.Set(&out[0], &out[32], true);
pubkey = key.GetPubKey(true);
memcpy(vchChainCode, &out[32], 32);
UnlockObject(out);
nDepth = 0;
nChild = 0;
memset(vchFingerprint, 0, sizeof(vchFingerprint));
};
int CExtKeyPair::SetKeyCode(const unsigned char *pkey, const unsigned char *pcode)
{
key.Set(pkey, true);
pubkey = key.GetPubKey(true);
memcpy(vchChainCode, pcode, 32);
nDepth = 0;
nChild = 0;
memset(vchFingerprint, 0, sizeof(vchFingerprint));
return 0;
};
bool ECC_InitSanityCheck()
{
EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if(pkey == NULL)
return false;
EC_KEY_free(pkey);
// TODO Is there more EC functionality that could be missing?
return true;
}