X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fkey.h;h=bc7e2ab59a518efc190bfb04100ca4e7202254ef;hp=a57143b7d91260bff4ce723a39ca464cc7700292;hb=75744e6526193604bfbcc6be3a3793315556f12c;hpb=a09f101f147f2313bc727371f8f1e44dc886d330 diff --git a/src/key.h b/src/key.h index a57143b..bc7e2ab 100644 --- a/src/key.h +++ b/src/key.h @@ -1,19 +1,21 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // 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. +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_KEY_H #define BITCOIN_KEY_H #include #include -#include -#include -#include - +#include "allocators.h" #include "serialize.h" #include "uint256.h" +#include "hash.h" +#include "bignum.h" +#include "ies.h" + +#include // for EC_KEY definition // secp160k1 // const unsigned int PRIVATE_KEY_SIZE = 192; @@ -38,22 +40,77 @@ // see www.keylength.com // script supports up to 75 for single byte push -int extern EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key); -int extern ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check); - class key_error : public std::runtime_error { public: explicit key_error(const std::string& str) : std::runtime_error(str) {} }; +/** A reference to a CKey: the Hash160 of its serialized public key */ +class CKeyID : public uint160 +{ +public: + CKeyID() : uint160(0) { } + CKeyID(const uint160 &in) : uint160(in) { } +}; -// secure_allocator is defined in serialize.h +/** A reference to a CScript: the Hash160 of its serialization (see script.h) */ +class CScriptID : public uint160 +{ +public: + CScriptID() : uint160(0) { } + CScriptID(const uint160 &in) : uint160(in) { } +}; + +/** An encapsulated public key. */ +class CPubKey { +private: + std::vector vchPubKey; + friend class CKey; + +public: + CPubKey() { } + CPubKey(const std::vector &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { } + friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; } + friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; } + friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; } + + IMPLEMENT_SERIALIZE( + READWRITE(vchPubKey); + ) + + CKeyID GetID() const { + return CKeyID(Hash160(vchPubKey)); + } + + uint256 GetHash() const { + return Hash(vchPubKey.begin(), vchPubKey.end()); + } + + bool IsValid() const { + return vchPubKey.size() == 33 || vchPubKey.size() == 65; + } + + bool IsCompressed() const { + return vchPubKey.size() == 33; + } + + std::vector Raw() const { + return vchPubKey; + } + + // Encrypt data + void EncryptData(const std::vector& data, std::vector& encrypted); +}; + + +// secure_allocator is defined in allocators.h // CPrivKey is a serialized private key, with all parameters included (279 bytes) typedef std::vector > CPrivKey; // CSecret is a serialization of just the secret parameter (32 bytes) typedef std::vector > CSecret; +/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */ class CKey { protected: @@ -61,267 +118,230 @@ protected: bool fSet; bool fCompressedPubKey; - void SetCompressedPubKey() - { - EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); - fCompressedPubKey = true; - } + void SetCompressedPubKey(); public: - 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; - } + void Reset(); - CKey() - { - Reset(); - } + CKey(); + CKey(const CKey& b); + CKey(const CSecret& b, bool fCompressed=true); - CKey(const CKey& b) - { - pkey = EC_KEY_dup(b.pkey); - if (pkey == NULL) - throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); - fSet = b.fSet; - } + CKey& operator=(const CKey& b); - CKey& operator=(const CKey& b) - { - if (!EC_KEY_copy(pkey, b.pkey)) - throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); - fSet = b.fSet; - return (*this); - } + ~CKey(); - ~CKey() - { - EC_KEY_free(pkey); - } + bool IsNull() const; + bool IsCompressed() const; - bool IsNull() const - { - return !fSet; - } + void MakeNewKey(bool fCompressed=true); + bool SetPrivKey(const CPrivKey& vchPrivKey); + bool SetSecret(const CSecret& vchSecret, bool fCompressed = true); + CSecret GetSecret(bool &fCompressed) const; + CSecret GetSecret() const; + CPrivKey GetPrivKey() const; + bool SetPubKey(const CPubKey& vchPubKey); + CPubKey GetPubKey() const; - bool IsCompressed() const - { - return fCompressedPubKey; - } + bool Sign(uint256 hash, std::vector& vchSig); - 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; - } + // create a compact signature (65 bytes), which allows reconstructing the used public key + // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. + // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, + // 0x1D = second key with even y, 0x1E = second key with odd y + bool SignCompact(uint256 hash, std::vector& vchSig); - bool SetPrivKey(const CPrivKey& vchPrivKey) - { - const unsigned char* pbegin = &vchPrivKey[0]; - if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) - return false; - fSet = true; - return true; - } + // reconstruct public key from a compact signature + // This is only slightly more CPU intensive than just verifying it. + // If this function succeeds, the recovered public key is guaranteed to be valid + // (the signature is a valid signature of the given data for that key) + bool SetCompactSignature(uint256 hash, const std::vector& vchSig); - bool SetSecret(const CSecret& vchSecret, bool fCompressed = false) - { - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (pkey == NULL) - throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); - 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) - 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; - } + bool Verify(uint256 hash, const std::vector& vchSig); - CSecret GetSecret(bool &fCompressed) const - { - CSecret vchRet; - vchRet.resize(32); - const BIGNUM *bn = EC_KEY_get0_private_key(pkey); - int nBytes = BN_num_bytes(bn); - if (bn == NULL) - throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed"); - int n=BN_bn2bin(bn,&vchRet[32 - nBytes]); - if (n != nBytes) - throw key_error("CKey::GetSecret(): BN_bn2bin failed"); - fCompressed = fCompressedPubKey; - return vchRet; - } + // Verify a compact signature + bool VerifyCompact(uint256 hash, const std::vector& vchSig); - CPrivKey GetPrivKey() const - { - unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); - CPrivKey vchPrivKey(nSize, 0); - unsigned char* pbegin = &vchPrivKey[0]; - if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); - return vchPrivKey; - } + bool IsValid(); + + // Check whether an element of a signature (r or s) is valid. + static bool CheckSignatureElement(const unsigned char *vch, int len, bool half); + + // Reserialize to DER + static bool ReserealizeSignature(std::vector& vchSig); + + // Encrypt data + void EncryptData(const std::vector& data, std::vector& encrypted); + + // Decrypt data + void DecryptData(const std::vector& encrypted, std::vector& data); +}; + +class CPoint +{ +private: + EC_POINT *point; + EC_GROUP* group; + BN_CTX* ctx; + +public: + CPoint(); + bool operator!=(const CPoint &a); + ~CPoint(); + + // Initialize from octets stream + bool setBytes(const std::vector &vchBytes); + + // Initialize from pubkey + bool setPubKey(const CPubKey &vchPubKey); - bool SetPubKey(const std::vector& vchPubKey) + // Serialize to octets stream + bool getBytes(std::vector &vchBytes); + + // ECC multiplication by specified multiplier + bool ECMUL(const CBigNum &bnMultiplier); + + // Calculate G*m + q + bool ECMULGEN(const CBigNum &bnMultiplier, const CPoint &qPoint); + + bool IsInfinity() { return EC_POINT_is_at_infinity(group, point) != 0; } +}; + +class CMalleablePubKey +{ +private: + CPubKey pubKeyL; + CPubKey pubKeyH; + friend class CMalleableKey; + + static const unsigned char CURRENT_VERSION = 1; + +public: + CMalleablePubKey() { } + CMalleablePubKey(const CMalleablePubKey& mpk) { - const unsigned char* pbegin = &vchPubKey[0]; - if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) - return false; - fSet = true; - if (vchPubKey.size() == 33) - SetCompressedPubKey(); - return true; + pubKeyL = mpk.pubKeyL; + pubKeyH = mpk.pubKeyH; } + CMalleablePubKey(const std::string& strMalleablePubKey) { SetString(strMalleablePubKey); } + CMalleablePubKey(const CPubKey &pubKeyInL, const CPubKey &pubKeyInH) : pubKeyL(pubKeyInL), pubKeyH(pubKeyInH) { } - std::vector GetPubKey() const - { - unsigned int nSize = i2o_ECPublicKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); - std::vector vchPubKey(nSize, 0); - unsigned char* pbegin = &vchPubKey[0]; - if (i2o_ECPublicKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); - return vchPubKey; + IMPLEMENT_SERIALIZE( + READWRITE(pubKeyL); + READWRITE(pubKeyH); + ) + + bool IsValid() const { + return pubKeyL.IsValid() && pubKeyH.IsValid(); } - bool Sign(uint256 hash, std::vector& vchSig) - { - 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); // Shrink to fit actual size - return true; + bool operator==(const CMalleablePubKey &b); + bool operator!=(const CMalleablePubKey &b) { return !(*this == b); } + CMalleablePubKey& operator=(const CMalleablePubKey& mpk) { + pubKeyL = mpk.pubKeyL; + pubKeyH = mpk.pubKeyH; + return *this; } - // create a compact signature (65 bytes), which allows reconstructing the used public key - // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. - // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, - // 0x1D = second key with even y, 0x1E = second key with odd y - bool SignCompact(uint256 hash, std::vector& vchSig) - { - bool fOk = false; - ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); - if (sig==NULL) - return false; - vchSig.clear(); - vchSig.resize(65,0); - int nBitsR = BN_num_bits(sig->r); - int nBitsS = BN_num_bits(sig->s); - if (nBitsR <= 256 && nBitsS <= 256) - { - int nRecId = -1; - for (int i=0; i<4; i++) - { - 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()) - { - nRecId = i; - break; - } - } - - if (nRecId == -1) - throw key_error("CKey::SignCompact() : unable to construct recoverable key"); - - 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; - } - ECDSA_SIG_free(sig); - return fOk; + std::string ToString() const; + bool SetString(const std::string& strMalleablePubKey); + + CKeyID GetID() const { + return pubKeyL.GetID(); } - // reconstruct public key from a compact signature - // This is only slightly more CPU intensive than just verifying it. - // If this function succeeds, the recovered public key is guaranteed to be valid - // (the signature is a valid signature of the given data for that key) - bool SetCompactSignature(uint256 hash, const std::vector& vchSig) - { - if (vchSig.size() != 65) - return false; - 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 (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 true; - } - return false; + bool setvch(const std::vector &vchPubKeyPair); + std::vector Raw() const; + + CPubKey& GetL() { return pubKeyL; } + CPubKey& GetH() { return pubKeyH; } + void GetVariant(CPubKey &R, CPubKey &vchPubKeyVariant); +}; + +class CMalleableKey +{ +private: + CSecret vchSecretL; + CSecret vchSecretH; + + friend class CMalleableKeyView; + +public: + CMalleableKey(); + CMalleableKey(const CMalleableKey &b); + CMalleableKey(const CSecret &L, const CSecret &H); + ~CMalleableKey(); + + IMPLEMENT_SERIALIZE( + READWRITE(vchSecretL); + READWRITE(vchSecretH); + ) + + std::string ToString() const; + bool SetString(const std::string& strMalleablePubKey); + std::vector Raw() const; + CMalleableKey& operator=(const CMalleableKey& mk) { + vchSecretL = mk.vchSecretL; + vchSecretH = mk.vchSecretH; + return *this; } - bool Verify(uint256 hash, const std::vector& vchSig) - { - // -1 = error, 0 = bad sig, 1 = good - if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) - return false; - return true; + void Reset(); + void MakeNewKeys(); + bool IsNull() const; + bool IsValid() const { return !IsNull() && GetMalleablePubKey().IsValid(); } + bool SetSecrets(const CSecret &pvchSecretL, const CSecret &pvchSecretH); + + CSecret GetSecretL() const { return vchSecretL; } + CSecret GetSecretH() const { return vchSecretH; } + + CKeyID GetID() const { + return GetMalleablePubKey().GetID(); } + CMalleablePubKey GetMalleablePubKey() const; + bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const; + bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant, CKey &privKeyVariant) const; +}; - // Verify a compact signature - bool VerifyCompact(uint256 hash, const std::vector& vchSig) - { - CKey key; - if (!key.SetCompactSignature(hash, vchSig)) - return false; - if (GetPubKey() != key.GetPubKey()) - return false; - return true; +class CMalleableKeyView +{ +private: + CSecret vchSecretL; + CPubKey vchPubKeyH; + +public: + CMalleableKeyView() { }; + CMalleableKeyView(const CMalleableKey &b); + CMalleableKeyView(const std::string &strMalleableKey); + + CMalleableKeyView(const CMalleableKeyView &b); + CMalleableKeyView& operator=(const CMalleableKey &b); + ~CMalleableKeyView(); + + IMPLEMENT_SERIALIZE( + READWRITE(vchSecretL); + READWRITE(vchPubKeyH); + ) + + bool IsValid() const; + std::string ToString() const; + bool SetString(const std::string& strMalleablePubKey); + std::vector Raw() const; + CMalleableKeyView& operator=(const CMalleableKeyView& mkv) { + vchSecretL = mkv.vchSecretL; + vchPubKeyH = mkv.vchPubKeyH; + return *this; } - bool IsValid() - { - if (!fSet) - return false; - - bool fCompr; - CSecret secret = GetSecret(fCompr); - CKey key2; - key2.SetSecret(secret, fCompr); - return GetPubKey() == key2.GetPubKey(); + CKeyID GetID() const { + return GetMalleablePubKey().GetID(); } + CMalleablePubKey GetMalleablePubKey() const; + CMalleableKey GetMalleableKey(const CSecret &vchSecretH) const { return CMalleableKey(vchSecretL, vchSecretH); } + bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const; + + bool operator <(const CMalleableKeyView& kv) const { return vchPubKeyH.GetID() < kv.vchPubKeyH.GetID(); } }; #endif