@@ -114,12 +114,17 @@ static bool GetPubKey(const SigningProvider& provider, const SignatureData& sigd
114
114
pubkey = it->second .first ;
115
115
return true ;
116
116
}
117
- // Look for pubkey in pubkey list
117
+ // Look for pubkey in pubkey lists
118
118
const auto & pk_it = sigdata.misc_pubkeys .find (address);
119
119
if (pk_it != sigdata.misc_pubkeys .end ()) {
120
120
pubkey = pk_it->second .first ;
121
121
return true ;
122
122
}
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
+ }
123
128
// Query the underlying provider
124
129
return provider.GetPubKey (address, pubkey);
125
130
}
@@ -186,41 +191,35 @@ miniscript::Availability MsLookupHelper(const M& map, const K& key, V& value)
186
191
* Context for solving a Miniscript.
187
192
* If enough material (access to keys, hash preimages, ..) is given, produces a valid satisfaction.
188
193
*/
194
+ template <typename Pk>
189
195
struct Satisfier {
190
- typedef CPubKey Key;
196
+ using Key = Pk ;
191
197
192
198
const SigningProvider& m_provider;
193
199
SignatureData& m_sig_data;
194
200
const BaseSignatureCreator& m_creator;
195
201
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;
198
204
199
205
explicit Satisfier (const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND,
200
206
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) {}
205
213
206
214
static bool KeyCompare (const Key& a, const Key& b) {
207
215
return a < b;
208
216
}
209
217
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.
220
219
template <typename I>
221
- std::optional<Key> FromPKHBytes (I first, I last) const {
220
+ std::optional<CPubKey> CPubFromPKHBytes (I first, I last) const {
222
221
assert (last - first == 20 );
223
- Key pubkey;
222
+ CPubKey pubkey;
224
223
CKeyID key_id;
225
224
std::copy (first, last, key_id.begin ());
226
225
if (GetPubKey (m_provider, m_sig_data, key_id, pubkey)) return pubkey;
@@ -229,21 +228,12 @@ struct Satisfier {
229
228
}
230
229
231
230
// ! 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 ()}; }
241
232
242
233
// ! Time lock satisfactions.
243
234
bool CheckAfter (uint32_t value) const { return m_creator.Checker ().CheckLockTime (CScriptNum (value)); }
244
235
bool CheckOlder (uint32_t value) const { return m_creator.Checker ().CheckSequence (CScriptNum (value)); }
245
236
246
-
247
237
// ! Hash preimage satisfactions.
248
238
miniscript::Availability SatSHA256 (const std::vector<unsigned char >& hash, std::vector<unsigned char >& preimage) const {
249
239
return MsLookupHelper (m_sig_data.sha256_preimages , hash, preimage);
@@ -263,49 +253,81 @@ struct Satisfier {
263
253
}
264
254
};
265
255
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) {}
271
261
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
+ }
274
269
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);
284
274
}
285
275
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;
300
280
}
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;
304
315
}
305
- return false ;
316
+ return miniscript::Availability::NO ;
306
317
}
318
+ };
307
319
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;
309
331
}
310
332
311
333
static 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
518
540
// isn't fully solved. For instance the CHECKMULTISIG satisfaction in SignStep() pushes partial signatures
519
541
// and the extractor relies on this behaviour to combine witnesses.
520
542
if (!solved && result.empty ()) {
521
- Satisfier ms_satisfier{provider, sigdata, creator, witnessscript};
543
+ WshSatisfier ms_satisfier{provider, sigdata, creator, witnessscript};
522
544
const auto ms = miniscript::FromScript (witnessscript, ms_satisfier);
523
545
solved = ms && ms->Satisfy (ms_satisfier, result) == miniscript::Availability::YES;
524
546
}
0 commit comments