66
77#include < key_io.h>
88#include < pubkey.h>
9+ #include < script/miniscript.h>
910#include < script/script.h>
1011#include < script/standard.h>
1112
@@ -161,6 +162,20 @@ struct PubkeyProvider
161162
162163 virtual ~PubkeyProvider () = default ;
163164
165+ /* * Compare two public keys represented by this provider.
166+ * Used by the Miniscript descriptors to check for duplicate keys in the script.
167+ */
168+ bool operator <(PubkeyProvider& other) const {
169+ CPubKey a, b;
170+ SigningProvider dummy;
171+ KeyOriginInfo dummy_info;
172+
173+ GetPubKey (0 , dummy, a, dummy_info);
174+ other.GetPubKey (0 , dummy, b, dummy_info);
175+
176+ return a < b;
177+ }
178+
164179 /* * Derive a public key.
165180 * read_cache is the cache to read keys from (if not nullptr)
166181 * write_cache is the cache to write keys to (if not nullptr)
@@ -493,12 +508,12 @@ class BIP32PubkeyProvider final : public PubkeyProvider
493508/* * Base class for all Descriptor implementations. */
494509class DescriptorImpl : public Descriptor
495510{
496- // ! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for Multisig).
511+ protected:
512+ // ! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for WSH and Multisig).
497513 const std::vector<std::unique_ptr<PubkeyProvider>> m_pubkey_args;
498514 // ! The string name of the descriptor function.
499515 const std::string m_name;
500516
501- protected:
502517 // ! The sub-descriptor arguments (empty for everything but SH and WSH).
503518 // ! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
504519 // ! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
@@ -563,7 +578,7 @@ class DescriptorImpl : public Descriptor
563578 return true ;
564579 }
565580
566- bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr ) const
581+ virtual bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr ) const
567582 {
568583 std::string extra = ToStringExtra ();
569584 size_t pos = extra.size () > 0 ? 1 : 0 ;
@@ -917,6 +932,89 @@ class TRDescriptor final : public DescriptorImpl
917932 bool IsSingleType () const final { return true ; }
918933};
919934
935+ /* We instantiate Miniscript here with a simple integer as key type.
936+ * The value of these key integers are an index in the
937+ * DescriptorImpl::m_pubkey_args vector.
938+ */
939+
940+ /* *
941+ * The context for converting a Miniscript descriptor into a Script.
942+ */
943+ class ScriptMaker {
944+ // ! Keys contained in the Miniscript (the evaluation of DescriptorImpl::m_pubkey_args).
945+ const std::vector<CPubKey>& m_keys;
946+
947+ public:
948+ ScriptMaker (const std::vector<CPubKey>& keys LIFETIMEBOUND) : m_keys(keys) {}
949+
950+ std::vector<unsigned char > ToPKBytes (uint32_t key) const {
951+ return {m_keys[key].begin (), m_keys[key].end ()};
952+ }
953+
954+ std::vector<unsigned char > ToPKHBytes (uint32_t key) const {
955+ auto id = m_keys[key].GetID ();
956+ return {id.begin (), id.end ()};
957+ }
958+ };
959+
960+ /* *
961+ * The context for converting a Miniscript descriptor to its textual form.
962+ */
963+ class StringMaker {
964+ // ! To convert private keys for private descriptors.
965+ const SigningProvider* m_arg;
966+ // ! Keys contained in the Miniscript (a reference to DescriptorImpl::m_pubkey_args).
967+ const std::vector<std::unique_ptr<PubkeyProvider>>& m_pubkeys;
968+ // ! Whether to serialize keys as private or public.
969+ bool m_private;
970+
971+ public:
972+ StringMaker (const SigningProvider* arg LIFETIMEBOUND, const std::vector<std::unique_ptr<PubkeyProvider>>& pubkeys LIFETIMEBOUND, bool priv)
973+ : m_arg(arg), m_pubkeys(pubkeys), m_private(priv) {}
974+
975+ std::optional<std::string> ToString (uint32_t key) const
976+ {
977+ std::string ret;
978+ if (m_private) {
979+ if (!m_pubkeys[key]->ToPrivateString (*m_arg, ret)) return {};
980+ } else {
981+ ret = m_pubkeys[key]->ToString ();
982+ }
983+ return ret;
984+ }
985+ };
986+
987+ class MiniscriptDescriptor final : public DescriptorImpl
988+ {
989+ private:
990+ miniscript::NodeRef<uint32_t > m_node;
991+
992+ protected:
993+ std::vector<CScript> MakeScripts (const std::vector<CPubKey>& keys, Span<const CScript> scripts,
994+ FlatSigningProvider& provider) const override
995+ {
996+ for (const auto & key : keys) provider.pubkeys .emplace (key.GetID (), key);
997+ return Vector (m_node->ToScript (ScriptMaker (keys)));
998+ }
999+
1000+ public:
1001+ MiniscriptDescriptor (std::vector<std::unique_ptr<PubkeyProvider>> providers, miniscript::NodeRef<uint32_t > node)
1002+ : DescriptorImpl(std::move(providers), " ?" ), m_node(std::move(node)) {}
1003+
1004+ bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type,
1005+ const DescriptorCache* cache = nullptr ) const override
1006+ {
1007+ if (const auto res = m_node->ToString (StringMaker (arg, m_pubkey_args, type == StringType::PRIVATE))) {
1008+ out = *res;
1009+ return true ;
1010+ }
1011+ return false ;
1012+ }
1013+
1014+ bool IsSolvable () const override { return false ; } // For now, mark these descriptors as non-solvable (as we don't have signing logic for them).
1015+ bool IsSingleType () const final { return true ; }
1016+ };
1017+
9201018// //////////////////////////////////////////////////////////////////////////
9211019// Parser //
9221020// //////////////////////////////////////////////////////////////////////////
@@ -1058,6 +1156,94 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
10581156 return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move (info), std::move (provider));
10591157}
10601158
1159+ std::unique_ptr<PubkeyProvider> InferPubkey (const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
1160+ {
1161+ std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, false );
1162+ KeyOriginInfo info;
1163+ if (provider.GetKeyOrigin (pubkey.GetID (), info)) {
1164+ return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1165+ }
1166+ return key_provider;
1167+ }
1168+
1169+ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey (const XOnlyPubKey& xkey, ParseScriptContext ctx, const SigningProvider& provider)
1170+ {
1171+ unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02 };
1172+ std::copy (xkey.begin (), xkey.end (), full_key + 1 );
1173+ CPubKey pubkey (full_key);
1174+ std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, true );
1175+ KeyOriginInfo info;
1176+ if (provider.GetKeyOriginByXOnly (xkey, info)) {
1177+ return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1178+ }
1179+ return key_provider;
1180+ }
1181+
1182+ /* *
1183+ * The context for parsing a Miniscript descriptor (either from Script or from its textual representation).
1184+ */
1185+ struct KeyParser {
1186+ // ! The Key type is an index in DescriptorImpl::m_pubkey_args
1187+ using Key = uint32_t ;
1188+ // ! Must not be nullptr if parsing from string.
1189+ FlatSigningProvider* m_out;
1190+ // ! Must not be nullptr if parsing from Script.
1191+ const SigningProvider* m_in;
1192+ // ! List of keys contained in the Miniscript.
1193+ mutable std::vector<std::unique_ptr<PubkeyProvider>> m_keys;
1194+ // ! Used to detect key parsing errors within a Miniscript.
1195+ mutable std::string m_key_parsing_error;
1196+
1197+ KeyParser (FlatSigningProvider* out LIFETIMEBOUND, const SigningProvider* in LIFETIMEBOUND) : m_out(out), m_in(in) {}
1198+
1199+ bool KeyCompare (const Key& a, const Key& b) const {
1200+ return *m_keys.at (a) < *m_keys.at (b);
1201+ }
1202+
1203+ template <typename I> std::optional<Key> FromString (I begin, I end) const
1204+ {
1205+ assert (m_out);
1206+ Key key = m_keys.size ();
1207+ auto pk = ParsePubkey (key, {&*begin, &*end}, ParseScriptContext::P2WSH, *m_out, m_key_parsing_error);
1208+ if (!pk) return {};
1209+ m_keys.push_back (std::move (pk));
1210+ return key;
1211+ }
1212+
1213+ std::optional<std::string> ToString (const Key& key) const
1214+ {
1215+ return m_keys.at (key)->ToString ();
1216+ }
1217+
1218+ template <typename I> std::optional<Key> FromPKBytes (I begin, I end) const
1219+ {
1220+ assert (m_in);
1221+ CPubKey pubkey (begin, end);
1222+ if (pubkey.IsValid ()) {
1223+ Key key = m_keys.size ();
1224+ m_keys.push_back (InferPubkey (pubkey, ParseScriptContext::P2WSH, *m_in));
1225+ return key;
1226+ }
1227+ return {};
1228+ }
1229+
1230+ template <typename I> std::optional<Key> FromPKHBytes (I begin, I end) const
1231+ {
1232+ assert (end - begin == 20 );
1233+ assert (m_in);
1234+ uint160 hash;
1235+ std::copy (begin, end, hash.begin ());
1236+ CKeyID keyid (hash);
1237+ CPubKey pubkey;
1238+ if (m_in->GetPubKey (keyid, pubkey)) {
1239+ Key key = m_keys.size ();
1240+ m_keys.push_back (InferPubkey (pubkey, ParseScriptContext::P2WSH, *m_in));
1241+ return key;
1242+ }
1243+ return {};
1244+ }
1245+ };
1246+
10611247/* * Parse a script in a particular context. */
10621248std::unique_ptr<DescriptorImpl> ParseScript (uint32_t & key_exp_index, Span<const char >& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
10631249{
@@ -1279,6 +1465,45 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
12791465 error = " Can only have raw() at top level" ;
12801466 return nullptr ;
12811467 }
1468+ // Process miniscript expressions.
1469+ {
1470+ KeyParser parser (&out, nullptr );
1471+ auto node = miniscript::FromString (std::string (expr.begin (), expr.end ()), parser);
1472+ if (node) {
1473+ if (ctx != ParseScriptContext::P2WSH) {
1474+ error = " Miniscript expressions can only be used in wsh" ;
1475+ return nullptr ;
1476+ }
1477+ if (parser.m_key_parsing_error != " " ) {
1478+ error = std::move (parser.m_key_parsing_error );
1479+ return nullptr ;
1480+ }
1481+ if (!node->IsSane ()) {
1482+ // Try to find the first insane sub for better error reporting.
1483+ auto insane_node = node.get ();
1484+ if (const auto sub = node->FindInsaneSub ()) insane_node = sub;
1485+ if (const auto str = insane_node->ToString (parser)) error = *str;
1486+ if (!insane_node->IsValid ()) {
1487+ error += " is invalid" ;
1488+ } else {
1489+ error += " is not sane" ;
1490+ if (!insane_node->IsNonMalleable ()) {
1491+ error += " : malleable witnesses exist" ;
1492+ } else if (insane_node == node.get () && !insane_node->NeedsSignature ()) {
1493+ error += " : witnesses without signature exist" ;
1494+ } else if (!insane_node->CheckTimeLocksMix ()) {
1495+ error += " : contains mixes of timelocks expressed in blocks and seconds" ;
1496+ } else if (!insane_node->CheckDuplicateKey ()) {
1497+ error += " : contains duplicate public keys" ;
1498+ } else if (!insane_node->ValidSatisfactions ()) {
1499+ error += " : needs witnesses that may exceed resource limits" ;
1500+ }
1501+ }
1502+ return nullptr ;
1503+ }
1504+ return std::make_unique<MiniscriptDescriptor>(std::move (parser.m_keys ), std::move (node));
1505+ }
1506+ }
12821507 if (ctx == ParseScriptContext::P2SH) {
12831508 error = " A function is needed within P2SH" ;
12841509 return nullptr ;
@@ -1290,29 +1515,6 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
12901515 return nullptr ;
12911516}
12921517
1293- std::unique_ptr<PubkeyProvider> InferPubkey (const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
1294- {
1295- std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, false );
1296- KeyOriginInfo info;
1297- if (provider.GetKeyOrigin (pubkey.GetID (), info)) {
1298- return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1299- }
1300- return key_provider;
1301- }
1302-
1303- std::unique_ptr<PubkeyProvider> InferXOnlyPubkey (const XOnlyPubKey& xkey, ParseScriptContext ctx, const SigningProvider& provider)
1304- {
1305- unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02 };
1306- std::copy (xkey.begin (), xkey.end (), full_key + 1 );
1307- CPubKey pubkey (full_key);
1308- std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, true );
1309- KeyOriginInfo info;
1310- if (provider.GetKeyOriginByXOnly (xkey, info)) {
1311- return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1312- }
1313- return key_provider;
1314- }
1315-
13161518std::unique_ptr<DescriptorImpl> InferMultiA (const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
13171519{
13181520 auto match = MatchMultiA (script);
@@ -1426,6 +1628,14 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
14261628 }
14271629 }
14281630
1631+ if (ctx == ParseScriptContext::P2WSH) {
1632+ KeyParser parser (nullptr , &provider);
1633+ auto node = miniscript::FromScript (script, parser);
1634+ if (node && node->IsSane ()) {
1635+ return std::make_unique<MiniscriptDescriptor>(std::move (parser.m_keys ), std::move (node));
1636+ }
1637+ }
1638+
14291639 CTxDestination dest;
14301640 if (ExtractDestination (script, dest)) {
14311641 if (GetScriptForDestination (dest) == script) {
0 commit comments