@@ -1114,16 +1114,33 @@ class TRDescriptor final : public DescriptorImpl
1114
1114
class ScriptMaker {
1115
1115
// ! Keys contained in the Miniscript (the evaluation of DescriptorImpl::m_pubkey_args).
1116
1116
const std::vector<CPubKey>& m_keys;
1117
+ // ! The script context we're operating within (Tapscript or P2WSH).
1118
+ const miniscript::MiniscriptContext m_script_ctx;
1119
+
1120
+ // ! Get the ripemd160(sha256()) hash of this key.
1121
+ // ! Any key that is valid in a descriptor serializes as 32 bytes within a Tapscript context. So we
1122
+ // ! must not hash the sign-bit byte in this case.
1123
+ uint160 GetHash160 (uint32_t key) const {
1124
+ if (miniscript::IsTapscript (m_script_ctx)) {
1125
+ return Hash160 (XOnlyPubKey{m_keys[key]});
1126
+ }
1127
+ return m_keys[key].GetID ();
1128
+ }
1117
1129
1118
1130
public:
1119
- ScriptMaker (const std::vector<CPubKey>& keys LIFETIMEBOUND) : m_keys(keys) {}
1131
+ ScriptMaker (const std::vector<CPubKey>& keys LIFETIMEBOUND, const miniscript::MiniscriptContext script_ctx ) : m_keys(keys), m_script_ctx{script_ctx} {}
1120
1132
1121
1133
std::vector<unsigned char > ToPKBytes (uint32_t key) const {
1122
- return {m_keys[key].begin (), m_keys[key].end ()};
1134
+ // In Tapscript keys always serialize as x-only, whether an x-only key was used in the descriptor or not.
1135
+ if (!miniscript::IsTapscript (m_script_ctx)) {
1136
+ return {m_keys[key].begin (), m_keys[key].end ()};
1137
+ }
1138
+ const XOnlyPubKey xonly_pubkey{m_keys[key]};
1139
+ return {xonly_pubkey.begin (), xonly_pubkey.end ()};
1123
1140
}
1124
1141
1125
1142
std::vector<unsigned char > ToPKHBytes (uint32_t key) const {
1126
- auto id = m_keys[key]. GetID ( );
1143
+ auto id = GetHash160 (key );
1127
1144
return {id.begin (), id.end ()};
1128
1145
}
1129
1146
};
@@ -1165,7 +1182,7 @@ class MiniscriptDescriptor final : public DescriptorImpl
1165
1182
FlatSigningProvider& provider) const override
1166
1183
{
1167
1184
for (const auto & key : keys) provider.pubkeys .emplace (key.GetID (), key);
1168
- return Vector (m_node->ToScript (ScriptMaker (keys)));
1185
+ return Vector (m_node->ToScript (ScriptMaker (keys, m_node-> GetMsCtx () )));
1169
1186
}
1170
1187
1171
1188
public:
@@ -1434,11 +1451,19 @@ struct KeyParser {
1434
1451
return *m_keys.at (a) < *m_keys.at (b);
1435
1452
}
1436
1453
1454
+ ParseScriptContext ParseContext () const {
1455
+ switch (m_script_ctx) {
1456
+ case miniscript::MiniscriptContext::P2WSH: return ParseScriptContext::P2WSH;
1457
+ case miniscript::MiniscriptContext::TAPSCRIPT: return ParseScriptContext::P2TR;
1458
+ }
1459
+ assert (false );
1460
+ }
1461
+
1437
1462
template <typename I> std::optional<Key> FromString (I begin, I end) const
1438
1463
{
1439
1464
assert (m_out);
1440
1465
Key key = m_keys.size ();
1441
- auto pk = ParsePubkey (key, {&*begin, &*end}, ParseScriptContext::P2WSH , *m_out, m_key_parsing_error);
1466
+ auto pk = ParsePubkey (key, {&*begin, &*end}, ParseContext () , *m_out, m_key_parsing_error);
1442
1467
if (!pk) return {};
1443
1468
m_keys.push_back (std::move (pk));
1444
1469
return key;
@@ -1452,11 +1477,18 @@ struct KeyParser {
1452
1477
template <typename I> std::optional<Key> FromPKBytes (I begin, I end) const
1453
1478
{
1454
1479
assert (m_in);
1455
- CPubKey pubkey (begin, end);
1456
- if (pubkey.IsValidNonHybrid ()) {
1457
- Key key = m_keys.size ();
1458
- m_keys.push_back (InferPubkey (pubkey, ParseScriptContext::P2WSH, *m_in));
1480
+ Key key = m_keys.size ();
1481
+ if (miniscript::IsTapscript (m_script_ctx) && end - begin == 32 ) {
1482
+ XOnlyPubKey pubkey;
1483
+ std::copy (begin, end, pubkey.begin ());
1484
+ m_keys.push_back (InferPubkey (pubkey.GetEvenCorrespondingCPubKey (), ParseContext (), *m_in));
1459
1485
return key;
1486
+ } else if (!miniscript::IsTapscript (m_script_ctx)) {
1487
+ CPubKey pubkey{begin, end};
1488
+ if (pubkey.IsValidNonHybrid ()) {
1489
+ m_keys.push_back (InferPubkey (pubkey, ParseContext (), *m_in));
1490
+ return key;
1491
+ }
1460
1492
}
1461
1493
return {};
1462
1494
}
@@ -1471,7 +1503,7 @@ struct KeyParser {
1471
1503
CPubKey pubkey;
1472
1504
if (m_in->GetPubKey (keyid, pubkey)) {
1473
1505
Key key = m_keys.size ();
1474
- m_keys.push_back (InferPubkey (pubkey, ParseScriptContext::P2WSH , *m_in));
1506
+ m_keys.push_back (InferPubkey (pubkey, ParseContext () , *m_in));
1475
1507
return key;
1476
1508
}
1477
1509
return {};
0 commit comments