diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/descriptor.h | 1 | ||||
-rw-r--r-- | src/script/keyorigin.h | 37 | ||||
-rw-r--r-- | src/script/sign.cpp | 60 | ||||
-rw-r--r-- | src/script/sign.h | 70 | ||||
-rw-r--r-- | src/script/signingprovider.cpp | 199 | ||||
-rw-r--r-- | src/script/signingprovider.h | 92 | ||||
-rw-r--r-- | src/script/standard.cpp | 1 |
7 files changed, 332 insertions, 128 deletions
diff --git a/src/script/descriptor.h b/src/script/descriptor.h index af7ae229ca..29915c6c92 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -7,6 +7,7 @@ #include <script/script.h> #include <script/sign.h> +#include <script/signingprovider.h> #include <vector> diff --git a/src/script/keyorigin.h b/src/script/keyorigin.h new file mode 100644 index 0000000000..610f233500 --- /dev/null +++ b/src/script/keyorigin.h @@ -0,0 +1,37 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SCRIPT_KEYORIGIN_H +#define BITCOIN_SCRIPT_KEYORIGIN_H + +#include <serialize.h> +#include <streams.h> +#include <vector> + +struct KeyOriginInfo +{ + unsigned char fingerprint[4]; //!< First 32 bits of the Hash160 of the public key at the root of the path + std::vector<uint32_t> path; + + friend bool operator==(const KeyOriginInfo& a, const KeyOriginInfo& b) + { + return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path; + } + + ADD_SERIALIZE_METHODS; + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITE(fingerprint); + READWRITE(path); + } + + void clear() + { + memset(fingerprint, 0, 4); + path.clear(); + } +}; + +#endif // BITCOIN_SCRIPT_KEYORIGIN_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 5320dc0876..13481af9c5 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -8,6 +8,7 @@ #include <key.h> #include <policy/policy.h> #include <primitives/transaction.h> +#include <script/signingprovider.h> #include <script/standard.h> #include <uint256.h> @@ -423,22 +424,10 @@ public: } }; -template<typename M, typename K, typename V> -bool LookupHelper(const M& map, const K& key, V& value) -{ - auto it = map.find(key); - if (it != map.end()) { - value = it->second; - return true; - } - return false; -} - } const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32); const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32); -const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider(); bool IsSolvable(const SigningProvider& provider, const CScript& script) { @@ -459,53 +448,6 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script) return false; } -bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const -{ - return m_provider->GetCScript(scriptid, script); -} - -bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const -{ - return m_provider->GetPubKey(keyid, pubkey); -} - -bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const -{ - if (m_hide_secret) return false; - return m_provider->GetKey(keyid, key); -} - -bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const -{ - if (m_hide_origin) return false; - return m_provider->GetKeyOrigin(keyid, info); -} - -bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); } -bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); } -bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const -{ - std::pair<CPubKey, KeyOriginInfo> out; - bool ret = LookupHelper(origins, keyid, out); - if (ret) info = std::move(out.second); - return ret; -} -bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); } - -FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b) -{ - FlatSigningProvider ret; - ret.scripts = a.scripts; - ret.scripts.insert(b.scripts.begin(), b.scripts.end()); - ret.pubkeys = a.pubkeys; - ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end()); - ret.keys = a.keys; - ret.keys.insert(b.keys.begin(), b.keys.end()); - ret.origins = a.origins; - ret.origins.insert(b.origins.begin(), b.origins.end()); - return ret; -} - bool IsSegWitOutput(const SigningProvider& provider, const CScript& script) { std::vector<valtype> solutions; diff --git a/src/script/sign.h b/src/script/sign.h index e5c0329a61..0e751afd3b 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -10,6 +10,7 @@ #include <hash.h> #include <pubkey.h> #include <script/interpreter.h> +#include <script/keyorigin.h> #include <streams.h> class CKey; @@ -17,77 +18,10 @@ class CKeyID; class CScript; class CScriptID; class CTransaction; +class SigningProvider; struct CMutableTransaction; -struct KeyOriginInfo -{ - unsigned char fingerprint[4]; //!< First 32 bits of the Hash160 of the public key at the root of the path - std::vector<uint32_t> path; - - friend bool operator==(const KeyOriginInfo& a, const KeyOriginInfo& b) - { - return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path; - } - - ADD_SERIALIZE_METHODS; - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(fingerprint); - READWRITE(path); - } - - void clear() - { - memset(fingerprint, 0, 4); - path.clear(); - } -}; - -/** An interface to be implemented by keystores that support signing. */ -class SigningProvider -{ -public: - virtual ~SigningProvider() {} - virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; } - virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; } - virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; } - virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; } -}; - -extern const SigningProvider& DUMMY_SIGNING_PROVIDER; - -class HidingSigningProvider : public SigningProvider -{ -private: - const bool m_hide_secret; - const bool m_hide_origin; - const SigningProvider* m_provider; - -public: - HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {} - bool GetCScript(const CScriptID& scriptid, CScript& script) const override; - bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; - bool GetKey(const CKeyID& keyid, CKey& key) const override; - bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; -}; - -struct FlatSigningProvider final : public SigningProvider -{ - std::map<CScriptID, CScript> scripts; - std::map<CKeyID, CPubKey> pubkeys; - std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins; - std::map<CKeyID, CKey> keys; - - bool GetCScript(const CScriptID& scriptid, CScript& script) const override; - bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; - bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; - bool GetKey(const CKeyID& keyid, CKey& key) const override; -}; - -FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b); - /** Interface for signature creators. */ class BaseSignatureCreator { public: diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp new file mode 100644 index 0000000000..01757e2f65 --- /dev/null +++ b/src/script/signingprovider.cpp @@ -0,0 +1,199 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2019 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 <script/keyorigin.h> +#include <script/signingprovider.h> +#include <script/standard.h> + +#include <util/system.h> + +const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider(); + +template<typename M, typename K, typename V> +bool LookupHelper(const M& map, const K& key, V& value) +{ + auto it = map.find(key); + if (it != map.end()) { + value = it->second; + return true; + } + return false; +} + +bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const +{ + return m_provider->GetCScript(scriptid, script); +} + +bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const +{ + return m_provider->GetPubKey(keyid, pubkey); +} + +bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const +{ + if (m_hide_secret) return false; + return m_provider->GetKey(keyid, key); +} + +bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const +{ + if (m_hide_origin) return false; + return m_provider->GetKeyOrigin(keyid, info); +} + +bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); } +bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); } +bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const +{ + std::pair<CPubKey, KeyOriginInfo> out; + bool ret = LookupHelper(origins, keyid, out); + if (ret) info = std::move(out.second); + return ret; +} +bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); } + +FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b) +{ + FlatSigningProvider ret; + ret.scripts = a.scripts; + ret.scripts.insert(b.scripts.begin(), b.scripts.end()); + ret.pubkeys = a.pubkeys; + ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end()); + ret.keys = a.keys; + ret.keys.insert(b.keys.begin(), b.keys.end()); + ret.origins = a.origins; + ret.origins.insert(b.origins.begin(), b.origins.end()); + return ret; +} + +void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) +{ + AssertLockHeld(cs_KeyStore); + CKeyID key_id = pubkey.GetID(); + // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH + // outputs. Technically P2WPKH outputs don't have a redeemscript to be + // spent. However, our current IsMine logic requires the corresponding + // P2SH-P2WPKH redeemscript to be present in the wallet in order to accept + // payment even to P2WPKH outputs. + // 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). + if (pubkey.IsCompressed()) { + CScript script = GetScriptForDestination(WitnessV0KeyHash(key_id)); + // This does not use AddCScript, as it may be overridden. + CScriptID id(script); + mapScripts[id] = std::move(script); + } +} + +bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const +{ + CKey key; + if (!GetKey(address, key)) { + return false; + } + vchPubKeyOut = key.GetPubKey(); + return true; +} + +bool FillableSigningProvider::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) +{ + LOCK(cs_KeyStore); + mapKeys[pubkey.GetID()] = key; + ImplicitlyLearnRelatedKeyScripts(pubkey); + return true; +} + +bool FillableSigningProvider::HaveKey(const CKeyID &address) const +{ + LOCK(cs_KeyStore); + return mapKeys.count(address) > 0; +} + +std::set<CKeyID> FillableSigningProvider::GetKeys() const +{ + LOCK(cs_KeyStore); + std::set<CKeyID> set_address; + for (const auto& mi : mapKeys) { + set_address.insert(mi.first); + } + return set_address; +} + +bool FillableSigningProvider::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 FillableSigningProvider::AddCScript(const CScript& redeemScript) +{ + if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) + return error("FillableSigningProvider::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE); + + LOCK(cs_KeyStore); + mapScripts[CScriptID(redeemScript)] = redeemScript; + return true; +} + +bool FillableSigningProvider::HaveCScript(const CScriptID& hash) const +{ + LOCK(cs_KeyStore); + return mapScripts.count(hash) > 0; +} + +std::set<CScriptID> FillableSigningProvider::GetCScripts() const +{ + LOCK(cs_KeyStore); + std::set<CScriptID> set_script; + for (const auto& mi : mapScripts) { + set_script.insert(mi.first); + } + return set_script; +} + +bool FillableSigningProvider::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; +} + +CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest) +{ + // Only supports destinations which map to single public keys, i.e. P2PKH, + // P2WPKH, and P2SH-P2WPKH. + if (auto id = boost::get<PKHash>(&dest)) { + return CKeyID(*id); + } + if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) { + return CKeyID(*witness_id); + } + if (auto script_hash = boost::get<ScriptHash>(&dest)) { + CScript script; + CScriptID script_id(*script_hash); + CTxDestination inner_dest; + if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) { + if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) { + return CKeyID(*inner_witness_id); + } + } + } + return CKeyID(); +} diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h new file mode 100644 index 0000000000..4eec2311d4 --- /dev/null +++ b/src/script/signingprovider.h @@ -0,0 +1,92 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SCRIPT_SIGNINGPROVIDER_H +#define BITCOIN_SCRIPT_SIGNINGPROVIDER_H + +#include <key.h> +#include <pubkey.h> +#include <script/script.h> +#include <script/standard.h> +#include <sync.h> + +struct KeyOriginInfo; + +/** An interface to be implemented by keystores that support signing. */ +class SigningProvider +{ +public: + virtual ~SigningProvider() {} + virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; } + virtual bool HaveCScript(const CScriptID &scriptid) const { return false; } + virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; } + virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; } + virtual bool HaveKey(const CKeyID &address) const { return false; } + virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; } +}; + +extern const SigningProvider& DUMMY_SIGNING_PROVIDER; + +class HidingSigningProvider : public SigningProvider +{ +private: + const bool m_hide_secret; + const bool m_hide_origin; + const SigningProvider* m_provider; + +public: + HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {} + bool GetCScript(const CScriptID& scriptid, CScript& script) const override; + bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; + bool GetKey(const CKeyID& keyid, CKey& key) const override; + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; +}; + +struct FlatSigningProvider final : public SigningProvider +{ + std::map<CScriptID, CScript> scripts; + std::map<CKeyID, CPubKey> pubkeys; + std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins; + std::map<CKeyID, CKey> keys; + + bool GetCScript(const CScriptID& scriptid, CScript& script) const override; + bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; + bool GetKey(const CKeyID& keyid, CKey& key) const override; +}; + +FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b); + +/** Fillable signing provider that keeps keys in an address->secret map */ +class FillableSigningProvider : public SigningProvider +{ +protected: + mutable CCriticalSection cs_KeyStore; + + using KeyMap = std::map<CKeyID, CKey>; + using ScriptMap = std::map<CScriptID, CScript>; + + KeyMap mapKeys GUARDED_BY(cs_KeyStore); + ScriptMap mapScripts GUARDED_BY(cs_KeyStore); + + void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); + +public: + virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); + virtual bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); } + virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; + virtual bool HaveKey(const CKeyID &address) const override; + virtual std::set<CKeyID> GetKeys() const; + virtual bool GetKey(const CKeyID &address, CKey &keyOut) const override; + virtual bool AddCScript(const CScript& redeemScript); + virtual bool HaveCScript(const CScriptID &hash) const override; + virtual std::set<CScriptID> GetCScripts() const; + virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override; +}; + +/** Return the CKeyID of the key involved in a script (if there is a unique one). */ +CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest); + +#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H diff --git a/src/script/standard.cpp b/src/script/standard.cpp index b7d6cd925c..fc6898f444 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -9,7 +9,6 @@ #include <pubkey.h> #include <script/script.h> - typedef std::vector<unsigned char> valtype; bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER; |