1use core::convert::TryFrom;
23use core::fmt;
24use core::ops::Deref;
25#[cfg(feature = "std")]
26use std::error;
27
28use bitcoin::hashes::{hash160, sha256d, Hash};
29use bitcoin::secp256k1::{self, Secp256k1, VerifyOnly};
30use bitcoin::util::bip32;
31use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt};
32use bitcoin::util::sighash::SighashCache;
33use bitcoin::util::taproot::{self, ControlBlock, LeafVersion, TapLeafHash};
34use bitcoin::{self, EcdsaSighashType, LockTime, SchnorrSighashType, Script, Sequence};
35
36use crate::miniscript::context::SigType;
37use crate::prelude::*;
38use crate::{
39 descriptor, interpreter, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey,
40 Preimage32, Satisfier, ToPublicKey, TranslatePk, Translator,
41};
42
43mod finalizer;
44
45#[allow(deprecated)]
46pub use self::finalizer::{finalize, finalize_mall, interpreter_check};
47
48#[derive(Debug)]
50pub enum Error {
51 InputError(InputError, usize),
53 WrongInputCount {
55 in_tx: usize,
57 in_map: usize,
59 },
60 InputIdxOutofBounds {
62 psbt_inp: usize,
64 index: usize,
66 },
67}
68
69impl fmt::Display for Error {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 match *self {
72 Error::InputError(ref inp_err, index) => write!(f, "{} at index {}", inp_err, index),
73 Error::WrongInputCount { in_tx, in_map } => write!(
74 f,
75 "PSBT had {} inputs in transaction but {} inputs in map",
76 in_tx, in_map
77 ),
78 Error::InputIdxOutofBounds { psbt_inp, index } => write!(
79 f,
80 "psbt input index {} out of bounds: psbt.inputs.len() {}",
81 index, psbt_inp
82 ),
83 }
84 }
85}
86
87#[cfg(feature = "std")]
88impl error::Error for Error {
89 fn cause(&self) -> Option<&dyn error::Error> {
90 use self::Error::*;
91
92 match self {
93 InputError(e, _) => Some(e),
94 WrongInputCount { .. } | InputIdxOutofBounds { .. } => None,
95 }
96 }
97}
98
99#[derive(Debug)]
101pub enum InputError {
102 SecpErr(bitcoin::secp256k1::Error),
104 KeyErr(bitcoin::util::key::Error),
106 CouldNotSatisfyTr,
111 Interpreter(interpreter::Error),
113 InvalidRedeemScript {
115 redeem: Script,
117 p2sh_expected: Script,
119 },
120 InvalidWitnessScript {
122 witness_script: Script,
124 p2wsh_expected: Script,
126 },
127 InvalidSignature {
129 pubkey: bitcoin::PublicKey,
131 sig: Vec<u8>,
133 },
134 MiniscriptError(super::Error),
136 MissingRedeemScript,
138 MissingWitness,
140 MissingPubkey,
142 MissingWitnessScript,
144 MissingUtxo,
146 NonEmptyWitnessScript,
148 NonEmptyRedeemScript,
150 NonStandardSighashType(bitcoin::blockdata::transaction::NonStandardSighashType),
152 WrongSighashFlag {
154 required: bitcoin::EcdsaSighashType,
156 got: bitcoin::EcdsaSighashType,
158 pubkey: bitcoin::PublicKey,
160 },
161}
162
163#[cfg(feature = "std")]
164impl error::Error for InputError {
165 fn cause(&self) -> Option<&dyn error::Error> {
166 use self::InputError::*;
167
168 match self {
169 CouldNotSatisfyTr
170 | InvalidRedeemScript { .. }
171 | InvalidWitnessScript { .. }
172 | InvalidSignature { .. }
173 | MissingRedeemScript
174 | MissingWitness
175 | MissingPubkey
176 | MissingWitnessScript
177 | MissingUtxo
178 | NonEmptyWitnessScript
179 | NonEmptyRedeemScript
180 | NonStandardSighashType(_)
181 | WrongSighashFlag { .. } => None,
182 SecpErr(e) => Some(e),
183 KeyErr(e) => Some(e),
184 Interpreter(e) => Some(e),
185 MiniscriptError(e) => Some(e),
186 }
187 }
188}
189
190impl fmt::Display for InputError {
191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192 match *self {
193 InputError::InvalidSignature {
194 ref pubkey,
195 ref sig,
196 } => write!(f, "PSBT: bad signature {} for key {:?}", pubkey, sig),
197 InputError::KeyErr(ref e) => write!(f, "Key Err: {}", e),
198 InputError::Interpreter(ref e) => write!(f, "Interpreter: {}", e),
199 InputError::SecpErr(ref e) => write!(f, "Secp Err: {}", e),
200 InputError::InvalidRedeemScript {
201 ref redeem,
202 ref p2sh_expected,
203 } => write!(
204 f,
205 "Redeem script {} does not match the p2sh script {}",
206 redeem, p2sh_expected
207 ),
208 InputError::InvalidWitnessScript {
209 ref witness_script,
210 ref p2wsh_expected,
211 } => write!(
212 f,
213 "Witness script {} does not match the p2wsh script {}",
214 witness_script, p2wsh_expected
215 ),
216 InputError::MiniscriptError(ref e) => write!(f, "Miniscript Error: {}", e),
217 InputError::MissingWitness => write!(f, "PSBT is missing witness"),
218 InputError::MissingRedeemScript => write!(f, "PSBT is Redeem script"),
219 InputError::MissingUtxo => {
220 write!(f, "PSBT is missing both witness and non-witness UTXO")
221 }
222 InputError::MissingWitnessScript => write!(f, "PSBT is missing witness script"),
223 InputError::MissingPubkey => write!(f, "Missing pubkey for a pkh/wpkh"),
224 InputError::NonEmptyRedeemScript => write!(
225 f,
226 "PSBT has non-empty redeem script at for legacy transactions"
227 ),
228 InputError::NonEmptyWitnessScript => {
229 write!(f, "PSBT has non-empty witness script at for legacy input")
230 }
231 InputError::WrongSighashFlag {
232 required,
233 got,
234 pubkey,
235 } => write!(
236 f,
237 "PSBT: signature with key {:?} had \
238 sighashflag {:?} rather than required {:?}",
239 pubkey, got, required
240 ),
241 InputError::CouldNotSatisfyTr => write!(f, "Could not satisfy Tr descriptor"),
242 InputError::NonStandardSighashType(e) => write!(f, "Non-standard sighash type {}", e),
243 }
244 }
245}
246
247#[doc(hidden)]
248impl From<super::Error> for InputError {
249 fn from(e: super::Error) -> InputError {
250 InputError::MiniscriptError(e)
251 }
252}
253
254#[doc(hidden)]
255impl From<bitcoin::secp256k1::Error> for InputError {
256 fn from(e: bitcoin::secp256k1::Error) -> InputError {
257 InputError::SecpErr(e)
258 }
259}
260
261#[doc(hidden)]
262impl From<bitcoin::util::key::Error> for InputError {
263 fn from(e: bitcoin::util::key::Error) -> InputError {
264 InputError::KeyErr(e)
265 }
266}
267
268pub struct PsbtInputSatisfier<'psbt> {
274 pub psbt: &'psbt Psbt,
276 pub index: usize,
278}
279
280impl<'psbt> PsbtInputSatisfier<'psbt> {
281 pub fn new(psbt: &'psbt Psbt, index: usize) -> Self {
284 Self { psbt, index }
285 }
286}
287
288impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for PsbtInputSatisfier<'psbt> {
289 fn lookup_tap_key_spend_sig(&self) -> Option<bitcoin::SchnorrSig> {
290 self.psbt.inputs[self.index].tap_key_sig
291 }
292
293 fn lookup_tap_leaf_script_sig(&self, pk: &Pk, lh: &TapLeafHash) -> Option<bitcoin::SchnorrSig> {
294 self.psbt.inputs[self.index]
295 .tap_script_sigs
296 .get(&(pk.to_x_only_pubkey(), *lh))
297 .copied()
298 }
299
300 fn lookup_raw_pkh_pk(&self, pkh: &hash160::Hash) -> Option<bitcoin::PublicKey> {
301 self.psbt.inputs[self.index]
302 .bip32_derivation
303 .iter()
304 .find(|&(pubkey, _)| pubkey.to_pubkeyhash(SigType::Ecdsa) == *pkh)
305 .map(|(pubkey, _)| bitcoin::PublicKey::new(*pubkey))
306 }
307
308 fn lookup_tap_control_block_map(
309 &self,
310 ) -> Option<&BTreeMap<ControlBlock, (bitcoin::Script, LeafVersion)>> {
311 Some(&self.psbt.inputs[self.index].tap_scripts)
312 }
313
314 fn lookup_raw_pkh_tap_leaf_script_sig(
315 &self,
316 pkh: &(hash160::Hash, TapLeafHash),
317 ) -> Option<(bitcoin::secp256k1::XOnlyPublicKey, bitcoin::SchnorrSig)> {
318 self.psbt.inputs[self.index]
319 .tap_script_sigs
320 .iter()
321 .find(|&((pubkey, lh), _sig)| {
322 pubkey.to_pubkeyhash(SigType::Schnorr) == pkh.0 && *lh == pkh.1
323 })
324 .map(|((x_only_pk, _leaf_hash), sig)| (*x_only_pk, *sig))
325 }
326
327 fn lookup_ecdsa_sig(&self, pk: &Pk) -> Option<bitcoin::EcdsaSig> {
328 self.psbt.inputs[self.index]
329 .partial_sigs
330 .get(&pk.to_public_key())
331 .copied()
332 }
333
334 fn lookup_raw_pkh_ecdsa_sig(
335 &self,
336 pkh: &hash160::Hash,
337 ) -> Option<(bitcoin::PublicKey, bitcoin::EcdsaSig)> {
338 self.psbt.inputs[self.index]
339 .partial_sigs
340 .iter()
341 .find(|&(pubkey, _sig)| pubkey.to_pubkeyhash(SigType::Ecdsa) == *pkh)
342 .map(|(pk, sig)| (*pk, *sig))
343 }
344
345 fn check_after(&self, n: LockTime) -> bool {
346 if !self.psbt.unsigned_tx.input[self.index].enables_lock_time() {
347 return false;
348 }
349
350 let lock_time = LockTime::from(self.psbt.unsigned_tx.lock_time);
351
352 <dyn Satisfier<Pk>>::check_after(&lock_time, n)
353 }
354
355 fn check_older(&self, n: Sequence) -> bool {
356 let seq = self.psbt.unsigned_tx.input[self.index].sequence;
357
358 if !n.is_relative_lock_time() {
361 return true;
362 }
363
364 if self.psbt.unsigned_tx.version < 2 || !seq.is_relative_lock_time() {
365 return false;
366 }
367
368 <dyn Satisfier<Pk>>::check_older(&seq, n)
369 }
370
371 fn lookup_hash160(&self, h: &Pk::Hash160) -> Option<Preimage32> {
372 self.psbt.inputs[self.index]
373 .hash160_preimages
374 .get(&Pk::to_hash160(h))
375 .and_then(try_vec_as_preimage32)
376 }
377
378 fn lookup_sha256(&self, h: &Pk::Sha256) -> Option<Preimage32> {
379 self.psbt.inputs[self.index]
380 .sha256_preimages
381 .get(&Pk::to_sha256(h))
382 .and_then(try_vec_as_preimage32)
383 }
384
385 fn lookup_hash256(&self, h: &Pk::Hash256) -> Option<Preimage32> {
386 self.psbt.inputs[self.index]
387 .hash256_preimages
388 .get(&sha256d::Hash::from_inner(Pk::to_hash256(h).into_inner())) .and_then(try_vec_as_preimage32)
390 }
391
392 fn lookup_ripemd160(&self, h: &Pk::Ripemd160) -> Option<Preimage32> {
393 self.psbt.inputs[self.index]
394 .ripemd160_preimages
395 .get(&Pk::to_ripemd160(h))
396 .and_then(try_vec_as_preimage32)
397 }
398}
399
400fn try_vec_as_preimage32(vec: &Vec<u8>) -> Option<Preimage32> {
401 if vec.len() == 32 {
402 let mut arr = [0u8; 32];
403 arr.copy_from_slice(vec);
404 Some(arr)
405 } else {
406 None
407 }
408}
409
410fn sanity_check(psbt: &Psbt) -> Result<(), Error> {
414 if psbt.unsigned_tx.input.len() != psbt.inputs.len() {
415 return Err(Error::WrongInputCount {
416 in_tx: psbt.unsigned_tx.input.len(),
417 in_map: psbt.inputs.len(),
418 });
419 }
420
421 for (index, input) in psbt.inputs.iter().enumerate() {
423 let target_ecdsa_sighash_ty = match input.sighash_type {
425 Some(psbt_hash_ty) => psbt_hash_ty
426 .ecdsa_hash_ty()
427 .map_err(|e| Error::InputError(InputError::NonStandardSighashType(e), index))?,
428 None => EcdsaSighashType::All,
429 };
430 for (key, ecdsa_sig) in &input.partial_sigs {
431 let flag = bitcoin::EcdsaSighashType::from_standard(ecdsa_sig.hash_ty as u32).map_err(
432 |_| {
433 Error::InputError(
434 InputError::Interpreter(interpreter::Error::NonStandardSighash(
435 ecdsa_sig.to_vec(),
436 )),
437 index,
438 )
439 },
440 )?;
441 if target_ecdsa_sighash_ty != flag {
442 return Err(Error::InputError(
443 InputError::WrongSighashFlag {
444 required: target_ecdsa_sighash_ty,
445 got: flag,
446 pubkey: *key,
447 },
448 index,
449 ));
450 }
451 }
453 }
454
455 Ok(())
456}
457
458pub trait PsbtExt {
462 fn finalize_mut<C: secp256k1::Verification>(
479 &mut self,
480 secp: &secp256k1::Secp256k1<C>,
481 ) -> Result<(), Vec<Error>>;
482
483 fn finalize<C: secp256k1::Verification>(
491 self,
492 secp: &secp256k1::Secp256k1<C>,
493 ) -> Result<Psbt, (Psbt, Vec<Error>)>;
494
495 fn finalize_mall_mut<C: secp256k1::Verification>(
497 &mut self,
498 secp: &Secp256k1<C>,
499 ) -> Result<(), Vec<Error>>;
500
501 fn finalize_mall<C: secp256k1::Verification>(
503 self,
504 secp: &Secp256k1<C>,
505 ) -> Result<Psbt, (Psbt, Vec<Error>)>;
506
507 fn finalize_inp_mut<C: secp256k1::Verification>(
515 &mut self,
516 secp: &secp256k1::Secp256k1<C>,
517 index: usize,
518 ) -> Result<(), Error>;
519
520 fn finalize_inp<C: secp256k1::Verification>(
527 self,
528 secp: &secp256k1::Secp256k1<C>,
529 index: usize,
530 ) -> Result<Psbt, (Psbt, Error)>;
531
532 fn finalize_inp_mall_mut<C: secp256k1::Verification>(
534 &mut self,
535 secp: &secp256k1::Secp256k1<C>,
536 index: usize,
537 ) -> Result<(), Error>;
538
539 fn finalize_inp_mall<C: secp256k1::Verification>(
541 self,
542 secp: &secp256k1::Secp256k1<C>,
543 index: usize,
544 ) -> Result<Psbt, (Psbt, Error)>;
545
546 fn extract<C: secp256k1::Verification>(
552 &self,
553 secp: &Secp256k1<C>,
554 ) -> Result<bitcoin::Transaction, Error>;
555
556 fn update_input_with_descriptor(
575 &mut self,
576 input_index: usize,
577 descriptor: &Descriptor<DefiniteDescriptorKey>,
578 ) -> Result<(), UtxoUpdateError>;
579
580 fn update_output_with_descriptor(
590 &mut self,
591 output_index: usize,
592 descriptor: &Descriptor<DefiniteDescriptorKey>,
593 ) -> Result<(), OutputUpdateError>;
594
595 fn sighash_msg<T: Deref<Target = bitcoin::Transaction>>(
614 &self,
615 idx: usize,
616 cache: &mut SighashCache<T>,
617 tapleaf_hash: Option<TapLeafHash>,
618 ) -> Result<PsbtSighashMsg, SighashError>;
619}
620
621impl PsbtExt for Psbt {
622 fn finalize_mut<C: secp256k1::Verification>(
623 &mut self,
624 secp: &secp256k1::Secp256k1<C>,
625 ) -> Result<(), Vec<Error>> {
626 let mut errors = vec![];
628 for index in 0..self.inputs.len() {
629 match finalizer::finalize_input(self, index, secp, false) {
630 Ok(..) => {}
631 Err(e) => {
632 errors.push(e);
633 }
634 }
635 }
636 if errors.is_empty() {
637 Ok(())
638 } else {
639 Err(errors)
640 }
641 }
642
643 fn finalize<C: secp256k1::Verification>(
644 mut self,
645 secp: &secp256k1::Secp256k1<C>,
646 ) -> Result<Psbt, (Psbt, Vec<Error>)> {
647 match self.finalize_mut(secp) {
648 Ok(..) => Ok(self),
649 Err(e) => Err((self, e)),
650 }
651 }
652
653 fn finalize_mall_mut<C: secp256k1::Verification>(
654 &mut self,
655 secp: &secp256k1::Secp256k1<C>,
656 ) -> Result<(), Vec<Error>> {
657 let mut errors = vec![];
658 for index in 0..self.inputs.len() {
659 match finalizer::finalize_input(self, index, secp, true) {
660 Ok(..) => {}
661 Err(e) => {
662 errors.push(e);
663 }
664 }
665 }
666 if errors.is_empty() {
667 Ok(())
668 } else {
669 Err(errors)
670 }
671 }
672
673 fn finalize_mall<C: secp256k1::Verification>(
674 mut self,
675 secp: &Secp256k1<C>,
676 ) -> Result<Psbt, (Psbt, Vec<Error>)> {
677 match self.finalize_mall_mut(secp) {
678 Ok(..) => Ok(self),
679 Err(e) => Err((self, e)),
680 }
681 }
682
683 fn finalize_inp_mut<C: secp256k1::Verification>(
684 &mut self,
685 secp: &secp256k1::Secp256k1<C>,
686 index: usize,
687 ) -> Result<(), Error> {
688 if index >= self.inputs.len() {
689 return Err(Error::InputIdxOutofBounds {
690 psbt_inp: self.inputs.len(),
691 index,
692 });
693 }
694 finalizer::finalize_input(self, index, secp, false)
695 }
696
697 fn finalize_inp<C: secp256k1::Verification>(
698 mut self,
699 secp: &secp256k1::Secp256k1<C>,
700 index: usize,
701 ) -> Result<Psbt, (Psbt, Error)> {
702 match self.finalize_inp_mut(secp, index) {
703 Ok(..) => Ok(self),
704 Err(e) => Err((self, e)),
705 }
706 }
707
708 fn finalize_inp_mall_mut<C: secp256k1::Verification>(
709 &mut self,
710 secp: &secp256k1::Secp256k1<C>,
711 index: usize,
712 ) -> Result<(), Error> {
713 if index >= self.inputs.len() {
714 return Err(Error::InputIdxOutofBounds {
715 psbt_inp: self.inputs.len(),
716 index,
717 });
718 }
719 finalizer::finalize_input(self, index, secp, false)
720 }
721
722 fn finalize_inp_mall<C: secp256k1::Verification>(
723 mut self,
724 secp: &secp256k1::Secp256k1<C>,
725 index: usize,
726 ) -> Result<Psbt, (Psbt, Error)> {
727 match self.finalize_inp_mall_mut(secp, index) {
728 Ok(..) => Ok(self),
729 Err(e) => Err((self, e)),
730 }
731 }
732
733 fn extract<C: secp256k1::Verification>(
734 &self,
735 secp: &Secp256k1<C>,
736 ) -> Result<bitcoin::Transaction, Error> {
737 sanity_check(self)?;
738
739 let mut ret = self.unsigned_tx.clone();
740 for (n, input) in self.inputs.iter().enumerate() {
741 if input.final_script_sig.is_none() && input.final_script_witness.is_none() {
742 return Err(Error::InputError(InputError::MissingWitness, n));
743 }
744
745 if let Some(witness) = input.final_script_witness.as_ref() {
746 ret.input[n].witness = witness.clone();
747 }
748 if let Some(script_sig) = input.final_script_sig.as_ref() {
749 ret.input[n].script_sig = script_sig.clone();
750 }
751 }
752 interpreter_check(self, secp)?;
753 Ok(ret)
754 }
755
756 fn update_input_with_descriptor(
757 &mut self,
758 input_index: usize,
759 desc: &Descriptor<DefiniteDescriptorKey>,
760 ) -> Result<(), UtxoUpdateError> {
761 let n_inputs = self.inputs.len();
762 let input = self
763 .inputs
764 .get_mut(input_index)
765 .ok_or(UtxoUpdateError::IndexOutOfBounds(input_index, n_inputs))?;
766 let txin = self
767 .unsigned_tx
768 .input
769 .get(input_index)
770 .ok_or(UtxoUpdateError::MissingInputUtxo)?;
771
772 let desc_type = desc.desc_type();
773
774 if let Some(non_witness_utxo) = &input.non_witness_utxo {
775 if txin.previous_output.txid != non_witness_utxo.txid() {
776 return Err(UtxoUpdateError::UtxoCheck);
777 }
778 }
779
780 let expected_spk = {
781 match (&input.witness_utxo, &input.non_witness_utxo) {
782 (Some(witness_utxo), None) => {
783 if desc_type.segwit_version().is_some() {
784 witness_utxo.script_pubkey.clone()
785 } else {
786 return Err(UtxoUpdateError::UtxoCheck);
787 }
788 }
789 (None, Some(non_witness_utxo)) => non_witness_utxo
790 .output
791 .get(txin.previous_output.vout as usize)
792 .ok_or(UtxoUpdateError::UtxoCheck)?
793 .script_pubkey
794 .clone(),
795 (Some(witness_utxo), Some(non_witness_utxo)) => {
796 if witness_utxo
797 != non_witness_utxo
798 .output
799 .get(txin.previous_output.vout as usize)
800 .ok_or(UtxoUpdateError::UtxoCheck)?
801 {
802 return Err(UtxoUpdateError::UtxoCheck);
803 }
804
805 witness_utxo.script_pubkey.clone()
806 }
807 (None, None) => return Err(UtxoUpdateError::UtxoCheck),
808 }
809 };
810
811 let (_, spk_check_passed) =
812 update_item_with_descriptor_helper(input, desc, Some(&expected_spk))
813 .map_err(UtxoUpdateError::DerivationError)?;
814
815 if !spk_check_passed {
816 return Err(UtxoUpdateError::MismatchedScriptPubkey);
817 }
818
819 Ok(())
820 }
821
822 fn update_output_with_descriptor(
823 &mut self,
824 output_index: usize,
825 desc: &Descriptor<DefiniteDescriptorKey>,
826 ) -> Result<(), OutputUpdateError> {
827 let n_outputs = self.outputs.len();
828 let output = self
829 .outputs
830 .get_mut(output_index)
831 .ok_or(OutputUpdateError::IndexOutOfBounds(output_index, n_outputs))?;
832 let txout = self
833 .unsigned_tx
834 .output
835 .get(output_index)
836 .ok_or(OutputUpdateError::MissingTxOut)?;
837
838 let (_, spk_check_passed) =
839 update_item_with_descriptor_helper(output, desc, Some(&txout.script_pubkey))
840 .map_err(OutputUpdateError::DerivationError)?;
841
842 if !spk_check_passed {
843 return Err(OutputUpdateError::MismatchedScriptPubkey);
844 }
845
846 Ok(())
847 }
848
849 fn sighash_msg<T: Deref<Target = bitcoin::Transaction>>(
850 &self,
851 idx: usize,
852 cache: &mut SighashCache<T>,
853 tapleaf_hash: Option<TapLeafHash>,
854 ) -> Result<PsbtSighashMsg, SighashError> {
855 if idx >= self.inputs.len() {
857 return Err(SighashError::IndexOutOfBounds(idx, self.inputs.len()));
858 }
859 let inp = &self.inputs[idx];
860 let prevouts = finalizer::prevouts(self).map_err(|_e| SighashError::MissingSpendUtxos)?;
861 let prevouts = bitcoin::util::sighash::Prevouts::All(&prevouts);
864 let inp_spk =
865 finalizer::get_scriptpubkey(self, idx).map_err(|_e| SighashError::MissingInputUtxo)?;
866 if inp_spk.is_v1_p2tr() {
867 let hash_ty = inp
868 .sighash_type
869 .map(|sighash_type| sighash_type.schnorr_hash_ty())
870 .unwrap_or(Ok(SchnorrSighashType::Default))
871 .map_err(|_e| SighashError::InvalidSighashType)?;
872 match tapleaf_hash {
873 Some(leaf_hash) => {
874 let tap_sighash_msg = cache
875 .taproot_script_spend_signature_hash(idx, &prevouts, leaf_hash, hash_ty)?;
876 Ok(PsbtSighashMsg::TapSighash(tap_sighash_msg))
877 }
878 None => {
879 let tap_sighash_msg =
880 cache.taproot_key_spend_signature_hash(idx, &prevouts, hash_ty)?;
881 Ok(PsbtSighashMsg::TapSighash(tap_sighash_msg))
882 }
883 }
884 } else {
885 let hash_ty = inp
886 .sighash_type
887 .map(|sighash_type| sighash_type.ecdsa_hash_ty())
888 .unwrap_or(Ok(EcdsaSighashType::All))
889 .map_err(|_e| SighashError::InvalidSighashType)?;
890 let amt = finalizer::get_utxo(self, idx)
891 .map_err(|_e| SighashError::MissingInputUtxo)?
892 .value;
893 let is_nested_wpkh = inp_spk.is_p2sh()
894 && inp
895 .redeem_script
896 .as_ref()
897 .map(|x| x.is_v0_p2wpkh())
898 .unwrap_or(false);
899 let is_nested_wsh = inp_spk.is_p2sh()
900 && inp
901 .redeem_script
902 .as_ref()
903 .map(|x| x.is_v0_p2wsh())
904 .unwrap_or(false);
905 if inp_spk.is_v0_p2wpkh() || inp_spk.is_v0_p2wsh() || is_nested_wpkh || is_nested_wsh {
906 let msg = if inp_spk.is_v0_p2wpkh() {
907 let script_code = script_code_wpkh(inp_spk);
908 cache.segwit_signature_hash(idx, &script_code, amt, hash_ty)?
909 } else if is_nested_wpkh {
910 let script_code = script_code_wpkh(
911 inp.redeem_script
912 .as_ref()
913 .expect("Redeem script non-empty checked earlier"),
914 );
915 cache.segwit_signature_hash(idx, &script_code, amt, hash_ty)?
916 } else {
917 let script_code = inp
919 .witness_script
920 .as_ref()
921 .ok_or(SighashError::MissingWitnessScript)?;
922 cache.segwit_signature_hash(idx, script_code, amt, hash_ty)?
923 };
924 Ok(PsbtSighashMsg::EcdsaSighash(msg))
925 } else {
926 let script_code = if inp_spk.is_p2sh() {
928 inp.redeem_script
929 .as_ref()
930 .ok_or(SighashError::MissingRedeemScript)?
931 } else {
932 inp_spk
933 };
934 let msg = cache.legacy_signature_hash(idx, script_code, hash_ty.to_u32())?;
935 Ok(PsbtSighashMsg::EcdsaSighash(msg))
936 }
937 }
938 }
939}
940
941pub trait PsbtInputExt {
943 fn update_with_descriptor_unchecked(
960 &mut self,
961 descriptor: &Descriptor<DefiniteDescriptorKey>,
962 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError>;
963}
964
965impl PsbtInputExt for psbt::Input {
966 fn update_with_descriptor_unchecked(
967 &mut self,
968 descriptor: &Descriptor<DefiniteDescriptorKey>,
969 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError> {
970 let (derived, _) = update_item_with_descriptor_helper(self, descriptor, None)?;
971 Ok(derived)
972 }
973}
974
975pub trait PsbtOutputExt {
977 fn update_with_descriptor_unchecked(
994 &mut self,
995 descriptor: &Descriptor<DefiniteDescriptorKey>,
996 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError>;
997}
998
999impl PsbtOutputExt for psbt::Output {
1000 fn update_with_descriptor_unchecked(
1001 &mut self,
1002 descriptor: &Descriptor<DefiniteDescriptorKey>,
1003 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError> {
1004 let (derived, _) = update_item_with_descriptor_helper(self, descriptor, None)?;
1005 Ok(derived)
1006 }
1007}
1008
1009struct KeySourceLookUp(
1012 pub BTreeMap<secp256k1::PublicKey, bip32::KeySource>,
1013 pub secp256k1::Secp256k1<VerifyOnly>,
1014);
1015
1016impl Translator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
1017 for KeySourceLookUp
1018{
1019 fn pk(
1020 &mut self,
1021 xpk: &DefiniteDescriptorKey,
1022 ) -> Result<bitcoin::PublicKey, descriptor::ConversionError> {
1023 let derived = xpk.derive_public_key(&self.1)?;
1024 self.0.insert(
1025 derived.to_public_key().inner,
1026 (xpk.master_fingerprint(), xpk.full_derivation_path()),
1027 );
1028 Ok(derived)
1029 }
1030
1031 translate_hash_clone!(
1032 DescriptorPublicKey,
1033 bitcoin::PublicKey,
1034 descriptor::ConversionError
1035 );
1036}
1037
1038trait PsbtFields {
1040 fn redeem_script(&mut self) -> &mut Option<Script>;
1042 fn witness_script(&mut self) -> &mut Option<Script>;
1043 fn bip32_derivation(&mut self) -> &mut BTreeMap<secp256k1::PublicKey, bip32::KeySource>;
1044 fn tap_internal_key(&mut self) -> &mut Option<bitcoin::XOnlyPublicKey>;
1045 fn tap_key_origins(
1046 &mut self,
1047 ) -> &mut BTreeMap<bitcoin::XOnlyPublicKey, (Vec<TapLeafHash>, bip32::KeySource)>;
1048 fn proprietary(&mut self) -> &mut BTreeMap<psbt::raw::ProprietaryKey, Vec<u8>>;
1049 fn unknown(&mut self) -> &mut BTreeMap<psbt::raw::Key, Vec<u8>>;
1050
1051 fn tap_tree(&mut self) -> Option<&mut Option<psbt::TapTree>> {
1053 None
1054 }
1055
1056 fn tap_scripts(&mut self) -> Option<&mut BTreeMap<ControlBlock, (Script, LeafVersion)>> {
1058 None
1059 }
1060 fn tap_merkle_root(&mut self) -> Option<&mut Option<taproot::TapBranchHash>> {
1061 None
1062 }
1063}
1064
1065impl PsbtFields for psbt::Input {
1066 fn redeem_script(&mut self) -> &mut Option<Script> {
1067 &mut self.redeem_script
1068 }
1069 fn witness_script(&mut self) -> &mut Option<Script> {
1070 &mut self.witness_script
1071 }
1072 fn bip32_derivation(&mut self) -> &mut BTreeMap<secp256k1::PublicKey, bip32::KeySource> {
1073 &mut self.bip32_derivation
1074 }
1075 fn tap_internal_key(&mut self) -> &mut Option<bitcoin::XOnlyPublicKey> {
1076 &mut self.tap_internal_key
1077 }
1078 fn tap_key_origins(
1079 &mut self,
1080 ) -> &mut BTreeMap<bitcoin::XOnlyPublicKey, (Vec<TapLeafHash>, bip32::KeySource)> {
1081 &mut self.tap_key_origins
1082 }
1083 fn proprietary(&mut self) -> &mut BTreeMap<psbt::raw::ProprietaryKey, Vec<u8>> {
1084 &mut self.proprietary
1085 }
1086 fn unknown(&mut self) -> &mut BTreeMap<psbt::raw::Key, Vec<u8>> {
1087 &mut self.unknown
1088 }
1089
1090 fn tap_scripts(&mut self) -> Option<&mut BTreeMap<ControlBlock, (Script, LeafVersion)>> {
1091 Some(&mut self.tap_scripts)
1092 }
1093 fn tap_merkle_root(&mut self) -> Option<&mut Option<taproot::TapBranchHash>> {
1094 Some(&mut self.tap_merkle_root)
1095 }
1096}
1097
1098impl PsbtFields for psbt::Output {
1099 fn redeem_script(&mut self) -> &mut Option<Script> {
1100 &mut self.redeem_script
1101 }
1102 fn witness_script(&mut self) -> &mut Option<Script> {
1103 &mut self.witness_script
1104 }
1105 fn bip32_derivation(&mut self) -> &mut BTreeMap<secp256k1::PublicKey, bip32::KeySource> {
1106 &mut self.bip32_derivation
1107 }
1108 fn tap_internal_key(&mut self) -> &mut Option<bitcoin::XOnlyPublicKey> {
1109 &mut self.tap_internal_key
1110 }
1111 fn tap_key_origins(
1112 &mut self,
1113 ) -> &mut BTreeMap<bitcoin::XOnlyPublicKey, (Vec<TapLeafHash>, bip32::KeySource)> {
1114 &mut self.tap_key_origins
1115 }
1116 fn proprietary(&mut self) -> &mut BTreeMap<psbt::raw::ProprietaryKey, Vec<u8>> {
1117 &mut self.proprietary
1118 }
1119 fn unknown(&mut self) -> &mut BTreeMap<psbt::raw::Key, Vec<u8>> {
1120 &mut self.unknown
1121 }
1122
1123 fn tap_tree(&mut self) -> Option<&mut Option<psbt::TapTree>> {
1124 Some(&mut self.tap_tree)
1125 }
1126}
1127
1128fn update_item_with_descriptor_helper<F: PsbtFields>(
1129 item: &mut F,
1130 descriptor: &Descriptor<DefiniteDescriptorKey>,
1131 check_script: Option<&Script>,
1132 ) -> Result<(Descriptor<bitcoin::PublicKey>, bool), descriptor::ConversionError> {
1136 let secp = secp256k1::Secp256k1::verification_only();
1137
1138 let derived = if let Descriptor::Tr(_) = &descriptor {
1139 let derived = descriptor.derived_descriptor(&secp)?;
1140
1141 if let Some(check_script) = check_script {
1142 if check_script != &derived.script_pubkey() {
1143 return Ok((derived, false));
1144 }
1145 }
1146
1147 if let (Descriptor::Tr(tr_derived), Descriptor::Tr(tr_xpk)) = (&derived, descriptor) {
1149 let spend_info = tr_derived.spend_info();
1150 let ik_derived = spend_info.internal_key();
1151 let ik_xpk = tr_xpk.internal_key();
1152 if let Some(merkle_root) = item.tap_merkle_root() {
1153 *merkle_root = spend_info.merkle_root();
1154 }
1155 *item.tap_internal_key() = Some(ik_derived);
1156 item.tap_key_origins().insert(
1157 ik_derived,
1158 (
1159 vec![],
1160 (ik_xpk.master_fingerprint(), ik_xpk.full_derivation_path()),
1161 ),
1162 );
1163
1164 let mut builder = taproot::TaprootBuilder::new();
1165
1166 for ((_depth_der, ms_derived), (depth, ms)) in
1167 tr_derived.iter_scripts().zip(tr_xpk.iter_scripts())
1168 {
1169 debug_assert_eq!(_depth_der, depth);
1170 let leaf_script = (ms_derived.encode(), LeafVersion::TapScript);
1171 let tapleaf_hash = TapLeafHash::from_script(&leaf_script.0, leaf_script.1);
1172 builder = builder
1173 .add_leaf(depth, leaf_script.0.clone())
1174 .expect("Computing spend data on a valid tree should always succeed");
1175 if let Some(tap_scripts) = item.tap_scripts() {
1176 let control_block = spend_info
1177 .control_block(&leaf_script)
1178 .expect("Control block must exist in script map for every known leaf");
1179 tap_scripts.insert(control_block, leaf_script);
1180 }
1181
1182 for (pk_pkh_derived, pk_pkh_xpk) in ms_derived.iter_pk().zip(ms.iter_pk()) {
1183 let (xonly, xpk) = (pk_pkh_derived.to_x_only_pubkey(), pk_pkh_xpk);
1184
1185 item.tap_key_origins()
1186 .entry(xonly)
1187 .and_modify(|(tapleaf_hashes, _)| {
1188 if tapleaf_hashes.last() != Some(&tapleaf_hash) {
1189 tapleaf_hashes.push(tapleaf_hash);
1190 }
1191 })
1192 .or_insert_with(|| {
1193 (
1194 vec![tapleaf_hash],
1195 (xpk.master_fingerprint(), xpk.full_derivation_path()),
1196 )
1197 });
1198 }
1199 }
1200
1201 for (tapleaf_hashes, _) in item.tap_key_origins().values_mut() {
1205 tapleaf_hashes.sort();
1206 tapleaf_hashes.dedup();
1207 }
1208
1209 match item.tap_tree() {
1210 Some(tap_tree) if tr_derived.taptree().is_some() => {
1213 *tap_tree = Some(
1214 psbt::TapTree::try_from(builder).expect("The tree should always be valid"),
1215 );
1216 }
1217 _ => {}
1218 }
1219 }
1220
1221 derived
1222 } else {
1223 let mut bip32_derivation = KeySourceLookUp(BTreeMap::new(), Secp256k1::verification_only());
1224 let derived = descriptor.translate_pk(&mut bip32_derivation)?;
1225
1226 if let Some(check_script) = check_script {
1227 if check_script != &derived.script_pubkey() {
1228 return Ok((derived, false));
1229 }
1230 }
1231
1232 item.bip32_derivation().append(&mut bip32_derivation.0);
1233
1234 match &derived {
1235 Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {}
1236 Descriptor::Sh(sh) => match sh.as_inner() {
1237 descriptor::ShInner::Wsh(wsh) => {
1238 *item.witness_script() = Some(wsh.inner_script());
1239 *item.redeem_script() = Some(wsh.inner_script().to_v0_p2wsh());
1240 }
1241 descriptor::ShInner::Wpkh(..) => *item.redeem_script() = Some(sh.inner_script()),
1242 descriptor::ShInner::SortedMulti(_) | descriptor::ShInner::Ms(_) => {
1243 *item.redeem_script() = Some(sh.inner_script())
1244 }
1245 },
1246 Descriptor::Wsh(wsh) => *item.witness_script() = Some(wsh.inner_script()),
1247 Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"),
1248 }
1249
1250 derived
1251 };
1252
1253 Ok((derived, true))
1254}
1255
1256fn script_code_wpkh(script: &Script) -> Script {
1258 assert!(script.is_v0_p2wpkh());
1259 let mut script_code = vec![0x76u8, 0xa9, 0x14];
1261 script_code.extend(&script.as_bytes()[2..]);
1262 script_code.push(0x88);
1263 script_code.push(0xac);
1264 Script::from(script_code)
1265}
1266
1267#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1269pub enum UtxoUpdateError {
1270 IndexOutOfBounds(usize, usize),
1272 MissingInputUtxo,
1274 DerivationError(descriptor::ConversionError),
1276 UtxoCheck,
1278 MismatchedScriptPubkey,
1281}
1282
1283impl fmt::Display for UtxoUpdateError {
1284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1285 match self {
1286 UtxoUpdateError::IndexOutOfBounds(ind, len) => {
1287 write!(f, "index {}, psbt input len: {}", ind, len)
1288 }
1289 UtxoUpdateError::MissingInputUtxo => {
1290 write!(f, "Missing input in unsigned transaction")
1291 }
1292 UtxoUpdateError::DerivationError(e) => write!(f, "Key derivation error {}", e),
1293 UtxoUpdateError::UtxoCheck => write!(
1294 f,
1295 "The input's witness_utxo and/or non_witness_utxo were invalid or missing"
1296 ),
1297 UtxoUpdateError::MismatchedScriptPubkey => {
1298 write!(f, "The input's witness_utxo and/or non_witness_utxo had a script pubkey that didn't match the descriptor")
1299 }
1300 }
1301 }
1302}
1303
1304#[cfg(feature = "std")]
1305impl error::Error for UtxoUpdateError {
1306 fn cause(&self) -> Option<&dyn error::Error> {
1307 use self::UtxoUpdateError::*;
1308
1309 match self {
1310 IndexOutOfBounds(_, _) | MissingInputUtxo | UtxoCheck | MismatchedScriptPubkey => None,
1311 DerivationError(e) => Some(e),
1312 }
1313 }
1314}
1315
1316#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1318pub enum OutputUpdateError {
1319 IndexOutOfBounds(usize, usize),
1321 MissingTxOut,
1323 DerivationError(descriptor::ConversionError),
1325 MismatchedScriptPubkey,
1327}
1328
1329impl fmt::Display for OutputUpdateError {
1330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1331 match self {
1332 OutputUpdateError::IndexOutOfBounds(ind, len) => {
1333 write!(f, "index {}, psbt output len: {}", ind, len)
1334 }
1335 OutputUpdateError::MissingTxOut => {
1336 write!(f, "Missing txout in the unsigned transaction")
1337 }
1338 OutputUpdateError::DerivationError(e) => write!(f, "Key derivation error {}", e),
1339 OutputUpdateError::MismatchedScriptPubkey => {
1340 write!(f, "The output's script pubkey didn't match the descriptor")
1341 }
1342 }
1343 }
1344}
1345
1346#[cfg(feature = "std")]
1347impl error::Error for OutputUpdateError {
1348 fn cause(&self) -> Option<&dyn error::Error> {
1349 use self::OutputUpdateError::*;
1350
1351 match self {
1352 IndexOutOfBounds(_, _) | MissingTxOut | MismatchedScriptPubkey => None,
1353 DerivationError(e) => Some(e),
1354 }
1355 }
1356}
1357
1358#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1360pub enum SighashError {
1361 IndexOutOfBounds(usize, usize),
1363 MissingInputUtxo,
1365 MissingSpendUtxos,
1367 InvalidSighashType,
1369 SighashComputationError(bitcoin::util::sighash::Error),
1373 MissingWitnessScript,
1375 MissingRedeemScript,
1377}
1378
1379impl fmt::Display for SighashError {
1380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1381 match self {
1382 SighashError::IndexOutOfBounds(ind, len) => {
1383 write!(f, "index {}, psbt input len: {}", ind, len)
1384 }
1385 SighashError::MissingInputUtxo => write!(f, "Missing input utxo in pbst"),
1386 SighashError::MissingSpendUtxos => write!(f, "Missing Psbt spend utxos"),
1387 SighashError::InvalidSighashType => write!(f, "Invalid Sighash type"),
1388 SighashError::SighashComputationError(e) => {
1389 write!(f, "Sighash computation error : {}", e)
1390 }
1391 SighashError::MissingWitnessScript => write!(f, "Missing Witness Script"),
1392 SighashError::MissingRedeemScript => write!(f, "Missing Redeem Script"),
1393 }
1394 }
1395}
1396
1397#[cfg(feature = "std")]
1398impl error::Error for SighashError {
1399 fn cause(&self) -> Option<&dyn error::Error> {
1400 use self::SighashError::*;
1401
1402 match self {
1403 IndexOutOfBounds(_, _)
1404 | MissingInputUtxo
1405 | MissingSpendUtxos
1406 | InvalidSighashType
1407 | MissingWitnessScript
1408 | MissingRedeemScript => None,
1409 SighashComputationError(e) => Some(e),
1410 }
1411 }
1412}
1413
1414impl From<bitcoin::util::sighash::Error> for SighashError {
1415 fn from(e: bitcoin::util::sighash::Error) -> Self {
1416 SighashError::SighashComputationError(e)
1417 }
1418}
1419
1420#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1422pub enum PsbtSighashMsg {
1423 TapSighash(taproot::TapSighashHash),
1425 EcdsaSighash(bitcoin::Sighash),
1427}
1428
1429impl PsbtSighashMsg {
1430 pub fn to_secp_msg(&self) -> secp256k1::Message {
1432 match *self {
1433 PsbtSighashMsg::TapSighash(msg) => {
1434 secp256k1::Message::from_slice(msg.as_ref()).expect("Sighashes are 32 bytes")
1435 }
1436 PsbtSighashMsg::EcdsaSighash(msg) => {
1437 secp256k1::Message::from_slice(msg.as_ref()).expect("Sighashes are 32 bytes")
1438 }
1439 }
1440 }
1441}
1442
1443#[cfg(test)]
1444mod tests {
1445 use std::str::FromStr;
1446
1447 use bitcoin::consensus::encode::deserialize;
1448 use bitcoin::hashes::hex::FromHex;
1449 use bitcoin::secp256k1::PublicKey;
1450 use bitcoin::util::bip32::{DerivationPath, ExtendedPubKey};
1451 use bitcoin::{OutPoint, PackedLockTime, TxIn, TxOut, XOnlyPublicKey};
1452
1453 use super::*;
1454 use crate::Miniscript;
1455
1456 #[test]
1457 fn test_extract_bip174() {
1458 let psbt: bitcoin::util::psbt::PartiallySignedTransaction = deserialize(&Vec::<u8>::from_hex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap();
1459 let secp = Secp256k1::verification_only();
1460 let tx = psbt.extract(&secp).unwrap();
1461 let expected: bitcoin::Transaction = deserialize(&Vec::<u8>::from_hex("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000").unwrap()).unwrap();
1462 assert_eq!(tx, expected);
1463 }
1464
1465 #[test]
1466 fn test_update_item_tr_no_script() {
1467 let root_xpub = ExtendedPubKey::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1469 let fingerprint = root_xpub.fingerprint();
1470 let desc = format!("tr([{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)", fingerprint);
1471 let desc = Descriptor::from_str(&desc).unwrap();
1472 let mut psbt_input = psbt::Input::default();
1473 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1474 let mut psbt_output = psbt::Output::default();
1475 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1476 let internal_key = XOnlyPublicKey::from_str(
1477 "cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115",
1478 )
1479 .unwrap();
1480 assert_eq!(psbt_input.tap_internal_key, Some(internal_key));
1481 assert_eq!(
1482 psbt_input.tap_key_origins.get(&internal_key),
1483 Some(&(
1484 vec![],
1485 (
1486 fingerprint,
1487 DerivationPath::from_str("m/86'/0'/0'/0/0").unwrap()
1488 )
1489 ))
1490 );
1491 assert_eq!(psbt_input.tap_key_origins.len(), 1);
1492 assert_eq!(psbt_input.tap_scripts.len(), 0);
1493 assert_eq!(psbt_input.tap_merkle_root, None);
1494
1495 assert_eq!(psbt_output.tap_internal_key, psbt_input.tap_internal_key);
1496 assert_eq!(psbt_output.tap_key_origins, psbt_input.tap_key_origins);
1497 assert_eq!(psbt_output.tap_tree, None);
1498 }
1499
1500 #[test]
1501 fn test_update_item_tr_with_tapscript() {
1502 use crate::Tap;
1503 let root_xpub = ExtendedPubKey::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1505 let fingerprint = root_xpub.fingerprint();
1506 let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1507 let desc = format!(
1508 "tr({}/0/0,{{pkh({}/0/1),multi_a(2,{}/0/1,{}/1/0)}})",
1509 xpub, xpub, xpub, xpub
1510 );
1511
1512 let desc = Descriptor::from_str(&desc).unwrap();
1513 let internal_key = XOnlyPublicKey::from_str(
1514 "cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115",
1515 )
1516 .unwrap();
1517 let mut psbt_input = psbt::Input::default();
1518 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1519 let mut psbt_output = psbt::Output::default();
1520 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1521 assert_eq!(psbt_input.tap_internal_key, Some(internal_key));
1522 assert_eq!(
1523 psbt_input.tap_key_origins.get(&internal_key),
1524 Some(&(
1525 vec![],
1526 (
1527 fingerprint,
1528 DerivationPath::from_str("m/86'/0'/0'/0/0").unwrap()
1529 )
1530 ))
1531 );
1532 assert_eq!(psbt_input.tap_key_origins.len(), 3);
1533 assert_eq!(psbt_input.tap_scripts.len(), 2);
1534 assert!(psbt_input.tap_merkle_root.is_some());
1535
1536 assert_eq!(psbt_output.tap_internal_key, psbt_input.tap_internal_key);
1537 assert_eq!(psbt_output.tap_key_origins, psbt_input.tap_key_origins);
1538 assert!(psbt_output.tap_tree.is_some());
1539
1540 let key_0_1 = XOnlyPublicKey::from_str(
1541 "83dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145",
1542 )
1543 .unwrap();
1544 let first_leaf_hash = {
1545 let ms =
1546 Miniscript::<XOnlyPublicKey, Tap>::from_str(&format!("pkh({})", &key_0_1)).unwrap();
1547 let first_script = ms.encode();
1548 assert!(psbt_input
1549 .tap_scripts
1550 .values()
1551 .find(|value| *value == &(first_script.clone(), LeafVersion::TapScript))
1552 .is_some());
1553 TapLeafHash::from_script(&first_script, LeafVersion::TapScript)
1554 };
1555
1556 {
1557 let (leaf_hashes, (key_fingerprint, deriv_path)) =
1559 psbt_input.tap_key_origins.get(&key_0_1).unwrap();
1560 assert_eq!(key_fingerprint, &fingerprint);
1561 assert_eq!(&deriv_path.to_string(), "m/86'/0'/0'/0/1");
1562 assert_eq!(leaf_hashes.len(), 2);
1563 assert!(leaf_hashes.contains(&first_leaf_hash));
1564 }
1565
1566 {
1567 let key_1_0 = XOnlyPublicKey::from_str(
1569 "399f1b2f4393f29a18c937859c5dd8a77350103157eb880f02e8c08214277cef",
1570 )
1571 .unwrap();
1572 let (leaf_hashes, (key_fingerprint, deriv_path)) =
1573 psbt_input.tap_key_origins.get(&key_1_0).unwrap();
1574 assert_eq!(key_fingerprint, &fingerprint);
1575 assert_eq!(&deriv_path.to_string(), "m/86'/0'/0'/1/0");
1576 assert_eq!(leaf_hashes.len(), 1);
1577 assert!(!leaf_hashes.contains(&first_leaf_hash));
1578 }
1579 }
1580
1581 #[test]
1582 fn test_update_item_non_tr_multi() {
1583 let root_xpub = ExtendedPubKey::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1585 let fingerprint = root_xpub.fingerprint();
1586 let xpub = format!("[{}/84'/0'/0']xpub6CatWdiZiodmUeTDp8LT5or8nmbKNcuyvz7WyksVFkKB4RHwCD3XyuvPEbvqAQY3rAPshWcMLoP2fMFMKHPJ4ZeZXYVUhLv1VMrjPC7PW6V", fingerprint);
1587 let pubkeys = [
1588 "0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c",
1589 "03e775fd51f0dfb8cd865d9ff1cca2a158cf651fe997fdc9fee9c1d3b5e995ea77",
1590 "03025324888e429ab8e3dbaf1f7802648b9cd01e9b418485c5fa4c1b9b5700e1a6",
1591 ];
1592
1593 let expected_bip32 = pubkeys
1594 .iter()
1595 .zip(["0/0", "0/1", "1/0"].iter())
1596 .map(|(pubkey, path)| {
1597 (
1598 PublicKey::from_str(pubkey).unwrap(),
1599 (
1600 fingerprint,
1601 DerivationPath::from_str(&format!("m/84'/0'/0'/{}", path)).unwrap(),
1602 ),
1603 )
1604 })
1605 .collect::<BTreeMap<_, _>>();
1606
1607 {
1608 let desc = format!("wsh(multi(2,{}/0/0,{}/0/1,{}/1/0))", xpub, xpub, xpub);
1610 let desc = Descriptor::from_str(&desc).unwrap();
1611 let derived = format!("wsh(multi(2,{}))", pubkeys.join(","));
1612 let derived = Descriptor::<bitcoin::PublicKey>::from_str(&derived).unwrap();
1613
1614 let mut psbt_input = psbt::Input::default();
1615 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1616
1617 let mut psbt_output = psbt::Output::default();
1618 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1619
1620 assert_eq!(expected_bip32, psbt_input.bip32_derivation);
1621 assert_eq!(
1622 psbt_input.witness_script,
1623 Some(derived.explicit_script().unwrap())
1624 );
1625
1626 assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation);
1627 assert_eq!(psbt_output.witness_script, psbt_input.witness_script);
1628 }
1629
1630 {
1631 let desc = format!("sh(multi(2,{}/0/0,{}/0/1,{}/1/0))", xpub, xpub, xpub);
1633 let desc = Descriptor::from_str(&desc).unwrap();
1634 let derived = format!("sh(multi(2,{}))", pubkeys.join(","));
1635 let derived = Descriptor::<bitcoin::PublicKey>::from_str(&derived).unwrap();
1636
1637 let mut psbt_input = psbt::Input::default();
1638 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1639
1640 let mut psbt_output = psbt::Output::default();
1641 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1642
1643 assert_eq!(psbt_input.bip32_derivation, expected_bip32);
1644 assert_eq!(psbt_input.witness_script, None);
1645 assert_eq!(
1646 psbt_input.redeem_script,
1647 Some(derived.explicit_script().unwrap())
1648 );
1649
1650 assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation);
1651 assert_eq!(psbt_output.witness_script, psbt_input.witness_script);
1652 assert_eq!(psbt_output.redeem_script, psbt_input.redeem_script);
1653 }
1654 }
1655
1656 #[test]
1657 fn test_update_input_checks() {
1658 let desc = format!("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)");
1659 let desc = Descriptor::<DefiniteDescriptorKey>::from_str(&desc).unwrap();
1660
1661 let mut non_witness_utxo = bitcoin::Transaction {
1662 version: 1,
1663 lock_time: PackedLockTime::ZERO,
1664 input: vec![],
1665 output: vec![TxOut {
1666 value: 1_000,
1667 script_pubkey: Script::from_str(
1668 "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c",
1669 )
1670 .unwrap(),
1671 }],
1672 };
1673
1674 let tx = bitcoin::Transaction {
1675 version: 1,
1676 lock_time: PackedLockTime::ZERO,
1677 input: vec![TxIn {
1678 previous_output: OutPoint {
1679 txid: non_witness_utxo.txid(),
1680 vout: 0,
1681 },
1682 ..Default::default()
1683 }],
1684 output: vec![],
1685 };
1686
1687 let mut psbt = Psbt::from_unsigned_tx(tx.clone()).unwrap();
1688 assert_eq!(
1689 psbt.update_input_with_descriptor(0, &desc),
1690 Err(UtxoUpdateError::UtxoCheck),
1691 "neither *_utxo are not set"
1692 );
1693 psbt.inputs[0].witness_utxo = Some(non_witness_utxo.output[0].clone());
1694 assert_eq!(
1695 psbt.update_input_with_descriptor(0, &desc),
1696 Ok(()),
1697 "witness_utxo is set which is ok"
1698 );
1699 psbt.inputs[0].non_witness_utxo = Some(non_witness_utxo.clone());
1700 assert_eq!(
1701 psbt.update_input_with_descriptor(0, &desc),
1702 Ok(()),
1703 "matching non_witness_utxo"
1704 );
1705 non_witness_utxo.version = 0;
1706 psbt.inputs[0].non_witness_utxo = Some(non_witness_utxo.clone());
1707 assert_eq!(
1708 psbt.update_input_with_descriptor(0, &desc),
1709 Err(UtxoUpdateError::UtxoCheck),
1710 "non_witness_utxo no longer matches"
1711 );
1712 psbt.inputs[0].non_witness_utxo = None;
1713 psbt.inputs[0].witness_utxo.as_mut().unwrap().script_pubkey = Script::default();
1714 assert_eq!(
1715 psbt.update_input_with_descriptor(0, &desc),
1716 Err(UtxoUpdateError::MismatchedScriptPubkey),
1717 "non_witness_utxo no longer matches"
1718 );
1719 }
1720
1721 #[test]
1722 fn test_update_output_checks() {
1723 let desc = format!("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)");
1724 let desc = Descriptor::<DefiniteDescriptorKey>::from_str(&desc).unwrap();
1725
1726 let tx = bitcoin::Transaction {
1727 version: 1,
1728 lock_time: PackedLockTime::ZERO,
1729 input: vec![],
1730 output: vec![TxOut {
1731 value: 1_000,
1732 script_pubkey: Script::from_str(
1733 "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c",
1734 )
1735 .unwrap(),
1736 }],
1737 };
1738
1739 let mut psbt = Psbt::from_unsigned_tx(tx.clone()).unwrap();
1740 assert_eq!(
1741 psbt.update_output_with_descriptor(1, &desc),
1742 Err(OutputUpdateError::IndexOutOfBounds(1, 1)),
1743 "output index doesn't exist"
1744 );
1745 assert_eq!(
1746 psbt.update_output_with_descriptor(0, &desc),
1747 Ok(()),
1748 "script_pubkey should match"
1749 );
1750 psbt.unsigned_tx.output[0].script_pubkey = Script::default();
1751 assert_eq!(
1752 psbt.update_output_with_descriptor(0, &desc),
1753 Err(OutputUpdateError::MismatchedScriptPubkey),
1754 "output script_pubkey no longer matches"
1755 );
1756 }
1757}