@@ -114,12 +114,17 @@ static bool GetPubKey(const SigningProvider& provider, const SignatureData& sigd
114114 pubkey = it->second .first ;
115115 return true ;
116116 }
117- // Look for pubkey in pubkey list
117+ // Look for pubkey in pubkey lists
118118 const auto & pk_it = sigdata.misc_pubkeys .find (address);
119119 if (pk_it != sigdata.misc_pubkeys .end ()) {
120120 pubkey = pk_it->second .first ;
121121 return true ;
122122 }
123+ const auto & tap_pk_it = sigdata.tap_pubkeys .find (address);
124+ if (tap_pk_it != sigdata.tap_pubkeys .end ()) {
125+ pubkey = tap_pk_it->second .GetEvenCorrespondingCPubKey ();
126+ return true ;
127+ }
123128 // Query the underlying provider
124129 return provider.GetPubKey (address, pubkey);
125130}
@@ -186,41 +191,35 @@ miniscript::Availability MsLookupHelper(const M& map, const K& key, V& value)
186191 * Context for solving a Miniscript.
187192 * If enough material (access to keys, hash preimages, ..) is given, produces a valid satisfaction.
188193 */
194+ template <typename Pk>
189195struct Satisfier {
190- typedef CPubKey Key;
196+ using Key = Pk ;
191197
192198 const SigningProvider& m_provider;
193199 SignatureData& m_sig_data;
194200 const BaseSignatureCreator& m_creator;
195201 const CScript& m_witness_script;
196- // ! For now Miniscript is only available under P2WSH.
197- const miniscript::MiniscriptContext m_script_ctx{miniscript::MiniscriptContext::P2WSH} ;
202+ // ! The context of the script we are satisfying (either P2WSH or Tapscript) .
203+ const miniscript::MiniscriptContext m_script_ctx;
198204
199205 explicit Satisfier (const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND,
200206 const BaseSignatureCreator& creator LIFETIMEBOUND,
201- const CScript& witscript LIFETIMEBOUND) : m_provider(provider),
202- m_sig_data(sig_data),
203- m_creator(creator),
204- m_witness_script(witscript) {}
207+ const CScript& witscript LIFETIMEBOUND,
208+ miniscript::MiniscriptContext script_ctx) : m_provider(provider),
209+ m_sig_data(sig_data),
210+ m_creator(creator),
211+ m_witness_script(witscript),
212+ m_script_ctx(script_ctx) {}
205213
206214 static bool KeyCompare (const Key& a, const Key& b) {
207215 return a < b;
208216 }
209217
210- // ! Conversion from a raw public key.
211- template <typename I>
212- std::optional<Key> FromPKBytes (I first, I last) const
213- {
214- Key pubkey{first, last};
215- if (pubkey.IsValid ()) return pubkey;
216- return {};
217- }
218-
219- // ! Conversion from a raw public key hash.
218+ // ! Get a CPubKey from a key hash. Note the key hash may be of an xonly pubkey.
220219 template <typename I>
221- std::optional<Key> FromPKHBytes (I first, I last) const {
220+ std::optional<CPubKey> CPubFromPKHBytes (I first, I last) const {
222221 assert (last - first == 20 );
223- Key pubkey;
222+ CPubKey pubkey;
224223 CKeyID key_id;
225224 std::copy (first, last, key_id.begin ());
226225 if (GetPubKey (m_provider, m_sig_data, key_id, pubkey)) return pubkey;
@@ -229,21 +228,12 @@ struct Satisfier {
229228 }
230229
231230 // ! Conversion to raw public key.
232- std::vector<unsigned char > ToPKBytes (const CPubKey& key) const { return {key.begin (), key.end ()}; }
233-
234- // ! Satisfy a signature check.
235- miniscript::Availability Sign (const CPubKey& key, std::vector<unsigned char >& sig) const {
236- if (CreateSig (m_creator, m_sig_data, m_provider, sig, key, m_witness_script, SigVersion::WITNESS_V0)) {
237- return miniscript::Availability::YES;
238- }
239- return miniscript::Availability::NO;
240- }
231+ std::vector<unsigned char > ToPKBytes (const Key& key) const { return {key.begin (), key.end ()}; }
241232
242233 // ! Time lock satisfactions.
243234 bool CheckAfter (uint32_t value) const { return m_creator.Checker ().CheckLockTime (CScriptNum (value)); }
244235 bool CheckOlder (uint32_t value) const { return m_creator.Checker ().CheckSequence (CScriptNum (value)); }
245236
246-
247237 // ! Hash preimage satisfactions.
248238 miniscript::Availability SatSHA256 (const std::vector<unsigned char >& hash, std::vector<unsigned char >& preimage) const {
249239 return MsLookupHelper (m_sig_data.sha256_preimages , hash, preimage);
@@ -263,49 +253,81 @@ struct Satisfier {
263253 }
264254};
265255
266- static bool SignTaprootScript ( const SigningProvider& provider, const BaseSignatureCreator& creator, SignatureData& sigdata, int leaf_version, Span< const unsigned char > script_bytes, std::vector<valtype>& result)
267- {
268- // Only BIP342 tapscript signing is supported for now.
269- if (leaf_version != TAPROOT_LEAF_TAPSCRIPT) return false ;
270- SigVersion sigversion = SigVersion::TAPSCRIPT;
256+ /* * Miniscript satisfier specific to P2WSH context. */
257+ struct WshSatisfier : Satisfier<CPubKey> {
258+ explicit WshSatisfier ( const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND,
259+ const BaseSignatureCreator& creator LIFETIMEBOUND, const CScript& witscript LIFETIMEBOUND)
260+ : Satisfier(provider, sig_data, creator, witscript, miniscript::MiniscriptContext::P2WSH) {}
271261
272- uint256 leaf_hash = ComputeTapleafHash (leaf_version, script_bytes);
273- CScript script = CScript (script_bytes.begin (), script_bytes.end ());
262+ // ! Conversion from a raw compressed public key.
263+ template <typename I>
264+ std::optional<CPubKey> FromPKBytes (I first, I last) const {
265+ CPubKey pubkey{first, last};
266+ if (pubkey.IsValid ()) return pubkey;
267+ return {};
268+ }
274269
275- // <xonly pubkey> OP_CHECKSIG
276- if (script.size () == 34 && script[33 ] == OP_CHECKSIG && script[0 ] == 0x20 ) {
277- XOnlyPubKey pubkey{Span{script}.subspan (1 , 32 )};
278- std::vector<unsigned char > sig;
279- if (CreateTaprootScriptSig (creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion)) {
280- result = Vector (std::move (sig));
281- return true ;
282- }
283- return false ;
270+ // ! Conversion from a raw compressed public key hash.
271+ template <typename I>
272+ std::optional<CPubKey> FromPKHBytes (I first, I last) const {
273+ return Satisfier::CPubFromPKHBytes (first, last);
284274 }
285275
286- // multi_a scripts (<key> OP_CHECKSIG <key> OP_CHECKSIGADD <key> OP_CHECKSIGADD <k> OP_NUMEQUAL)
287- if (auto match = MatchMultiA (script)) {
288- std::vector<std::vector<unsigned char >> sigs;
289- int good_sigs = 0 ;
290- for (size_t i = 0 ; i < match->second .size (); ++i) {
291- XOnlyPubKey pubkey{*(match->second .rbegin () + i)};
292- std::vector<unsigned char > sig;
293- bool good_sig = CreateTaprootScriptSig (creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion);
294- if (good_sig && good_sigs < match->first ) {
295- ++good_sigs;
296- sigs.push_back (std::move (sig));
297- } else {
298- sigs.emplace_back ();
299- }
276+ // ! Satisfy an ECDSA signature check.
277+ miniscript::Availability Sign (const CPubKey& key, std::vector<unsigned char >& sig) const {
278+ if (CreateSig (m_creator, m_sig_data, m_provider, sig, key, m_witness_script, SigVersion::WITNESS_V0)) {
279+ return miniscript::Availability::YES;
300280 }
301- if (good_sigs == match->first ) {
302- result = std::move (sigs);
303- return true ;
281+ return miniscript::Availability::NO;
282+ }
283+ };
284+
285+ /* * Miniscript satisfier specific to Tapscript context. */
286+ struct TapSatisfier : Satisfier<XOnlyPubKey> {
287+ const uint256& m_leaf_hash;
288+
289+ explicit TapSatisfier (const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND,
290+ const BaseSignatureCreator& creator LIFETIMEBOUND, const CScript& script LIFETIMEBOUND,
291+ const uint256& leaf_hash LIFETIMEBOUND)
292+ : Satisfier(provider, sig_data, creator, script, miniscript::MiniscriptContext::TAPSCRIPT),
293+ m_leaf_hash(leaf_hash) {}
294+
295+ // ! Conversion from a raw xonly public key.
296+ template <typename I>
297+ std::optional<XOnlyPubKey> FromPKBytes (I first, I last) const {
298+ CHECK_NONFATAL (last - first == 32 );
299+ XOnlyPubKey pubkey;
300+ std::copy (first, last, pubkey.begin ());
301+ return pubkey;
302+ }
303+
304+ // ! Conversion from a raw xonly public key hash.
305+ template <typename I>
306+ std::optional<XOnlyPubKey> FromPKHBytes (I first, I last) const {
307+ if (auto pubkey = Satisfier::CPubFromPKHBytes (first, last)) return XOnlyPubKey{*pubkey};
308+ return {};
309+ }
310+
311+ // ! Satisfy a BIP340 signature check.
312+ miniscript::Availability Sign (const XOnlyPubKey& key, std::vector<unsigned char >& sig) const {
313+ if (CreateTaprootScriptSig (m_creator, m_sig_data, m_provider, sig, key, m_leaf_hash, SigVersion::TAPSCRIPT)) {
314+ return miniscript::Availability::YES;
304315 }
305- return false ;
316+ return miniscript::Availability::NO ;
306317 }
318+ };
307319
308- return false ;
320+ static bool SignTaprootScript (const SigningProvider& provider, const BaseSignatureCreator& creator, SignatureData& sigdata, int leaf_version, Span<const unsigned char > script_bytes, std::vector<valtype>& result)
321+ {
322+ // Only BIP342 tapscript signing is supported for now.
323+ if (leaf_version != TAPROOT_LEAF_TAPSCRIPT) return false ;
324+
325+ uint256 leaf_hash = ComputeTapleafHash (leaf_version, script_bytes);
326+ CScript script = CScript (script_bytes.begin (), script_bytes.end ());
327+
328+ TapSatisfier ms_satisfier{provider, sigdata, creator, script, leaf_hash};
329+ const auto ms = miniscript::FromScript (script, ms_satisfier);
330+ return ms && ms->Satisfy (ms_satisfier, result) == miniscript::Availability::YES;
309331}
310332
311333static bool SignTaproot (const SigningProvider& provider, const BaseSignatureCreator& creator, const WitnessV1Taproot& output, SignatureData& sigdata, std::vector<valtype>& result)
@@ -518,7 +540,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
518540 // isn't fully solved. For instance the CHECKMULTISIG satisfaction in SignStep() pushes partial signatures
519541 // and the extractor relies on this behaviour to combine witnesses.
520542 if (!solved && result.empty ()) {
521- Satisfier ms_satisfier{provider, sigdata, creator, witnessscript};
543+ WshSatisfier ms_satisfier{provider, sigdata, creator, witnessscript};
522544 const auto ms = miniscript::FromScript (witnessscript, ms_satisfier);
523545 solved = ms && ms->Satisfy (ms_satisfier, result) == miniscript::Availability::YES;
524546 }
0 commit comments