diff --git a/src/keystore.cpp b/src/keystore.cpp index 4eee90a55..19c14605f 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -1,175 +1,175 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include bool CKeyStore::AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); } void CBasicKeyStore::ImplicitlyLearnRelatedKeyScripts(const CPubKey &pubkey) { AssertLockHeld(cs_KeyStore); CKeyID key_id = pubkey.GetID(); // We must actually know about this key already. assert(HaveKey(key_id) || mapWatchKeys.count(key_id)); // This adds the redeemscripts necessary to detect alternative outputs using // the same keys. Also note that having superfluous scripts in the keystore // never hurts. They're only used to guide recursion in signing and IsMine // logic - if a script is present but we can't do anything with it, it has // no effect. "Implicitly" refers to fact that scripts are derived // automatically from existing keys, and are present in memory, even without // being explicitly loaded (e.g. from a file). // Right now there are none so do nothing. } bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const { CKey key; if (!GetKey(address, key)) { LOCK(cs_KeyStore); WatchKeyMap::const_iterator it = mapWatchKeys.find(address); if (it != mapWatchKeys.end()) { vchPubKeyOut = it->second; return true; } return false; } vchPubKeyOut = key.GetPubKey(); return true; } bool CBasicKeyStore::AddKeyPubKey(const CKey &key, const CPubKey &pubkey) { LOCK(cs_KeyStore); mapKeys[pubkey.GetID()] = key; ImplicitlyLearnRelatedKeyScripts(pubkey); return true; } bool CBasicKeyStore::HaveKey(const CKeyID &address) const { LOCK(cs_KeyStore); return mapKeys.count(address) > 0; } std::set CBasicKeyStore::GetKeys() const { LOCK(cs_KeyStore); std::set set_address; for (const auto &mi : mapKeys) { set_address.insert(mi.first); } return set_address; } bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const { LOCK(cs_KeyStore); KeyMap::const_iterator mi = mapKeys.find(address); if (mi != mapKeys.end()) { keyOut = mi->second; return true; } return false; } bool CBasicKeyStore::AddCScript(const CScript &redeemScript) { if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { return error("CBasicKeyStore::AddCScript(): redeemScripts > %i bytes " "are invalid", MAX_SCRIPT_ELEMENT_SIZE); } LOCK(cs_KeyStore); mapScripts[CScriptID(redeemScript)] = redeemScript; return true; } bool CBasicKeyStore::HaveCScript(const CScriptID &hash) const { LOCK(cs_KeyStore); return mapScripts.count(hash) > 0; } std::set CBasicKeyStore::GetCScripts() const { LOCK(cs_KeyStore); std::set set_script; for (const auto &mi : mapScripts) { set_script.insert(mi.first); } return set_script; } bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const { LOCK(cs_KeyStore); ScriptMap::const_iterator mi = mapScripts.find(hash); if (mi != mapScripts.end()) { redeemScriptOut = (*mi).second; return true; } return false; } static bool ExtractPubKey(const CScript &dest, CPubKey &pubKeyOut) { // TODO: Use Solver to extract this? CScript::const_iterator pc = dest.begin(); opcodetype opcode; std::vector vch; - if (!dest.GetOp(pc, opcode, vch) || vch.size() < 33 || vch.size() > 65) { + if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch)) { return false; } pubKeyOut = CPubKey(vch); if (!pubKeyOut.IsFullyValid()) { return false; } if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch)) { return false; } return true; } bool CBasicKeyStore::AddWatchOnly(const CScript &dest) { LOCK(cs_KeyStore); setWatchOnly.insert(dest); CPubKey pubKey; if (ExtractPubKey(dest, pubKey)) { mapWatchKeys[pubKey.GetID()] = pubKey; ImplicitlyLearnRelatedKeyScripts(pubKey); } return true; } bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest) { LOCK(cs_KeyStore); setWatchOnly.erase(dest); CPubKey pubKey; if (ExtractPubKey(dest, pubKey)) { mapWatchKeys.erase(pubKey.GetID()); } // Related CScripts are not removed; having superfluous scripts around is // harmless (see comment in ImplicitlyLearnRelatedKeyScripts). return true; } bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const { LOCK(cs_KeyStore); return setWatchOnly.count(dest) > 0; } bool CBasicKeyStore::HaveWatchOnly() const { LOCK(cs_KeyStore); return (!setWatchOnly.empty()); } CKeyID GetKeyForDestination(const CKeyStore &store, const CTxDestination &dest) { // Only supports destinations which map to single public keys, i.e. P2PKH. if (auto id = boost::get(&dest)) { return *id; } return CKeyID(); } diff --git a/src/pubkey.h b/src/pubkey.h index 599aad7c1..e468b7179 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -1,240 +1,244 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_PUBKEY_H #define BITCOIN_PUBKEY_H #include #include #include #include #include #include const unsigned int BIP32_EXTKEY_SIZE = 74; /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { public: CKeyID() : uint160() {} explicit CKeyID(const uint160 &in) : uint160(in) {} }; typedef uint256 ChainCode; /** An encapsulated public key. */ class CPubKey { public: /** * secp256k1: */ static const unsigned int PUBLIC_KEY_SIZE = 65; static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33; static const unsigned int SIGNATURE_SIZE = 72; static const unsigned int COMPACT_SIGNATURE_SIZE = 65; /** * see www.keylength.com * script supports up to 75 for single byte push */ static_assert(PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE, "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE"); private: /** * Just store the serialized data. * Its length can very cheaply be computed from the first byte. */ uint8_t vch[PUBLIC_KEY_SIZE]; //! Compute the length of a pubkey with a given first byte. static unsigned int GetLen(uint8_t chHeader) { if (chHeader == 2 || chHeader == 3) { return COMPRESSED_PUBLIC_KEY_SIZE; } if (chHeader == 4 || chHeader == 6 || chHeader == 7) { return PUBLIC_KEY_SIZE; } return 0; } //! Set this key data to be invalid void Invalidate() { vch[0] = 0xFF; } public: + bool static ValidSize(const std::vector &vch) { + return vch.size() > 0 && GetLen(vch[0]) == vch.size(); + } + //! Construct an invalid public key. CPubKey() { Invalidate(); } //! Initialize a public key using begin/end iterators to byte data. template void Set(const T pbegin, const T pend) { int len = pend == pbegin ? 0 : GetLen(pbegin[0]); if (len && len == (pend - pbegin)) { memcpy(vch, (uint8_t *)&pbegin[0], len); } else { Invalidate(); } } //! Construct a public key using begin/end iterators to byte data. template CPubKey(const T pbegin, const T pend) { Set(pbegin, pend); } //! Construct a public key from a byte vector. explicit CPubKey(const std::vector &_vch) { Set(_vch.begin(), _vch.end()); } //! Simple read-only vector-like interface to the pubkey data. unsigned int size() const { return GetLen(vch[0]); } const uint8_t *begin() const { return vch; } const uint8_t *end() const { return vch + size(); } const uint8_t &operator[](unsigned int pos) const { return vch[pos]; } //! Comparator implementation. friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) == 0; } friend bool operator!=(const CPubKey &a, const CPubKey &b) { return !(a == b); } friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vch[0] < b.vch[0] || (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0); } //! Implement serialization, as if this was a byte vector. template void Serialize(Stream &s) const { unsigned int len = size(); ::WriteCompactSize(s, len); s.write((char *)vch, len); } template void Unserialize(Stream &s) { unsigned int len = ::ReadCompactSize(s); if (len <= PUBLIC_KEY_SIZE) { s.read((char *)vch, len); } else { // invalid pubkey, skip available data char dummy; while (len--) { s.read(&dummy, 1); } Invalidate(); } } //! Get the KeyID of this public key (hash of its serialization) CKeyID GetID() const { return CKeyID(Hash160(vch, vch + size())); } //! Get the 256-bit hash of this public key. uint256 GetHash() const { return Hash(vch, vch + size()); } /* * Check syntactic correctness. * * Note that this is consensus critical as CheckSig() calls it! */ bool IsValid() const { return size() > 0; } //! fully validate whether this is a valid public key (more expensive than //! IsValid()) bool IsFullyValid() const; //! Check whether this is a compressed public key. bool IsCompressed() const { return size() == COMPRESSED_PUBLIC_KEY_SIZE; } /** * Verify a DER-serialized ECDSA signature (~72 bytes). * If this public key is not fully valid, the return value will be false. */ bool VerifyECDSA(const uint256 &hash, const std::vector &vchSig) const; /** * Verify a Schnorr signature (=64 bytes). * If this public key is not fully valid, the return value will be false. */ bool VerifySchnorr(const uint256 &hash, const std::vector &vchSig) const; /** * Check whether a DER-serialized ECDSA signature is normalized (lower-S). */ static bool CheckLowS(const boost::sliced_range> &vchSig); static bool CheckLowS(const std::vector &vchSig) { return CheckLowS(vchSig | boost::adaptors::sliced(0, vchSig.size())); } //! Recover a public key from a compact ECDSA signature. bool RecoverCompact(const uint256 &hash, const std::vector &vchSig); //! Turn this public key into an uncompressed public key. bool Decompress(); //! Derive BIP32 child pubkey. bool Derive(CPubKey &pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode &cc) const; }; struct CExtPubKey { uint8_t nDepth; uint8_t vchFingerprint[4]; unsigned int nChild; ChainCode chaincode; CPubKey pubkey; friend bool operator==(const CExtPubKey &a, const CExtPubKey &b) { return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && a.nChild == b.nChild && a.chaincode == b.chaincode && a.pubkey == b.pubkey; } void Encode(uint8_t code[BIP32_EXTKEY_SIZE]) const; void Decode(const uint8_t code[BIP32_EXTKEY_SIZE]); bool Derive(CExtPubKey &out, unsigned int nChild) const; void Serialize(CSizeComputer &s) const { // Optimized implementation for ::GetSerializeSize that avoids copying. // add one byte for the size (compact int) s.seek(BIP32_EXTKEY_SIZE + 1); } template void Serialize(Stream &s) const { unsigned int len = BIP32_EXTKEY_SIZE; ::WriteCompactSize(s, len); uint8_t code[BIP32_EXTKEY_SIZE]; Encode(code); s.write((const char *)&code[0], len); } template void Unserialize(Stream &s) { unsigned int len = ::ReadCompactSize(s); if (len != BIP32_EXTKEY_SIZE) { throw std::runtime_error("Invalid extended key size\n"); } uint8_t code[BIP32_EXTKEY_SIZE]; s.read((char *)&code[0], len); Decode(code); } }; /** * Users of this module must hold an ECCVerifyHandle. The constructor and * destructor of these are not allowed to run in parallel, though. */ class ECCVerifyHandle { static int refcount; public: ECCVerifyHandle(); ~ECCVerifyHandle(); }; #endif // BITCOIN_PUBKEY_H diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp index 49270c9f5..7789a9f04 100644 --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -1,330 +1,330 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include