X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fkey.h;h=2d8e61850f1d77e041e36c8b2e26bc1980f0dd0f;hp=9673b2a0bca26a3dbde576f4571ed3995728bd33;hb=6aba6f08af53e3fa49ab4d1ef002e6771d0ce358;hpb=ddd0d9ae54e52a299589c3655b5b2afc7c2bfd5e diff --git a/src/key.h b/src/key.h index 9673b2a..2d8e618 100644 --- a/src/key.h +++ b/src/key.h @@ -1,20 +1,21 @@ // 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. +// 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 "base58.h" +#include "hash.h" +#include "bignum.h" +#include "ies.h" + +#include // for EC_KEY definition // secp160k1 // const unsigned int PRIVATE_KEY_SIZE = 192; @@ -39,365 +40,309 @@ // see www.keylength.com // script supports up to 75 for single byte push -// Generate a private key from just the secret parameter -int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) +class key_error : public std::runtime_error { - int ok = 0; - BN_CTX *ctx = NULL; - EC_POINT *pub_key = NULL; - - if (!eckey) return 0; - - const EC_GROUP *group = EC_KEY_get0_group(eckey); - - if ((ctx = BN_CTX_new()) == NULL) - goto err; - - pub_key = EC_POINT_new(group); - - if (pub_key == NULL) - goto err; +public: + explicit key_error(const std::string& str) : std::runtime_error(str) {} +}; - if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) - goto err; +/** 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) { } +}; - EC_KEY_set_private_key(eckey,priv_key); - EC_KEY_set_public_key(eckey,pub_key); +/** 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) { } +}; - ok = 1; +/** An encapsulated public key. */ +class CPubKey { +private: + std::vector vchPubKey; + friend class CKey; -err: +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)); + } - if (pub_key) - EC_POINT_free(pub_key); - if (ctx != NULL) - BN_CTX_free(ctx); + uint256 GetHash() const { + return Hash(vchPubKey.begin(), vchPubKey.end()); + } - return(ok); -} + bool IsValid() const { + return vchPubKey.size() == 33 || vchPubKey.size() == 65; + } -// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields -// recid selects which key is recovered -// if check is nonzero, additional checks are performed -int static inline ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) -{ - if (!eckey) return 0; - - int ret = 0; - BN_CTX *ctx = NULL; - - BIGNUM *x = NULL; - BIGNUM *e = NULL; - BIGNUM *order = NULL; - BIGNUM *sor = NULL; - BIGNUM *eor = NULL; - BIGNUM *field = NULL; - EC_POINT *R = NULL; - EC_POINT *O = NULL; - EC_POINT *Q = NULL; - BIGNUM *rr = NULL; - BIGNUM *zero = NULL; - int n = 0; - int i = recid / 2; - - const EC_GROUP *group = EC_KEY_get0_group(eckey); - if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } - BN_CTX_start(ctx); - order = BN_CTX_get(ctx); - if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } - x = BN_CTX_get(ctx); - if (!BN_copy(x, order)) { ret=-1; goto err; } - if (!BN_mul_word(x, i)) { ret=-1; goto err; } - if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } - field = BN_CTX_get(ctx); - if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } - if (BN_cmp(x, field) >= 0) { ret=0; goto err; } - if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } - if (check) - { - if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } - if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } + bool IsCompressed() const { + return vchPubKey.size() == 33; } - if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - n = EC_GROUP_get_degree(group); - e = BN_CTX_get(ctx); - if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } - if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); - zero = BN_CTX_get(ctx); - if (!BN_zero(zero)) { ret=-1; goto err; } - if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } - rr = BN_CTX_get(ctx); - if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } - sor = BN_CTX_get(ctx); - if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } - eor = BN_CTX_get(ctx); - if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } - if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } - if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } - - ret = 1; - -err: - if (ctx) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); + + std::vector Raw() const { + return vchPubKey; } - if (R != NULL) EC_POINT_free(R); - if (O != NULL) EC_POINT_free(O); - if (Q != NULL) EC_POINT_free(Q); - return ret; -} -class key_error : public std::runtime_error -{ -public: - explicit key_error(const std::string& str) : std::runtime_error(str) {} + // Encrypt data + void EncryptData(const std::vector& data, std::vector& encrypted); }; -// secure_allocator is defined in serialize.h +// 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: EC_KEY* pkey; bool fSet; + bool fCompressedPubKey; - void SetCompressedPubKey() - { - EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); - } + void SetCompressedPubKey(); public: - CKey() - { - 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(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; - } + void Reset(); - 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(const CKey& b); + CKey(const CSecret& b, bool fCompressed=true); - ~CKey() - { - EC_KEY_free(pkey); - } + CKey& operator=(const CKey& b); - bool IsNull() const - { - return !fSet; - } + ~CKey(); - void MakeNewKey() - { - if (!EC_KEY_generate_key(pkey)) - throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); - fSet = true; - } + bool IsNull() const; + bool IsCompressed() const; - bool SetPrivKey(const CPrivKey& vchPrivKey) - { - const unsigned char* pbegin = &vchPrivKey[0]; - if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) - return false; - fSet = true; - return true; - } + 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 SetSecret(const CSecret& vchSecret) - { - 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)) - throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); - BN_clear_free(bn); - fSet = true; - return true; - } + bool Sign(uint256 hash, std::vector& vchSig); - CSecret GetSecret() 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"); - return vchRet; - } + // 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); - 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; - } + // 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 Verify(uint256 hash, const std::vector& vchSig); + + // Verify a compact signature + bool VerifyCompact(uint256 hash, const std::vector& vchSig); + + 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); - bool SetPubKey(const std::vector& vchPubKey) + // Initialize from pubkey + bool setPubKey(const CPubKey &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; - return true; + pubKeyL = mpk.pubKeyL; + pubKeyH = mpk.pubKeyH; } + CMalleablePubKey(const std::vector &vchPubKeyPair) { setvch(vchPubKeyPair); } + 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) - { - vchSig.clear(); - unsigned char pchSig[10000]; - unsigned int nSize = 0; - if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey)) - return false; - vchSig.resize(nSize); - memcpy(&vchSig[0], pchSig, nSize); - 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 (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; - 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; } - // Get the address corresponding to this key - CBitcoinAddress GetAddress() const - { - return CBitcoinAddress(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