1use core::convert::TryFrom;
12use core::mem;
13
14use bitcoin::hashes::hash160;
15use bitcoin::key::XOnlyPublicKey;
16#[cfg(not(test))] use bitcoin::secp256k1;
18use bitcoin::secp256k1::Secp256k1;
19use bitcoin::sighash::Prevouts;
20use bitcoin::taproot::LeafVersion;
21use bitcoin::{PublicKey, Script, ScriptBuf, TxOut, Witness};
22
23use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier};
24use crate::prelude::*;
25use crate::util::witness_size;
26use crate::{
27 interpreter, BareCtx, Descriptor, ExtParams, Legacy, Miniscript, Satisfier, Segwitv0, SigType,
28 Tap, ToPublicKey,
29};
30
31fn construct_tap_witness(
36 spk: &Script,
37 sat: &PsbtInputSatisfier,
38 allow_mall: bool,
39) -> Result<Vec<Vec<u8>>, InputError> {
40 let mut map: BTreeMap<hash160::Hash, bitcoin::key::XOnlyPublicKey> = BTreeMap::new();
43 let psbt_inputs = &sat.psbt.inputs;
44 for psbt_input in psbt_inputs {
45 let public_keys = psbt_input.tap_key_origins.keys();
48 for key in public_keys {
49 let bitcoin_key = *key;
50 let hash = bitcoin_key.to_pubkeyhash(SigType::Schnorr);
51 map.insert(hash, bitcoin_key);
52 }
53 }
54 assert!(spk.is_p2tr());
55
56 if let Some(sig) =
58 <PsbtInputSatisfier as Satisfier<XOnlyPublicKey>>::lookup_tap_key_spend_sig(sat)
59 {
60 return Ok(vec![sig.to_vec()]);
61 }
62 let (mut min_wit, mut min_wit_len) = (None, None);
64 if let Some(block_map) =
65 <PsbtInputSatisfier as Satisfier<XOnlyPublicKey>>::lookup_tap_control_block_map(sat)
66 {
67 for (control_block, (script, ver)) in block_map {
68 if *ver != LeafVersion::TapScript {
69 continue;
71 }
72 let ms = match Miniscript::<XOnlyPublicKey, Tap>::parse_with_ext(
73 script,
74 &ExtParams::allow_all(),
75 ) {
76 Ok(ms) => ms.substitute_raw_pkh(&map),
77 Err(..) => continue, };
79 let mut wit = if allow_mall {
80 match ms.satisfy_malleable(sat) {
81 Ok(ms) => ms,
82 Err(..) => continue,
83 }
84 } else {
85 match ms.satisfy(sat) {
86 Ok(ms) => ms,
87 Err(..) => continue,
88 }
89 };
90 wit.push(ms.encode().into_bytes());
91 wit.push(control_block.serialize());
92 let wit_len = Some(witness_size(&wit));
93 if min_wit_len.is_some() && wit_len > min_wit_len {
94 continue;
95 } else {
96 min_wit = Some(wit);
98 min_wit_len = wit_len;
99 }
100 }
101 min_wit.ok_or(InputError::CouldNotSatisfyTr)
102 } else {
103 Err(InputError::CouldNotSatisfyTr)
105 }
106}
107
108pub(super) fn get_scriptpubkey(psbt: &Psbt, index: usize) -> Result<ScriptBuf, InputError> {
110 get_utxo(psbt, index).map(|utxo| utxo.script_pubkey.clone())
111}
112
113pub(super) fn get_utxo(psbt: &Psbt, index: usize) -> Result<&bitcoin::TxOut, InputError> {
115 let inp = &psbt.inputs[index];
116 let utxo = if let Some(ref witness_utxo) = inp.witness_utxo {
117 witness_utxo
118 } else if let Some(ref non_witness_utxo) = inp.non_witness_utxo {
119 let vout = psbt.unsigned_tx.input[index].previous_output.vout;
120 &non_witness_utxo.output[vout as usize]
121 } else {
122 return Err(InputError::MissingUtxo);
123 };
124 Ok(utxo)
125}
126
127pub(super) fn prevouts(psbt: &Psbt) -> Result<Vec<&bitcoin::TxOut>, super::Error> {
129 let mut utxos = vec![];
130 for i in 0..psbt.inputs.len() {
131 let utxo_ref = get_utxo(psbt, i).map_err(|e| Error::InputError(e, i))?;
132 utxos.push(utxo_ref);
133 }
134 Ok(utxos)
135}
136
137fn get_descriptor(psbt: &Psbt, index: usize) -> Result<Descriptor<PublicKey>, InputError> {
146 let mut map: BTreeMap<hash160::Hash, PublicKey> = BTreeMap::new();
147 let psbt_inputs = &psbt.inputs;
148 for psbt_input in psbt_inputs {
149 let public_keys = psbt_input.bip32_derivation.keys();
151 for key in public_keys {
152 let bitcoin_key = bitcoin::PublicKey::new(*key);
153 let hash = bitcoin_key.pubkey_hash().to_raw_hash();
154 map.insert(hash, bitcoin_key);
155 }
156 }
157
158 let script_pubkey = get_scriptpubkey(psbt, index)?;
160 let inp = &psbt.inputs[index];
161 if script_pubkey.is_p2pk() {
163 let script_pubkey_len = script_pubkey.len();
164 let pk_bytes = &script_pubkey.to_bytes();
165 match bitcoin::PublicKey::from_slice(&pk_bytes[1..script_pubkey_len - 1]) {
166 Ok(pk) => Ok(Descriptor::new_pk(pk)),
167 Err(e) => Err(InputError::from(e)),
168 }
169 } else if script_pubkey.is_p2pkh() {
170 let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| {
172 let addr = bitcoin::Address::p2pkh(pk, bitcoin::Network::Bitcoin);
179 *script_pubkey == addr.script_pubkey()
180 });
181 match partial_sig_contains_pk {
182 Some((pk, _sig)) => Descriptor::new_pkh(*pk).map_err(InputError::from),
183 None => Err(InputError::MissingPubkey),
184 }
185 } else if script_pubkey.is_p2wpkh() {
186 let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| {
188 match bitcoin::key::CompressedPublicKey::try_from(pk) {
189 Ok(compressed) => {
190 let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin);
193 *script_pubkey == addr.script_pubkey()
194 }
195 Err(_) => false,
196 }
197 });
198 match partial_sig_contains_pk {
199 Some((pk, _sig)) => Ok(Descriptor::new_wpkh(*pk)?),
200 None => Err(InputError::MissingPubkey),
201 }
202 } else if script_pubkey.is_p2wsh() {
203 if inp.redeem_script.is_some() {
205 return Err(InputError::NonEmptyRedeemScript);
206 }
207 if let Some(ref witness_script) = inp.witness_script {
208 if witness_script.to_p2wsh() != *script_pubkey {
209 return Err(InputError::InvalidWitnessScript {
210 witness_script: witness_script.clone(),
211 p2wsh_expected: script_pubkey.clone(),
212 });
213 }
214 let ms = Miniscript::<bitcoin::PublicKey, Segwitv0>::parse_with_ext(
215 witness_script,
216 &ExtParams::allow_all(),
217 )?;
218 Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&map))?)
219 } else {
220 Err(InputError::MissingWitnessScript)
221 }
222 } else if script_pubkey.is_p2sh() {
223 match inp.redeem_script {
224 None => Err(InputError::MissingRedeemScript),
225 Some(ref redeem_script) => {
226 if redeem_script.to_p2sh() != *script_pubkey {
227 return Err(InputError::InvalidRedeemScript {
228 redeem: redeem_script.clone(),
229 p2sh_expected: script_pubkey.clone(),
230 });
231 }
232 if redeem_script.is_p2wsh() {
233 if let Some(ref witness_script) = inp.witness_script {
235 if witness_script.to_p2wsh() != *redeem_script {
236 return Err(InputError::InvalidWitnessScript {
237 witness_script: witness_script.clone(),
238 p2wsh_expected: redeem_script.clone(),
239 });
240 }
241 let ms = Miniscript::<bitcoin::PublicKey, Segwitv0>::parse_with_ext(
242 witness_script,
243 &ExtParams::allow_all(),
244 )?;
245 Ok(Descriptor::new_sh_wsh(ms.substitute_raw_pkh(&map))?)
246 } else {
247 Err(InputError::MissingWitnessScript)
248 }
249 } else if redeem_script.is_p2wpkh() {
250 let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| {
252 match bitcoin::key::CompressedPublicKey::try_from(pk) {
253 Ok(compressed) => {
254 let addr = bitcoin::Address::p2wpkh(
255 &compressed,
256 bitcoin::Network::Bitcoin,
257 );
258 *redeem_script == addr.script_pubkey()
259 }
260 Err(_) => false,
261 }
262 });
263 match partial_sig_contains_pk {
264 Some((pk, _sig)) => Ok(Descriptor::new_sh_wpkh(*pk)?),
265 None => Err(InputError::MissingPubkey),
266 }
267 } else {
268 if inp.witness_script.is_some() {
270 return Err(InputError::NonEmptyWitnessScript);
271 }
272 if let Some(ref redeem_script) = inp.redeem_script {
273 let ms = Miniscript::<bitcoin::PublicKey, Legacy>::parse_with_ext(
274 redeem_script,
275 &ExtParams::allow_all(),
276 )?;
277 Ok(Descriptor::new_sh(ms)?)
278 } else {
279 Err(InputError::MissingWitnessScript)
280 }
281 }
282 }
283 }
284 } else {
285 if inp.witness_script.is_some() {
287 return Err(InputError::NonEmptyWitnessScript);
288 }
289 if inp.redeem_script.is_some() {
290 return Err(InputError::NonEmptyRedeemScript);
291 }
292 let ms = Miniscript::<bitcoin::PublicKey, BareCtx>::parse_with_ext(
293 &script_pubkey,
294 &ExtParams::allow_all(),
295 )?;
296 Ok(Descriptor::new_bare(ms.substitute_raw_pkh(&map))?)
297 }
298}
299
300pub fn interpreter_check<C: secp256k1::Verification>(
306 psbt: &Psbt,
307 secp: &Secp256k1<C>,
308) -> Result<(), Error> {
309 let utxos = prevouts(psbt)?;
310 let utxos = &Prevouts::All(&utxos);
311 for (index, input) in psbt.inputs.iter().enumerate() {
312 let empty_script_sig = ScriptBuf::new();
313 let empty_witness = Witness::default();
314 let script_sig = input.final_script_sig.as_ref().unwrap_or(&empty_script_sig);
315 let witness = input
316 .final_script_witness
317 .as_ref()
318 .map(|wit_slice| Witness::from_slice(&wit_slice.to_vec())) .unwrap_or(empty_witness);
320
321 interpreter_inp_check(psbt, secp, index, utxos, &witness, script_sig)?;
322 }
323 Ok(())
324}
325
326fn interpreter_inp_check<C: secp256k1::Verification, T: Borrow<TxOut>>(
328 psbt: &Psbt,
329 secp: &Secp256k1<C>,
330 index: usize,
331 utxos: &Prevouts<T>,
332 witness: &Witness,
333 script_sig: &Script,
334) -> Result<(), Error> {
335 let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?;
336
337 {
341 let cltv = psbt.unsigned_tx.lock_time;
342 let csv = psbt.unsigned_tx.input[index].sequence;
343 let interpreter =
344 interpreter::Interpreter::from_txdata(&spk, script_sig, witness, csv, cltv)
345 .map_err(|e| Error::InputError(InputError::Interpreter(e), index))?;
346 let iter = interpreter.iter(secp, &psbt.unsigned_tx, index, utxos);
347 if let Some(error) = iter.filter_map(Result::err).next() {
348 return Err(Error::InputError(InputError::Interpreter(error), index));
349 };
350 }
351 Ok(())
352}
353
354#[deprecated(since = "7.0.0", note = "Please use PsbtExt::finalize instead")]
364pub fn finalize<C: secp256k1::Verification>(
365 psbt: &mut Psbt,
366 secp: &Secp256k1<C>,
367) -> Result<(), super::Error> {
368 finalize_helper(psbt, secp, false)
369}
370
371pub fn finalize_mall<C: secp256k1::Verification>(
373 psbt: &mut Psbt,
374 secp: &Secp256k1<C>,
375) -> Result<(), super::Error> {
376 finalize_helper(psbt, secp, true)
377}
378
379pub fn finalize_helper<C: secp256k1::Verification>(
380 psbt: &mut Psbt,
381 secp: &Secp256k1<C>,
382 allow_mall: bool,
383) -> Result<(), super::Error> {
384 sanity_check(psbt)?;
385
386 for index in 0..psbt.inputs.len() {
388 finalize_input(psbt, index, secp, allow_mall)?;
389 }
390 Ok(())
392}
393
394fn finalize_input_helper<C: secp256k1::Verification>(
397 psbt: &Psbt,
398 index: usize,
399 secp: &Secp256k1<C>,
400 allow_mall: bool,
401) -> Result<(Witness, ScriptBuf), super::Error> {
402 let (witness, script_sig) = {
403 let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?;
404 let sat = PsbtInputSatisfier::new(psbt, index);
405
406 if spk.is_p2tr() {
407 let wit = construct_tap_witness(&spk, &sat, allow_mall)
409 .map_err(|e| Error::InputError(e, index))?;
410 (wit, ScriptBuf::new())
411 } else {
412 let desc = get_descriptor(psbt, index).map_err(|e| Error::InputError(e, index))?;
414
415 let sat = PsbtInputSatisfier::new(psbt, index);
417 if !allow_mall {
418 desc.get_satisfaction(sat)
419 } else {
420 desc.get_satisfaction_mall(sat)
421 }
422 .map_err(|e| Error::InputError(InputError::MiniscriptError(e), index))?
423 }
424 };
425
426 let witness = bitcoin::Witness::from_slice(&witness);
427 let utxos = prevouts(psbt)?;
428 let utxos = &Prevouts::All(&utxos);
429 interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?;
430
431 Ok((witness, script_sig))
432}
433
434pub(super) fn finalize_input<C: secp256k1::Verification>(
435 psbt: &mut Psbt,
436 index: usize,
437 secp: &Secp256k1<C>,
438 allow_mall: bool,
439) -> Result<(), super::Error> {
440 let (witness, script_sig) = finalize_input_helper(psbt, index, secp, allow_mall)?;
441
442 {
445 let original = mem::take(&mut psbt.inputs[index]);
446 let input = &mut psbt.inputs[index];
447 input.non_witness_utxo = original.non_witness_utxo;
448 input.witness_utxo = original.witness_utxo;
449 input.final_script_sig = if script_sig.is_empty() {
450 None
451 } else {
452 Some(script_sig)
453 };
454 input.final_script_witness = if witness.is_empty() {
455 None
456 } else {
457 Some(witness)
458 };
459 }
460
461 Ok(())
462}
463
464#[cfg(test)]
465mod tests {
466 use bitcoin::hashes::hex::FromHex;
467
468 use super::*;
469 use crate::psbt::PsbtExt;
470
471 #[test]
472 fn tests_from_bip174() {
473 let mut psbt = Psbt::deserialize(&Vec::<u8>::from_hex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f012202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap();
474
475 let secp = Secp256k1::verification_only();
476 psbt.finalize_mut(&secp).unwrap();
477
478 let expected = Psbt::deserialize(&Vec::<u8>::from_hex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap();
479 assert_eq!(psbt, expected);
480 }
481}