diff options
author | Roy Badami <roy@gnomon.org.uk> | 2014-07-07 22:06:21 +0100 |
---|---|---|
committer | Roy Badami <roy@gnomon.org.uk> | 2014-07-07 22:06:21 +0100 |
commit | 96df327834af3b55918adfac9b3f65adfc960b3a (patch) | |
tree | 8bd199df46ea6f39f7094c0e7db2185b4d3f5d6d /src/key.cpp | |
parent | 2e4fee2ac4824570c1340a8f8fe2aed4580de879 (diff) | |
parent | 1fedd65fcf9ac04b70f0fa8cf6caa9629857d586 (diff) |
Merge remote-tracking branch 'upstream/master'
Conflicts:
src/qt/overviewpage.cpp
src/qt/transactiondesc.cpp
Diffstat (limited to 'src/key.cpp')
-rw-r--r-- | src/key.cpp | 247 |
1 files changed, 189 insertions, 58 deletions
diff --git a/src/key.cpp b/src/key.cpp index b57b7c506c..3c4fa77e72 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -4,14 +4,35 @@ #include "key.h" +#include "crypto/sha2.h" +#include <openssl/rand.h> + +#ifdef USE_SECP256K1 +#include <secp256k1.h> +#else #include <openssl/bn.h> #include <openssl/ecdsa.h> #include <openssl/obj_mac.h> -#include <openssl/rand.h> +#endif // anonymous namespace with local implementation code (OpenSSL interaction) namespace { +#ifdef USE_SECP256K1 +#include <secp256k1.h> +class CSecp256k1Init { +public: + CSecp256k1Init() { + secp256k1_start(); + } + ~CSecp256k1Init() { + secp256k1_stop(); + } +}; +static CSecp256k1Init instance_of_csecp256k1; + +#else + // Generate a private key from just the secret parameter int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) { @@ -332,30 +353,61 @@ public: } }; -}; // end of anonymous namespace +#endif -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; +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--; } - return true; + 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] = {}; + +} // anon namespace + +bool CKey::Check(const unsigned char *vch) { + return CompareBigEndian(vch, 32, vchZero, 0) > 0 && + CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0; +} + +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) { @@ -367,10 +419,15 @@ void CKey::MakeNewKey(bool fCompressedIn) { } bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { +#ifdef USE_SECP256K1 + if (!secp256k1_ecdsa_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size())) + return false; +#else CECKey key; if (!key.SetPrivKey(privkey)) return false; key.GetSecretBytes(vch); +#endif fCompressed = fCompressedIn; fValid = true; return true; @@ -378,114 +435,167 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { CPrivKey CKey::GetPrivKey() const { assert(fValid); + CPrivKey privkey; +#ifdef USE_SECP256K1 + privkey.resize(279); + int privkeylen = 279; + int ret = secp256k1_ecdsa_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); + assert(ret); + privkey.resize(privkeylen); +#else CECKey key; key.SetSecretBytes(vch); - CPrivKey privkey; key.GetPrivKey(privkey, fCompressed); +#endif return privkey; } CPubKey CKey::GetPubKey() const { assert(fValid); + CPubKey pubkey; +#ifdef USE_SECP256K1 + int clen = 65; + int ret = secp256k1_ecdsa_pubkey_create((unsigned char*)pubkey.begin(), &clen, begin(), fCompressed); + assert(ret); + assert(pubkey.IsValid()); + assert((int)pubkey.size() == clen); +#else CECKey key; key.SetSecretBytes(vch); - CPubKey pubkey; key.GetPubKey(pubkey, fCompressed); +#endif return pubkey; } bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const { if (!fValid) return false; +#ifdef USE_SECP256K1 + vchSig.resize(72); + int nSigLen = 72; + CKey nonce; + do { + nonce.MakeNewKey(true); + if (secp256k1_ecdsa_sign((const unsigned char*)&hash, 32, (unsigned char*)&vchSig[0], &nSigLen, begin(), nonce.begin())) + break; + } while(true); + vchSig.resize(nSigLen); + return true; +#else CECKey key; key.SetSecretBytes(vch); return key.Sign(hash, vchSig); +#endif } 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; +#ifdef USE_SECP256K1 + CKey nonce; + do { + nonce.MakeNewKey(true); + if (secp256k1_ecdsa_sign_compact((const unsigned char*)&hash, 32, &vchSig[1], begin(), nonce.begin(), &rec)) + break; + } while(true); +#else + CECKey key; + key.SetSecretBytes(vch); if (!key.SignCompact(hash, &vchSig[1], rec)) return false; +#endif assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); return true; } bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) { +#ifdef USE_SECP256K1 + if (!secp256k1_ecdsa_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size())) + return false; +#else CECKey key; if (!key.SetPrivKey(privkey, fSkipCheck)) return false; - key.GetSecretBytes(vch); +#endif 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; +#ifdef USE_SECP256K1 + if (secp256k1_ecdsa_verify((const unsigned char*)&hash, 32, &vchSig[0], vchSig.size(), begin(), size()) != 1) + return false; +#else CECKey key; if (!key.SetPubKey(*this)) return false; if (!key.Verify(hash, vchSig)) return false; +#endif 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) + int recid = (vchSig[0] - 27) & 3; + bool fComp = (vchSig[0] - 27) & 4; +#ifdef USE_SECP256K1 + int pubkeylen = 65; + if (!secp256k1_ecdsa_recover_compact((const unsigned char*)&hash, 32, &vchSig[1], (unsigned char*)begin(), &pubkeylen, fComp, recid)) return false; + assert((int)size() == pubkeylen); +#else CECKey key; - if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4)) - return false; - CPubKey pubkeyRec; - key.GetPubKey(pubkeyRec, IsCompressed()); - if (*this != pubkeyRec) + if (!key.Recover(hash, &vchSig[1], recid)) return false; + key.GetPubKey(*this, fComp); +#endif return true; } bool CPubKey::IsFullyValid() const { if (!IsValid()) return false; +#ifdef USE_SECP256K1 + if (!secp256k1_ecdsa_pubkey_verify(begin(), size())) + return false; +#else CECKey key; if (!key.SetPubKey(*this)) return false; +#endif return true; } bool CPubKey::Decompress() { if (!IsValid()) return false; +#ifdef USE_SECP256K1 + int clen = size(); + int ret = secp256k1_ecdsa_pubkey_decompress((unsigned char*)begin(), &clen); + assert(ret); + assert(clen == (int)size()); +#else CECKey key; if (!key.SetPubKey(*this)) return false; key.GetPubKey(*this, false); +#endif return true; } @@ -495,12 +605,10 @@ void static BIP32Hash(const unsigned char chainCode[32], unsigned int nChild, un 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); + CHMAC_SHA512(chainCode, 32).Write(&header, 1) + .Write(data, 32) + .Write(num, 4) + .Finalize(output); } bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const { @@ -517,7 +625,12 @@ bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild BIP32Hash(cc, nChild, 0, begin(), out); } memcpy(ccChild, out+32, 32); +#ifdef USE_SECP256K1 + memcpy((unsigned char*)keyChild.begin(), begin(), 32); + bool ret = secp256k1_ecdsa_privkey_tweak_add((unsigned char*)keyChild.begin(), out); +#else bool ret = CECKey::TweakSecret((unsigned char*)keyChild.begin(), begin(), out); +#endif UnlockObject(out); keyChild.fCompressed = true; keyChild.fValid = ret; @@ -531,10 +644,15 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned i unsigned char out[64]; BIP32Hash(cc, nChild, *begin(), begin()+1, out); memcpy(ccChild, out+32, 32); +#ifdef USE_SECP256K1 + pubkeyChild = *this; + bool ret = secp256k1_ecdsa_pubkey_tweak_add((unsigned char*)pubkeyChild.begin(), pubkeyChild.size(), out); +#else CECKey key; bool ret = key.SetPubKey(*this); ret &= key.TweakPublic(out); key.GetPubKey(pubkeyChild, true); +#endif return ret; } @@ -547,13 +665,10 @@ bool CExtKey::Derive(CExtKey &out, unsigned int nChild) const { } 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); + static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'}; unsigned char out[64]; LockObject(out); - HMAC_SHA512_Final(out, &ctx); + CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(out); key.Set(&out[0], &out[32], true); memcpy(vchChainCode, &out[32], 32); UnlockObject(out); @@ -616,3 +731,19 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const { out.nChild = nChild; return pubkey.Derive(out.pubkey, out.vchChainCode, nChild, vchChainCode); } + +bool ECC_InitSanityCheck() { +#ifdef USE_SECP256K1 + return true; +#else + 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; +#endif +} + + |