1use core::convert::TryFrom;
11use core::fmt;
12#[cfg(feature = "std")]
13use std::error;
14
15use bitcoin::hashes::{hash160, sha256d, Hash};
16use bitcoin::psbt::{self, Psbt};
17#[cfg(not(test))] use bitcoin::secp256k1;
19use bitcoin::secp256k1::{Secp256k1, VerifyOnly};
20use bitcoin::sighash::{self, SighashCache};
21use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapLeafHash};
22use bitcoin::{absolute, bip32, relative, transaction, Script, ScriptBuf};
23
24use crate::miniscript::context::SigType;
25use crate::prelude::*;
26use crate::{
27 descriptor, interpreter, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey,
28 Preimage32, Satisfier, ToPublicKey, TranslatePk, Translator,
29};
30
31mod finalizer;
32
33#[allow(deprecated)]
34pub use self::finalizer::{finalize, finalize_mall, interpreter_check};
35
36#[derive(Debug)]
38pub enum Error {
39 InputError(InputError, usize),
41 WrongInputCount {
43 in_tx: usize,
45 in_map: usize,
47 },
48 InputIdxOutofBounds {
50 psbt_inp: usize,
52 index: usize,
54 },
55}
56
57impl fmt::Display for Error {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 match *self {
60 Error::InputError(ref inp_err, index) => write!(f, "{} at index {}", inp_err, index),
61 Error::WrongInputCount { in_tx, in_map } => {
62 write!(f, "PSBT had {} inputs in transaction but {} inputs in map", in_tx, in_map)
63 }
64 Error::InputIdxOutofBounds { psbt_inp, index } => write!(
65 f,
66 "psbt input index {} out of bounds: psbt.inputs.len() {}",
67 index, psbt_inp
68 ),
69 }
70 }
71}
72
73#[cfg(feature = "std")]
74impl error::Error for Error {
75 fn cause(&self) -> Option<&dyn error::Error> {
76 use self::Error::*;
77
78 match self {
79 InputError(e, _) => Some(e),
80 WrongInputCount { .. } | InputIdxOutofBounds { .. } => None,
81 }
82 }
83}
84
85#[derive(Debug)]
87pub enum InputError {
88 SecpErr(bitcoin::secp256k1::Error),
90 KeyErr(bitcoin::key::FromSliceError),
92 CouldNotSatisfyTr,
97 Interpreter(interpreter::Error),
99 InvalidRedeemScript {
101 redeem: ScriptBuf,
103 p2sh_expected: ScriptBuf,
105 },
106 InvalidWitnessScript {
108 witness_script: ScriptBuf,
110 p2wsh_expected: ScriptBuf,
112 },
113 InvalidSignature {
115 pubkey: bitcoin::PublicKey,
117 sig: Vec<u8>,
119 },
120 MiniscriptError(super::Error),
122 MissingRedeemScript,
124 MissingWitness,
126 MissingPubkey,
128 MissingWitnessScript,
130 MissingUtxo,
132 NonEmptyWitnessScript,
134 NonEmptyRedeemScript,
136 NonStandardSighashType(sighash::NonStandardSighashTypeError),
138 WrongSighashFlag {
140 required: sighash::EcdsaSighashType,
142 got: sighash::EcdsaSighashType,
144 pubkey: bitcoin::PublicKey,
146 },
147}
148
149#[cfg(feature = "std")]
150impl error::Error for InputError {
151 fn cause(&self) -> Option<&dyn error::Error> {
152 use self::InputError::*;
153
154 match self {
155 CouldNotSatisfyTr
156 | InvalidRedeemScript { .. }
157 | InvalidWitnessScript { .. }
158 | InvalidSignature { .. }
159 | MissingRedeemScript
160 | MissingWitness
161 | MissingPubkey
162 | MissingWitnessScript
163 | MissingUtxo
164 | NonEmptyWitnessScript
165 | NonEmptyRedeemScript
166 | NonStandardSighashType(_)
167 | WrongSighashFlag { .. } => None,
168 SecpErr(e) => Some(e),
169 KeyErr(e) => Some(e),
170 Interpreter(e) => Some(e),
171 MiniscriptError(e) => Some(e),
172 }
173 }
174}
175
176impl fmt::Display for InputError {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 match *self {
179 InputError::InvalidSignature { ref pubkey, ref sig } => {
180 write!(f, "PSBT: bad signature {} for key {:?}", pubkey, sig)
181 }
182 InputError::KeyErr(ref e) => write!(f, "Key Err: {}", e),
183 InputError::Interpreter(ref e) => write!(f, "Interpreter: {}", e),
184 InputError::SecpErr(ref e) => write!(f, "Secp Err: {}", e),
185 InputError::InvalidRedeemScript { ref redeem, ref p2sh_expected } => write!(
186 f,
187 "Redeem script {} does not match the p2sh script {}",
188 redeem, p2sh_expected
189 ),
190 InputError::InvalidWitnessScript { ref witness_script, ref p2wsh_expected } => write!(
191 f,
192 "Witness script {} does not match the p2wsh script {}",
193 witness_script, p2wsh_expected
194 ),
195 InputError::MiniscriptError(ref e) => write!(f, "Miniscript Error: {}", e),
196 InputError::MissingWitness => write!(f, "PSBT is missing witness"),
197 InputError::MissingRedeemScript => write!(f, "PSBT is Redeem script"),
198 InputError::MissingUtxo => {
199 write!(f, "PSBT is missing both witness and non-witness UTXO")
200 }
201 InputError::MissingWitnessScript => write!(f, "PSBT is missing witness script"),
202 InputError::MissingPubkey => write!(f, "Missing pubkey for a pkh/wpkh"),
203 InputError::NonEmptyRedeemScript => {
204 write!(f, "PSBT has non-empty redeem script at for legacy transactions")
205 }
206 InputError::NonEmptyWitnessScript => {
207 write!(f, "PSBT has non-empty witness script at for legacy input")
208 }
209 InputError::WrongSighashFlag { required, got, pubkey } => write!(
210 f,
211 "PSBT: signature with key {:?} had \
212 sighashflag {:?} rather than required {:?}",
213 pubkey, got, required
214 ),
215 InputError::CouldNotSatisfyTr => write!(f, "Could not satisfy Tr descriptor"),
216 InputError::NonStandardSighashType(ref e) => {
217 write!(f, "Non-standard sighash type {}", e)
218 }
219 }
220 }
221}
222
223#[doc(hidden)]
224impl From<super::Error> for InputError {
225 fn from(e: super::Error) -> InputError { InputError::MiniscriptError(e) }
226}
227
228#[doc(hidden)]
229impl From<bitcoin::secp256k1::Error> for InputError {
230 fn from(e: bitcoin::secp256k1::Error) -> InputError { InputError::SecpErr(e) }
231}
232
233#[doc(hidden)]
234impl From<bitcoin::key::FromSliceError> for InputError {
235 fn from(e: bitcoin::key::FromSliceError) -> InputError { InputError::KeyErr(e) }
236}
237
238pub struct PsbtInputSatisfier<'psbt> {
244 pub psbt: &'psbt Psbt,
246 pub index: usize,
248}
249
250impl<'psbt> PsbtInputSatisfier<'psbt> {
251 pub fn new(psbt: &'psbt Psbt, index: usize) -> Self { Self { psbt, index } }
254}
255
256impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for PsbtInputSatisfier<'psbt> {
257 fn lookup_tap_key_spend_sig(&self) -> Option<bitcoin::taproot::Signature> {
258 self.psbt.inputs[self.index].tap_key_sig
259 }
260
261 fn lookup_tap_leaf_script_sig(
262 &self,
263 pk: &Pk,
264 lh: &TapLeafHash,
265 ) -> Option<bitcoin::taproot::Signature> {
266 self.psbt.inputs[self.index]
267 .tap_script_sigs
268 .get(&(pk.to_x_only_pubkey(), *lh))
269 .copied()
270 }
271
272 fn lookup_raw_pkh_pk(&self, pkh: &hash160::Hash) -> Option<bitcoin::PublicKey> {
273 self.psbt.inputs[self.index]
274 .bip32_derivation
275 .iter()
276 .find(|&(pubkey, _)| pubkey.to_pubkeyhash(SigType::Ecdsa) == *pkh)
277 .map(|(pubkey, _)| bitcoin::PublicKey::new(*pubkey))
278 }
279
280 fn lookup_tap_control_block_map(
281 &self,
282 ) -> Option<&BTreeMap<ControlBlock, (bitcoin::ScriptBuf, LeafVersion)>> {
283 Some(&self.psbt.inputs[self.index].tap_scripts)
284 }
285
286 fn lookup_raw_pkh_tap_leaf_script_sig(
287 &self,
288 pkh: &(hash160::Hash, TapLeafHash),
289 ) -> Option<(bitcoin::secp256k1::XOnlyPublicKey, bitcoin::taproot::Signature)> {
290 self.psbt.inputs[self.index]
291 .tap_script_sigs
292 .iter()
293 .find(|&((pubkey, lh), _sig)| {
294 pubkey.to_pubkeyhash(SigType::Schnorr) == pkh.0 && *lh == pkh.1
295 })
296 .map(|((x_only_pk, _leaf_hash), sig)| (*x_only_pk, *sig))
297 }
298
299 fn lookup_ecdsa_sig(&self, pk: &Pk) -> Option<bitcoin::ecdsa::Signature> {
300 self.psbt.inputs[self.index]
301 .partial_sigs
302 .get(&pk.to_public_key())
303 .copied()
304 }
305
306 fn lookup_raw_pkh_ecdsa_sig(
307 &self,
308 pkh: &hash160::Hash,
309 ) -> Option<(bitcoin::PublicKey, bitcoin::ecdsa::Signature)> {
310 self.psbt.inputs[self.index]
311 .partial_sigs
312 .iter()
313 .find(|&(pubkey, _sig)| pubkey.to_pubkeyhash(SigType::Ecdsa) == *pkh)
314 .map(|(pk, sig)| (*pk, *sig))
315 }
316
317 fn check_after(&self, n: absolute::LockTime) -> bool {
318 if !self.psbt.unsigned_tx.input[self.index].enables_lock_time() {
319 return false;
320 }
321
322 let lock_time = self.psbt.unsigned_tx.lock_time;
323
324 <dyn Satisfier<Pk>>::check_after(&lock_time, n)
325 }
326
327 fn check_older(&self, n: relative::LockTime) -> bool {
328 let seq = self.psbt.unsigned_tx.input[self.index].sequence;
329
330 if self.psbt.unsigned_tx.version < transaction::Version::TWO || !seq.is_relative_lock_time()
331 {
332 return false;
333 }
334
335 <dyn Satisfier<Pk>>::check_older(&seq, n)
336 }
337
338 fn lookup_hash160(&self, h: &Pk::Hash160) -> Option<Preimage32> {
339 self.psbt.inputs[self.index]
340 .hash160_preimages
341 .get(&Pk::to_hash160(h))
342 .and_then(|x: &Vec<u8>| try_vec_as_preimage32(x))
343 }
344
345 fn lookup_sha256(&self, h: &Pk::Sha256) -> Option<Preimage32> {
346 self.psbt.inputs[self.index]
347 .sha256_preimages
348 .get(&Pk::to_sha256(h))
349 .and_then(|x: &Vec<u8>| try_vec_as_preimage32(x))
350 }
351
352 fn lookup_hash256(&self, h: &Pk::Hash256) -> Option<Preimage32> {
353 self.psbt.inputs[self.index]
354 .hash256_preimages
355 .get(&sha256d::Hash::from_byte_array(Pk::to_hash256(h).to_byte_array())) .and_then(|x: &Vec<u8>| try_vec_as_preimage32(x))
357 }
358
359 fn lookup_ripemd160(&self, h: &Pk::Ripemd160) -> Option<Preimage32> {
360 self.psbt.inputs[self.index]
361 .ripemd160_preimages
362 .get(&Pk::to_ripemd160(h))
363 .and_then(|x: &Vec<u8>| try_vec_as_preimage32(x))
364 }
365}
366
367fn try_vec_as_preimage32(vec: &[u8]) -> Option<Preimage32> {
368 if vec.len() == 32 {
369 let mut arr = [0u8; 32];
370 arr.copy_from_slice(vec);
371 Some(arr)
372 } else {
373 None
374 }
375}
376
377fn sanity_check(psbt: &Psbt) -> Result<(), Error> {
381 if psbt.unsigned_tx.input.len() != psbt.inputs.len() {
382 return Err(Error::WrongInputCount {
383 in_tx: psbt.unsigned_tx.input.len(),
384 in_map: psbt.inputs.len(),
385 });
386 }
387
388 for (index, input) in psbt.inputs.iter().enumerate() {
390 let target_ecdsa_sighash_ty = match input.sighash_type {
392 Some(psbt_hash_ty) => psbt_hash_ty
393 .ecdsa_hash_ty()
394 .map_err(|e| Error::InputError(InputError::NonStandardSighashType(e), index))?,
395 None => sighash::EcdsaSighashType::All,
396 };
397 for (key, ecdsa_sig) in &input.partial_sigs {
398 let flag = sighash::EcdsaSighashType::from_standard(ecdsa_sig.sighash_type as u32)
399 .map_err(|_| {
400 Error::InputError(
401 InputError::Interpreter(interpreter::Error::NonStandardSighash(
402 ecdsa_sig.to_vec(),
403 )),
404 index,
405 )
406 })?;
407 if target_ecdsa_sighash_ty != flag {
408 return Err(Error::InputError(
409 InputError::WrongSighashFlag {
410 required: target_ecdsa_sighash_ty,
411 got: flag,
412 pubkey: *key,
413 },
414 index,
415 ));
416 }
417 }
419 }
420
421 Ok(())
422}
423
424pub trait PsbtExt {
428 fn finalize_mut<C: secp256k1::Verification>(
445 &mut self,
446 secp: &secp256k1::Secp256k1<C>,
447 ) -> Result<(), Vec<Error>>;
448
449 fn finalize<C: secp256k1::Verification>(
457 self,
458 secp: &secp256k1::Secp256k1<C>,
459 ) -> Result<Psbt, (Psbt, Vec<Error>)>;
460
461 fn finalize_mall_mut<C: secp256k1::Verification>(
463 &mut self,
464 secp: &Secp256k1<C>,
465 ) -> Result<(), Vec<Error>>;
466
467 fn finalize_mall<C: secp256k1::Verification>(
469 self,
470 secp: &Secp256k1<C>,
471 ) -> Result<Psbt, (Psbt, Vec<Error>)>;
472
473 fn finalize_inp_mut<C: secp256k1::Verification>(
481 &mut self,
482 secp: &secp256k1::Secp256k1<C>,
483 index: usize,
484 ) -> Result<(), Error>;
485
486 fn finalize_inp<C: secp256k1::Verification>(
493 self,
494 secp: &secp256k1::Secp256k1<C>,
495 index: usize,
496 ) -> Result<Psbt, (Psbt, Error)>;
497
498 fn finalize_inp_mall_mut<C: secp256k1::Verification>(
500 &mut self,
501 secp: &secp256k1::Secp256k1<C>,
502 index: usize,
503 ) -> Result<(), Error>;
504
505 fn finalize_inp_mall<C: secp256k1::Verification>(
507 self,
508 secp: &secp256k1::Secp256k1<C>,
509 index: usize,
510 ) -> Result<Psbt, (Psbt, Error)>;
511
512 fn extract<C: secp256k1::Verification>(
518 &self,
519 secp: &Secp256k1<C>,
520 ) -> Result<bitcoin::Transaction, Error>;
521
522 fn update_input_with_descriptor(
541 &mut self,
542 input_index: usize,
543 descriptor: &Descriptor<DefiniteDescriptorKey>,
544 ) -> Result<(), UtxoUpdateError>;
545
546 fn update_output_with_descriptor(
556 &mut self,
557 output_index: usize,
558 descriptor: &Descriptor<DefiniteDescriptorKey>,
559 ) -> Result<(), OutputUpdateError>;
560
561 fn sighash_msg<T: Borrow<bitcoin::Transaction>>(
583 &self,
584 idx: usize,
585 cache: &mut SighashCache<T>,
586 tapleaf_hash: Option<TapLeafHash>,
587 ) -> Result<PsbtSighashMsg, SighashError>;
588}
589
590impl PsbtExt for Psbt {
591 fn finalize_mut<C: secp256k1::Verification>(
592 &mut self,
593 secp: &secp256k1::Secp256k1<C>,
594 ) -> Result<(), Vec<Error>> {
595 let mut errors = vec![];
597 for index in 0..self.inputs.len() {
598 match finalizer::finalize_input(self, index, secp, false) {
599 Ok(..) => {}
600 Err(e) => {
601 errors.push(e);
602 }
603 }
604 }
605 if errors.is_empty() {
606 Ok(())
607 } else {
608 Err(errors)
609 }
610 }
611
612 fn finalize<C: secp256k1::Verification>(
613 mut self,
614 secp: &secp256k1::Secp256k1<C>,
615 ) -> Result<Psbt, (Psbt, Vec<Error>)> {
616 match self.finalize_mut(secp) {
617 Ok(..) => Ok(self),
618 Err(e) => Err((self, e)),
619 }
620 }
621
622 fn finalize_mall_mut<C: secp256k1::Verification>(
623 &mut self,
624 secp: &secp256k1::Secp256k1<C>,
625 ) -> Result<(), Vec<Error>> {
626 let mut errors = vec![];
627 for index in 0..self.inputs.len() {
628 match finalizer::finalize_input(self, index, secp, true) {
629 Ok(..) => {}
630 Err(e) => {
631 errors.push(e);
632 }
633 }
634 }
635 if errors.is_empty() {
636 Ok(())
637 } else {
638 Err(errors)
639 }
640 }
641
642 fn finalize_mall<C: secp256k1::Verification>(
643 mut self,
644 secp: &Secp256k1<C>,
645 ) -> Result<Psbt, (Psbt, Vec<Error>)> {
646 match self.finalize_mall_mut(secp) {
647 Ok(..) => Ok(self),
648 Err(e) => Err((self, e)),
649 }
650 }
651
652 fn finalize_inp_mut<C: secp256k1::Verification>(
653 &mut self,
654 secp: &secp256k1::Secp256k1<C>,
655 index: usize,
656 ) -> Result<(), Error> {
657 if index >= self.inputs.len() {
658 return Err(Error::InputIdxOutofBounds { psbt_inp: self.inputs.len(), index });
659 }
660 finalizer::finalize_input(self, index, secp, false)
661 }
662
663 fn finalize_inp<C: secp256k1::Verification>(
664 mut self,
665 secp: &secp256k1::Secp256k1<C>,
666 index: usize,
667 ) -> Result<Psbt, (Psbt, Error)> {
668 match self.finalize_inp_mut(secp, index) {
669 Ok(..) => Ok(self),
670 Err(e) => Err((self, e)),
671 }
672 }
673
674 fn finalize_inp_mall_mut<C: secp256k1::Verification>(
675 &mut self,
676 secp: &secp256k1::Secp256k1<C>,
677 index: usize,
678 ) -> Result<(), Error> {
679 if index >= self.inputs.len() {
680 return Err(Error::InputIdxOutofBounds { psbt_inp: self.inputs.len(), index });
681 }
682 finalizer::finalize_input(self, index, secp, false)
683 }
684
685 fn finalize_inp_mall<C: secp256k1::Verification>(
686 mut self,
687 secp: &secp256k1::Secp256k1<C>,
688 index: usize,
689 ) -> Result<Psbt, (Psbt, Error)> {
690 match self.finalize_inp_mall_mut(secp, index) {
691 Ok(..) => Ok(self),
692 Err(e) => Err((self, e)),
693 }
694 }
695
696 fn extract<C: secp256k1::Verification>(
697 &self,
698 secp: &Secp256k1<C>,
699 ) -> Result<bitcoin::Transaction, Error> {
700 sanity_check(self)?;
701
702 let mut ret = self.unsigned_tx.clone();
703 for (n, input) in self.inputs.iter().enumerate() {
704 if input.final_script_sig.is_none() && input.final_script_witness.is_none() {
705 return Err(Error::InputError(InputError::MissingWitness, n));
706 }
707
708 if let Some(witness) = input.final_script_witness.as_ref() {
709 ret.input[n].witness = witness.clone();
710 }
711 if let Some(script_sig) = input.final_script_sig.as_ref() {
712 ret.input[n].script_sig = script_sig.clone();
713 }
714 }
715 interpreter_check(self, secp)?;
716 Ok(ret)
717 }
718
719 fn update_input_with_descriptor(
720 &mut self,
721 input_index: usize,
722 desc: &Descriptor<DefiniteDescriptorKey>,
723 ) -> Result<(), UtxoUpdateError> {
724 let n_inputs = self.inputs.len();
725 let input = self
726 .inputs
727 .get_mut(input_index)
728 .ok_or(UtxoUpdateError::IndexOutOfBounds(input_index, n_inputs))?;
729 let txin = self
730 .unsigned_tx
731 .input
732 .get(input_index)
733 .ok_or(UtxoUpdateError::MissingInputUtxo)?;
734
735 let desc_type = desc.desc_type();
736
737 if let Some(non_witness_utxo) = &input.non_witness_utxo {
738 if txin.previous_output.txid != non_witness_utxo.compute_txid() {
739 return Err(UtxoUpdateError::UtxoCheck);
740 }
741 }
742
743 let expected_spk = {
744 match (&input.witness_utxo, &input.non_witness_utxo) {
745 (Some(witness_utxo), None) => {
746 if desc_type.segwit_version().is_some() {
747 witness_utxo.script_pubkey.clone()
748 } else {
749 return Err(UtxoUpdateError::UtxoCheck);
750 }
751 }
752 (None, Some(non_witness_utxo)) => non_witness_utxo
753 .output
754 .get(txin.previous_output.vout as usize)
755 .ok_or(UtxoUpdateError::UtxoCheck)?
756 .script_pubkey
757 .clone(),
758 (Some(witness_utxo), Some(non_witness_utxo)) => {
759 if witness_utxo
760 != non_witness_utxo
761 .output
762 .get(txin.previous_output.vout as usize)
763 .ok_or(UtxoUpdateError::UtxoCheck)?
764 {
765 return Err(UtxoUpdateError::UtxoCheck);
766 }
767
768 witness_utxo.script_pubkey.clone()
769 }
770 (None, None) => return Err(UtxoUpdateError::UtxoCheck),
771 }
772 };
773
774 let (_, spk_check_passed) =
775 update_item_with_descriptor_helper(input, desc, Some(&expected_spk))
776 .map_err(UtxoUpdateError::DerivationError)?;
777
778 if !spk_check_passed {
779 return Err(UtxoUpdateError::MismatchedScriptPubkey);
780 }
781
782 Ok(())
783 }
784
785 fn update_output_with_descriptor(
786 &mut self,
787 output_index: usize,
788 desc: &Descriptor<DefiniteDescriptorKey>,
789 ) -> Result<(), OutputUpdateError> {
790 let n_outputs = self.outputs.len();
791 let output = self
792 .outputs
793 .get_mut(output_index)
794 .ok_or(OutputUpdateError::IndexOutOfBounds(output_index, n_outputs))?;
795 let txout = self
796 .unsigned_tx
797 .output
798 .get(output_index)
799 .ok_or(OutputUpdateError::MissingTxOut)?;
800
801 let (_, spk_check_passed) =
802 update_item_with_descriptor_helper(output, desc, Some(&txout.script_pubkey))
803 .map_err(OutputUpdateError::DerivationError)?;
804
805 if !spk_check_passed {
806 return Err(OutputUpdateError::MismatchedScriptPubkey);
807 }
808
809 Ok(())
810 }
811
812 fn sighash_msg<T: Borrow<bitcoin::Transaction>>(
813 &self,
814 idx: usize,
815 cache: &mut SighashCache<T>,
816 tapleaf_hash: Option<TapLeafHash>,
817 ) -> Result<PsbtSighashMsg, SighashError> {
818 if idx >= self.inputs.len() {
820 return Err(SighashError::IndexOutOfBounds(idx, self.inputs.len()));
821 }
822 let inp = &self.inputs[idx];
823 let prevouts = finalizer::prevouts(self).map_err(|_e| SighashError::MissingSpendUtxos)?;
824 let prevouts = bitcoin::sighash::Prevouts::All(&prevouts);
827 let inp_spk =
828 finalizer::get_scriptpubkey(self, idx).map_err(|_e| SighashError::MissingInputUtxo)?;
829 if inp_spk.is_p2tr() {
830 let hash_ty = inp
831 .sighash_type
832 .map(|sighash_type| sighash_type.taproot_hash_ty())
833 .unwrap_or(Ok(sighash::TapSighashType::Default))
834 .map_err(|_e| SighashError::InvalidSighashType)?;
835 match tapleaf_hash {
836 Some(leaf_hash) => {
837 let tap_sighash_msg = cache
838 .taproot_script_spend_signature_hash(idx, &prevouts, leaf_hash, hash_ty)?;
839 Ok(PsbtSighashMsg::TapSighash(tap_sighash_msg))
840 }
841 None => {
842 let tap_sighash_msg =
843 cache.taproot_key_spend_signature_hash(idx, &prevouts, hash_ty)?;
844 Ok(PsbtSighashMsg::TapSighash(tap_sighash_msg))
845 }
846 }
847 } else {
848 let hash_ty = inp
849 .sighash_type
850 .map(|sighash_type| sighash_type.ecdsa_hash_ty())
851 .unwrap_or(Ok(sighash::EcdsaSighashType::All))
852 .map_err(|_e| SighashError::InvalidSighashType)?;
853 let amt = finalizer::get_utxo(self, idx)
854 .map_err(|_e| SighashError::MissingInputUtxo)?
855 .value;
856 let is_nested_wpkh = inp_spk.is_p2sh()
857 && inp
858 .redeem_script
859 .as_ref()
860 .map(|x| x.is_p2wpkh())
861 .unwrap_or(false);
862 let is_nested_wsh = inp_spk.is_p2sh()
863 && inp
864 .redeem_script
865 .as_ref()
866 .map(|x| x.is_p2wsh())
867 .unwrap_or(false);
868 if inp_spk.is_p2wpkh() || inp_spk.is_p2wsh() || is_nested_wpkh || is_nested_wsh {
869 let msg = if inp_spk.is_p2wpkh() {
870 cache.p2wpkh_signature_hash(idx, &inp_spk, amt, hash_ty)?
871 } else if is_nested_wpkh {
872 let script_code = inp
873 .redeem_script
874 .as_ref()
875 .expect("redeem script non-empty checked earlier");
876 cache.p2wpkh_signature_hash(idx, script_code, amt, hash_ty)?
877 } else {
878 let witness_script = inp
879 .witness_script
880 .as_ref()
881 .ok_or(SighashError::MissingWitnessScript)?;
882 cache.p2wsh_signature_hash(idx, witness_script, amt, hash_ty)?
883 };
884 Ok(PsbtSighashMsg::SegwitV0Sighash(msg))
885 } else {
886 let script_code = if inp_spk.is_p2sh() {
888 inp.redeem_script
889 .as_ref()
890 .ok_or(SighashError::MissingRedeemScript)?
891 } else {
892 &inp_spk
893 };
894 let msg = cache.legacy_signature_hash(idx, script_code, hash_ty.to_u32())?;
895 Ok(PsbtSighashMsg::LegacySighash(msg))
896 }
897 }
898 }
899}
900
901pub trait PsbtInputExt {
903 fn update_with_descriptor_unchecked(
920 &mut self,
921 descriptor: &Descriptor<DefiniteDescriptorKey>,
922 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError>;
923}
924
925impl PsbtInputExt for psbt::Input {
926 fn update_with_descriptor_unchecked(
927 &mut self,
928 descriptor: &Descriptor<DefiniteDescriptorKey>,
929 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError> {
930 let (derived, _) = update_item_with_descriptor_helper(self, descriptor, None)?;
931 Ok(derived)
932 }
933}
934
935pub trait PsbtOutputExt {
937 fn update_with_descriptor_unchecked(
954 &mut self,
955 descriptor: &Descriptor<DefiniteDescriptorKey>,
956 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError>;
957}
958
959impl PsbtOutputExt for psbt::Output {
960 fn update_with_descriptor_unchecked(
961 &mut self,
962 descriptor: &Descriptor<DefiniteDescriptorKey>,
963 ) -> Result<Descriptor<bitcoin::PublicKey>, descriptor::ConversionError> {
964 let (derived, _) = update_item_with_descriptor_helper(self, descriptor, None)?;
965 Ok(derived)
966 }
967}
968
969struct KeySourceLookUp(
972 pub BTreeMap<secp256k1::PublicKey, bip32::KeySource>,
973 pub secp256k1::Secp256k1<VerifyOnly>,
974);
975
976impl Translator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
977 for KeySourceLookUp
978{
979 fn pk(
980 &mut self,
981 xpk: &DefiniteDescriptorKey,
982 ) -> Result<bitcoin::PublicKey, descriptor::ConversionError> {
983 let derived = xpk.derive_public_key(&self.1)?;
984 self.0.insert(
985 derived.to_public_key().inner,
986 (
987 xpk.master_fingerprint(),
988 xpk.full_derivation_path()
989 .ok_or(descriptor::ConversionError::MultiKey)?,
990 ),
991 );
992 Ok(derived)
993 }
994
995 translate_hash_clone!(DescriptorPublicKey, bitcoin::PublicKey, descriptor::ConversionError);
996}
997
998trait PsbtFields {
1000 fn redeem_script(&mut self) -> &mut Option<ScriptBuf>;
1002 fn witness_script(&mut self) -> &mut Option<ScriptBuf>;
1003 fn bip32_derivation(&mut self) -> &mut BTreeMap<secp256k1::PublicKey, bip32::KeySource>;
1004 fn tap_internal_key(&mut self) -> &mut Option<bitcoin::key::XOnlyPublicKey>;
1005 fn tap_key_origins(
1006 &mut self,
1007 ) -> &mut BTreeMap<bitcoin::key::XOnlyPublicKey, (Vec<TapLeafHash>, bip32::KeySource)>;
1008 #[allow(dead_code)]
1009 fn proprietary(&mut self) -> &mut BTreeMap<psbt::raw::ProprietaryKey, Vec<u8>>;
1010 #[allow(dead_code)]
1011 fn unknown(&mut self) -> &mut BTreeMap<psbt::raw::Key, Vec<u8>>;
1012
1013 fn tap_tree(&mut self) -> Option<&mut Option<taproot::TapTree>> { None }
1015
1016 fn tap_scripts(&mut self) -> Option<&mut BTreeMap<ControlBlock, (ScriptBuf, LeafVersion)>> {
1018 None
1019 }
1020 fn tap_merkle_root(&mut self) -> Option<&mut Option<taproot::TapNodeHash>> { None }
1021}
1022
1023impl PsbtFields for psbt::Input {
1024 fn redeem_script(&mut self) -> &mut Option<ScriptBuf> { &mut self.redeem_script }
1025 fn witness_script(&mut self) -> &mut Option<ScriptBuf> { &mut self.witness_script }
1026 fn bip32_derivation(&mut self) -> &mut BTreeMap<secp256k1::PublicKey, bip32::KeySource> {
1027 &mut self.bip32_derivation
1028 }
1029 fn tap_internal_key(&mut self) -> &mut Option<bitcoin::key::XOnlyPublicKey> {
1030 &mut self.tap_internal_key
1031 }
1032 fn tap_key_origins(
1033 &mut self,
1034 ) -> &mut BTreeMap<bitcoin::key::XOnlyPublicKey, (Vec<TapLeafHash>, bip32::KeySource)> {
1035 &mut self.tap_key_origins
1036 }
1037 #[allow(dead_code)]
1038 fn proprietary(&mut self) -> &mut BTreeMap<psbt::raw::ProprietaryKey, Vec<u8>> {
1039 &mut self.proprietary
1040 }
1041 #[allow(dead_code)]
1042 fn unknown(&mut self) -> &mut BTreeMap<psbt::raw::Key, Vec<u8>> { &mut self.unknown }
1043
1044 fn tap_scripts(&mut self) -> Option<&mut BTreeMap<ControlBlock, (ScriptBuf, LeafVersion)>> {
1045 Some(&mut self.tap_scripts)
1046 }
1047 fn tap_merkle_root(&mut self) -> Option<&mut Option<taproot::TapNodeHash>> {
1048 Some(&mut self.tap_merkle_root)
1049 }
1050}
1051
1052impl PsbtFields for psbt::Output {
1053 fn redeem_script(&mut self) -> &mut Option<ScriptBuf> { &mut self.redeem_script }
1054 fn witness_script(&mut self) -> &mut Option<ScriptBuf> { &mut self.witness_script }
1055 fn bip32_derivation(&mut self) -> &mut BTreeMap<secp256k1::PublicKey, bip32::KeySource> {
1056 &mut self.bip32_derivation
1057 }
1058 fn tap_internal_key(&mut self) -> &mut Option<bitcoin::key::XOnlyPublicKey> {
1059 &mut self.tap_internal_key
1060 }
1061 fn tap_key_origins(
1062 &mut self,
1063 ) -> &mut BTreeMap<bitcoin::key::XOnlyPublicKey, (Vec<TapLeafHash>, bip32::KeySource)> {
1064 &mut self.tap_key_origins
1065 }
1066 #[allow(dead_code)]
1067 fn proprietary(&mut self) -> &mut BTreeMap<psbt::raw::ProprietaryKey, Vec<u8>> {
1068 &mut self.proprietary
1069 }
1070 #[allow(dead_code)]
1071 fn unknown(&mut self) -> &mut BTreeMap<psbt::raw::Key, Vec<u8>> { &mut self.unknown }
1072
1073 fn tap_tree(&mut self) -> Option<&mut Option<taproot::TapTree>> { Some(&mut self.tap_tree) }
1074}
1075
1076fn update_item_with_descriptor_helper<F: PsbtFields>(
1077 item: &mut F,
1078 descriptor: &Descriptor<DefiniteDescriptorKey>,
1079 check_script: Option<&Script>,
1080 ) -> Result<(Descriptor<bitcoin::PublicKey>, bool), descriptor::ConversionError> {
1084 let secp = secp256k1::Secp256k1::verification_only();
1085
1086 let derived = if let Descriptor::Tr(_) = &descriptor {
1087 let derived = descriptor.derived_descriptor(&secp)?;
1088
1089 if let Some(check_script) = check_script {
1090 if check_script != &derived.script_pubkey() {
1091 return Ok((derived, false));
1092 }
1093 }
1094
1095 if let (Descriptor::Tr(tr_derived), Descriptor::Tr(tr_xpk)) = (&derived, descriptor) {
1097 let spend_info = tr_derived.spend_info();
1098 let ik_derived = spend_info.internal_key();
1099 let ik_xpk = tr_xpk.internal_key();
1100 if let Some(merkle_root) = item.tap_merkle_root() {
1101 *merkle_root = spend_info.merkle_root();
1102 }
1103 *item.tap_internal_key() = Some(ik_derived);
1104 item.tap_key_origins().insert(
1105 ik_derived,
1106 (
1107 vec![],
1108 (
1109 ik_xpk.master_fingerprint(),
1110 ik_xpk
1111 .full_derivation_path()
1112 .ok_or(descriptor::ConversionError::MultiKey)?,
1113 ),
1114 ),
1115 );
1116
1117 let mut builder = taproot::TaprootBuilder::new();
1118
1119 for ((_depth_der, ms_derived), (depth, ms)) in
1120 tr_derived.iter_scripts().zip(tr_xpk.iter_scripts())
1121 {
1122 debug_assert_eq!(_depth_der, depth);
1123 let leaf_script = (ms_derived.encode(), LeafVersion::TapScript);
1124 let tapleaf_hash = TapLeafHash::from_script(&leaf_script.0, leaf_script.1);
1125 builder = builder
1126 .add_leaf(depth, leaf_script.0.clone())
1127 .expect("Computing spend data on a valid tree should always succeed");
1128 if let Some(tap_scripts) = item.tap_scripts() {
1129 let control_block = spend_info
1130 .control_block(&leaf_script)
1131 .expect("Control block must exist in script map for every known leaf");
1132 tap_scripts.insert(control_block, leaf_script);
1133 }
1134
1135 for (pk_pkh_derived, pk_pkh_xpk) in ms_derived.iter_pk().zip(ms.iter_pk()) {
1136 let (xonly, xpk) = (pk_pkh_derived.to_x_only_pubkey(), pk_pkh_xpk);
1137
1138 let xpk_full_derivation_path = xpk
1139 .full_derivation_path()
1140 .ok_or(descriptor::ConversionError::MultiKey)?;
1141 item.tap_key_origins()
1142 .entry(xonly)
1143 .and_modify(|(tapleaf_hashes, _)| {
1144 if tapleaf_hashes.last() != Some(&tapleaf_hash) {
1145 tapleaf_hashes.push(tapleaf_hash);
1146 }
1147 })
1148 .or_insert_with(|| {
1149 (
1150 vec![tapleaf_hash],
1151 (xpk.master_fingerprint(), xpk_full_derivation_path),
1152 )
1153 });
1154 }
1155 }
1156
1157 for (tapleaf_hashes, _) in item.tap_key_origins().values_mut() {
1161 tapleaf_hashes.sort();
1162 tapleaf_hashes.dedup();
1163 }
1164
1165 match item.tap_tree() {
1166 Some(tap_tree) if tr_derived.tap_tree().is_some() => {
1169 *tap_tree = Some(
1170 taproot::TapTree::try_from(builder)
1171 .expect("The tree should always be valid"),
1172 );
1173 }
1174 _ => {}
1175 }
1176 }
1177
1178 derived
1179 } else {
1180 let mut bip32_derivation = KeySourceLookUp(BTreeMap::new(), Secp256k1::verification_only());
1181 let derived = descriptor
1182 .translate_pk(&mut bip32_derivation)
1183 .map_err(|e| e.expect_translator_err("No Outer Context errors in translations"))?;
1184
1185 if let Some(check_script) = check_script {
1186 if check_script != &derived.script_pubkey() {
1187 return Ok((derived, false));
1188 }
1189 }
1190
1191 item.bip32_derivation().append(&mut bip32_derivation.0);
1192
1193 match &derived {
1194 Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {}
1195 Descriptor::Sh(sh) => match sh.as_inner() {
1196 descriptor::ShInner::Wsh(wsh) => {
1197 *item.witness_script() = Some(wsh.inner_script());
1198 *item.redeem_script() = Some(wsh.inner_script().to_p2wsh());
1199 }
1200 descriptor::ShInner::Wpkh(..) => *item.redeem_script() = Some(sh.inner_script()),
1201 descriptor::ShInner::SortedMulti(_) | descriptor::ShInner::Ms(_) => {
1202 *item.redeem_script() = Some(sh.inner_script())
1203 }
1204 },
1205 Descriptor::Wsh(wsh) => *item.witness_script() = Some(wsh.inner_script()),
1206 Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"),
1207 }
1208
1209 derived
1210 };
1211
1212 Ok((derived, true))
1213}
1214
1215#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1217pub enum UtxoUpdateError {
1218 IndexOutOfBounds(usize, usize),
1220 MissingInputUtxo,
1222 DerivationError(descriptor::ConversionError),
1224 UtxoCheck,
1226 MismatchedScriptPubkey,
1229}
1230
1231impl fmt::Display for UtxoUpdateError {
1232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1233 match self {
1234 UtxoUpdateError::IndexOutOfBounds(ind, len) => {
1235 write!(f, "index {}, psbt input len: {}", ind, len)
1236 }
1237 UtxoUpdateError::MissingInputUtxo => {
1238 write!(f, "Missing input in unsigned transaction")
1239 }
1240 UtxoUpdateError::DerivationError(e) => write!(f, "Key derivation error {}", e),
1241 UtxoUpdateError::UtxoCheck => write!(
1242 f,
1243 "The input's witness_utxo and/or non_witness_utxo were invalid or missing"
1244 ),
1245 UtxoUpdateError::MismatchedScriptPubkey => {
1246 write!(f, "The input's witness_utxo and/or non_witness_utxo had a script pubkey that didn't match the descriptor")
1247 }
1248 }
1249 }
1250}
1251
1252#[cfg(feature = "std")]
1253impl error::Error for UtxoUpdateError {
1254 fn cause(&self) -> Option<&dyn error::Error> {
1255 use self::UtxoUpdateError::*;
1256
1257 match self {
1258 IndexOutOfBounds(_, _) | MissingInputUtxo | UtxoCheck | MismatchedScriptPubkey => None,
1259 DerivationError(e) => Some(e),
1260 }
1261 }
1262}
1263
1264#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1266pub enum OutputUpdateError {
1267 IndexOutOfBounds(usize, usize),
1269 MissingTxOut,
1271 DerivationError(descriptor::ConversionError),
1273 MismatchedScriptPubkey,
1275}
1276
1277impl fmt::Display for OutputUpdateError {
1278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1279 match self {
1280 OutputUpdateError::IndexOutOfBounds(ind, len) => {
1281 write!(f, "index {}, psbt output len: {}", ind, len)
1282 }
1283 OutputUpdateError::MissingTxOut => {
1284 write!(f, "Missing txout in the unsigned transaction")
1285 }
1286 OutputUpdateError::DerivationError(e) => write!(f, "Key derivation error {}", e),
1287 OutputUpdateError::MismatchedScriptPubkey => {
1288 write!(f, "The output's script pubkey didn't match the descriptor")
1289 }
1290 }
1291 }
1292}
1293
1294#[cfg(feature = "std")]
1295impl error::Error for OutputUpdateError {
1296 fn cause(&self) -> Option<&dyn error::Error> {
1297 use self::OutputUpdateError::*;
1298
1299 match self {
1300 IndexOutOfBounds(_, _) | MissingTxOut | MismatchedScriptPubkey => None,
1301 DerivationError(e) => Some(e),
1302 }
1303 }
1304}
1305
1306#[derive(Debug, Clone, PartialEq, Eq)]
1308pub enum SighashError {
1309 IndexOutOfBounds(usize, usize),
1311 MissingInputUtxo,
1313 MissingSpendUtxos,
1315 InvalidSighashType,
1317 SighashTaproot(sighash::TaprootError),
1319 SighashP2wpkh(sighash::P2wpkhError),
1321 TransactionInputsIndex(transaction::InputsIndexError),
1323 MissingWitnessScript,
1325 MissingRedeemScript,
1327}
1328
1329impl fmt::Display for SighashError {
1330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1331 match self {
1332 SighashError::IndexOutOfBounds(ind, len) => {
1333 write!(f, "index {}, psbt input len: {}", ind, len)
1334 }
1335 SighashError::MissingInputUtxo => write!(f, "Missing input utxo in pbst"),
1336 SighashError::MissingSpendUtxos => write!(f, "Missing Psbt spend utxos"),
1337 SighashError::InvalidSighashType => write!(f, "Invalid Sighash type"),
1338 SighashError::MissingWitnessScript => write!(f, "Missing Witness Script"),
1339 SighashError::MissingRedeemScript => write!(f, "Missing Redeem Script"),
1340 SighashError::SighashTaproot(ref e) => write!(f, "sighash taproot: {}", e),
1341 SighashError::SighashP2wpkh(ref e) => write!(f, "sighash p2wpkh: {}", e),
1342 SighashError::TransactionInputsIndex(ref e) => write!(f, "tx inputs index: {}", e),
1343 }
1344 }
1345}
1346
1347#[cfg(feature = "std")]
1348impl error::Error for SighashError {
1349 fn cause(&self) -> Option<&dyn error::Error> {
1350 use self::SighashError::*;
1351
1352 match self {
1353 IndexOutOfBounds(_, _)
1354 | MissingInputUtxo
1355 | MissingSpendUtxos
1356 | InvalidSighashType
1357 | MissingWitnessScript
1358 | MissingRedeemScript => None,
1359 SighashTaproot(ref e) => Some(e),
1360 SighashP2wpkh(ref e) => Some(e),
1361 TransactionInputsIndex(ref e) => Some(e),
1362 }
1363 }
1364}
1365
1366impl From<sighash::TaprootError> for SighashError {
1367 fn from(e: sighash::TaprootError) -> Self { SighashError::SighashTaproot(e) }
1368}
1369
1370impl From<sighash::P2wpkhError> for SighashError {
1371 fn from(e: sighash::P2wpkhError) -> Self { SighashError::SighashP2wpkh(e) }
1372}
1373
1374impl From<transaction::InputsIndexError> for SighashError {
1375 fn from(e: transaction::InputsIndexError) -> Self { SighashError::TransactionInputsIndex(e) }
1376}
1377
1378#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
1380pub enum PsbtSighashMsg {
1381 TapSighash(sighash::TapSighash),
1383 LegacySighash(sighash::LegacySighash),
1385 SegwitV0Sighash(sighash::SegwitV0Sighash),
1387}
1388
1389impl PsbtSighashMsg {
1390 pub fn to_secp_msg(&self) -> secp256k1::Message {
1392 match *self {
1393 PsbtSighashMsg::TapSighash(msg) => secp256k1::Message::from_digest(msg.to_byte_array()),
1394 PsbtSighashMsg::LegacySighash(msg) => {
1395 secp256k1::Message::from_digest(msg.to_byte_array())
1396 }
1397 PsbtSighashMsg::SegwitV0Sighash(msg) => {
1398 secp256k1::Message::from_digest(msg.to_byte_array())
1399 }
1400 }
1401 }
1402}
1403
1404#[cfg(test)]
1405mod tests {
1406 use std::str::FromStr;
1407
1408 use bitcoin::bip32::{DerivationPath, Xpub};
1409 use bitcoin::consensus::encode::deserialize;
1410 use bitcoin::hashes::hex::FromHex;
1411 use bitcoin::key::XOnlyPublicKey;
1412 use bitcoin::secp256k1::PublicKey;
1413 use bitcoin::{Amount, OutPoint, TxIn, TxOut};
1414
1415 use super::*;
1416 use crate::Miniscript;
1417
1418 #[test]
1419 fn test_extract_bip174() {
1420 let psbt = bitcoin::Psbt::deserialize(&Vec::<u8>::from_hex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap();
1421 let secp = Secp256k1::verification_only();
1422 let tx = psbt.extract(&secp).unwrap();
1423 let expected: bitcoin::Transaction = deserialize(&Vec::<u8>::from_hex("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000").unwrap()).unwrap();
1424 assert_eq!(tx, expected);
1425 }
1426
1427 #[test]
1428 fn test_update_item_tr_no_script() {
1429 let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1431 let fingerprint = root_xpub.fingerprint();
1432 let desc = format!("tr([{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)", fingerprint);
1433 let desc = Descriptor::from_str(&desc).unwrap();
1434 let mut psbt_input = psbt::Input::default();
1435 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1436 let mut psbt_output = psbt::Output::default();
1437 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1438 let internal_key = XOnlyPublicKey::from_str(
1439 "cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115",
1440 )
1441 .unwrap();
1442 assert_eq!(psbt_input.tap_internal_key, Some(internal_key));
1443 assert_eq!(
1444 psbt_input.tap_key_origins.get(&internal_key),
1445 Some(&(vec![], (fingerprint, DerivationPath::from_str("m/86'/0'/0'/0/0").unwrap())))
1446 );
1447 assert_eq!(psbt_input.tap_key_origins.len(), 1);
1448 assert_eq!(psbt_input.tap_scripts.len(), 0);
1449 assert_eq!(psbt_input.tap_merkle_root, None);
1450
1451 assert_eq!(psbt_output.tap_internal_key, psbt_input.tap_internal_key);
1452 assert_eq!(psbt_output.tap_key_origins, psbt_input.tap_key_origins);
1453 assert_eq!(psbt_output.tap_tree, None);
1454 }
1455
1456 #[test]
1457 fn test_update_item_tr_with_tapscript() {
1458 use crate::Tap;
1459 let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1461 let fingerprint = root_xpub.fingerprint();
1462 let xpub = format!("[{}/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", fingerprint);
1463 let desc =
1464 format!("tr({}/0/0,{{pkh({}/0/1),multi_a(2,{}/0/1,{}/1/0)}})", xpub, xpub, xpub, xpub);
1465
1466 let desc = Descriptor::from_str(&desc).unwrap();
1467 let internal_key = XOnlyPublicKey::from_str(
1468 "cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115",
1469 )
1470 .unwrap();
1471 let mut psbt_input = psbt::Input::default();
1472 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1473 let mut psbt_output = psbt::Output::default();
1474 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1475 assert_eq!(psbt_input.tap_internal_key, Some(internal_key));
1476 assert_eq!(
1477 psbt_input.tap_key_origins.get(&internal_key),
1478 Some(&(vec![], (fingerprint, DerivationPath::from_str("m/86'/0'/0'/0/0").unwrap())))
1479 );
1480 assert_eq!(psbt_input.tap_key_origins.len(), 3);
1481 assert_eq!(psbt_input.tap_scripts.len(), 2);
1482 assert!(psbt_input.tap_merkle_root.is_some());
1483
1484 assert_eq!(psbt_output.tap_internal_key, psbt_input.tap_internal_key);
1485 assert_eq!(psbt_output.tap_key_origins, psbt_input.tap_key_origins);
1486 assert!(psbt_output.tap_tree.is_some());
1487
1488 let key_0_1 = XOnlyPublicKey::from_str(
1489 "83dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145",
1490 )
1491 .unwrap();
1492 let first_leaf_hash = {
1493 let ms =
1494 Miniscript::<XOnlyPublicKey, Tap>::from_str(&format!("pkh({})", &key_0_1)).unwrap();
1495 let first_script = ms.encode();
1496 assert!(psbt_input
1497 .tap_scripts
1498 .values()
1499 .any(|value| *value == (first_script.clone(), LeafVersion::TapScript)));
1500 TapLeafHash::from_script(&first_script, LeafVersion::TapScript)
1501 };
1502
1503 {
1504 let (leaf_hashes, (key_fingerprint, deriv_path)) =
1506 psbt_input.tap_key_origins.get(&key_0_1).unwrap();
1507 assert_eq!(key_fingerprint, &fingerprint);
1508 assert_eq!(&deriv_path.to_string(), "86'/0'/0'/0/1");
1509 assert_eq!(leaf_hashes.len(), 2);
1510 assert!(leaf_hashes.contains(&first_leaf_hash));
1511 }
1512
1513 {
1514 let key_1_0 = XOnlyPublicKey::from_str(
1516 "399f1b2f4393f29a18c937859c5dd8a77350103157eb880f02e8c08214277cef",
1517 )
1518 .unwrap();
1519 let (leaf_hashes, (key_fingerprint, deriv_path)) =
1520 psbt_input.tap_key_origins.get(&key_1_0).unwrap();
1521 assert_eq!(key_fingerprint, &fingerprint);
1522 assert_eq!(&deriv_path.to_string(), "86'/0'/0'/1/0");
1523 assert_eq!(leaf_hashes.len(), 1);
1524 assert!(!leaf_hashes.contains(&first_leaf_hash));
1525 }
1526 }
1527
1528 #[test]
1529 fn test_update_item_non_tr_multi() {
1530 let root_xpub = Xpub::from_str("xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8").unwrap();
1532 let fingerprint = root_xpub.fingerprint();
1533 let xpub = format!("[{}/84'/0'/0']xpub6CatWdiZiodmUeTDp8LT5or8nmbKNcuyvz7WyksVFkKB4RHwCD3XyuvPEbvqAQY3rAPshWcMLoP2fMFMKHPJ4ZeZXYVUhLv1VMrjPC7PW6V", fingerprint);
1534 let pubkeys = [
1535 "0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c",
1536 "03e775fd51f0dfb8cd865d9ff1cca2a158cf651fe997fdc9fee9c1d3b5e995ea77",
1537 "03025324888e429ab8e3dbaf1f7802648b9cd01e9b418485c5fa4c1b9b5700e1a6",
1538 ];
1539
1540 let expected_bip32 = pubkeys
1541 .iter()
1542 .zip(["0/0", "0/1", "1/0"].iter())
1543 .map(|(pubkey, path)| {
1544 (
1545 PublicKey::from_str(pubkey).unwrap(),
1546 (
1547 fingerprint,
1548 DerivationPath::from_str(&format!("m/84'/0'/0'/{}", path)).unwrap(),
1549 ),
1550 )
1551 })
1552 .collect::<BTreeMap<_, _>>();
1553
1554 {
1555 let desc = format!("wsh(multi(2,{}/0/0,{}/0/1,{}/1/0))", xpub, xpub, xpub);
1557 let desc = Descriptor::from_str(&desc).unwrap();
1558 let derived = format!("wsh(multi(2,{}))", pubkeys.join(","));
1559 let derived = Descriptor::<bitcoin::PublicKey>::from_str(&derived).unwrap();
1560
1561 let mut psbt_input = psbt::Input::default();
1562 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1563
1564 let mut psbt_output = psbt::Output::default();
1565 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1566
1567 assert_eq!(expected_bip32, psbt_input.bip32_derivation);
1568 assert_eq!(psbt_input.witness_script, Some(derived.explicit_script().unwrap()));
1569
1570 assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation);
1571 assert_eq!(psbt_output.witness_script, psbt_input.witness_script);
1572 }
1573
1574 {
1575 let desc = format!("sh(multi(2,{}/0/0,{}/0/1,{}/1/0))", xpub, xpub, xpub);
1577 let desc = Descriptor::from_str(&desc).unwrap();
1578 let derived = format!("sh(multi(2,{}))", pubkeys.join(","));
1579 let derived = Descriptor::<bitcoin::PublicKey>::from_str(&derived).unwrap();
1580
1581 let mut psbt_input = psbt::Input::default();
1582 psbt_input.update_with_descriptor_unchecked(&desc).unwrap();
1583
1584 let mut psbt_output = psbt::Output::default();
1585 psbt_output.update_with_descriptor_unchecked(&desc).unwrap();
1586
1587 assert_eq!(psbt_input.bip32_derivation, expected_bip32);
1588 assert_eq!(psbt_input.witness_script, None);
1589 assert_eq!(psbt_input.redeem_script, Some(derived.explicit_script().unwrap()));
1590
1591 assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation);
1592 assert_eq!(psbt_output.witness_script, psbt_input.witness_script);
1593 assert_eq!(psbt_output.redeem_script, psbt_input.redeem_script);
1594 }
1595 }
1596
1597 #[test]
1598 fn test_update_input_checks() {
1599 let desc = "tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)";
1600 let desc = Descriptor::<DefiniteDescriptorKey>::from_str(desc).unwrap();
1601
1602 let mut non_witness_utxo = bitcoin::Transaction {
1603 version: transaction::Version::ONE,
1604 lock_time: absolute::LockTime::ZERO,
1605 input: vec![],
1606 output: vec![TxOut {
1607 value: Amount::from_sat(1_000),
1608 script_pubkey: ScriptBuf::from_hex(
1609 "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c",
1610 )
1611 .unwrap(),
1612 }],
1613 };
1614
1615 let tx = bitcoin::Transaction {
1616 version: transaction::Version::ONE,
1617 lock_time: absolute::LockTime::ZERO,
1618 input: vec![TxIn {
1619 previous_output: OutPoint { txid: non_witness_utxo.compute_txid(), vout: 0 },
1620 ..Default::default()
1621 }],
1622 output: vec![],
1623 };
1624
1625 let mut psbt = Psbt::from_unsigned_tx(tx).unwrap();
1626 assert_eq!(
1627 psbt.update_input_with_descriptor(0, &desc),
1628 Err(UtxoUpdateError::UtxoCheck),
1629 "neither *_utxo are not set"
1630 );
1631 psbt.inputs[0].witness_utxo = Some(non_witness_utxo.output[0].clone());
1632 assert_eq!(
1633 psbt.update_input_with_descriptor(0, &desc),
1634 Ok(()),
1635 "witness_utxo is set which is ok"
1636 );
1637 psbt.inputs[0].non_witness_utxo = Some(non_witness_utxo.clone());
1638 assert_eq!(
1639 psbt.update_input_with_descriptor(0, &desc),
1640 Ok(()),
1641 "matching non_witness_utxo"
1642 );
1643 non_witness_utxo.version = transaction::Version::non_standard(0);
1644 psbt.inputs[0].non_witness_utxo = Some(non_witness_utxo);
1645 assert_eq!(
1646 psbt.update_input_with_descriptor(0, &desc),
1647 Err(UtxoUpdateError::UtxoCheck),
1648 "non_witness_utxo no longer matches"
1649 );
1650 psbt.inputs[0].non_witness_utxo = None;
1651 psbt.inputs[0].witness_utxo.as_mut().unwrap().script_pubkey = ScriptBuf::default();
1652 assert_eq!(
1653 psbt.update_input_with_descriptor(0, &desc),
1654 Err(UtxoUpdateError::MismatchedScriptPubkey),
1655 "non_witness_utxo no longer matches"
1656 );
1657 }
1658
1659 #[test]
1660 fn test_update_output_checks() {
1661 let desc = "tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)";
1662 let desc = Descriptor::<DefiniteDescriptorKey>::from_str(desc).unwrap();
1663
1664 let tx = bitcoin::Transaction {
1665 version: transaction::Version::ONE,
1666 lock_time: absolute::LockTime::ZERO,
1667 input: vec![],
1668 output: vec![TxOut {
1669 value: Amount::from_sat(1_000),
1670 script_pubkey: ScriptBuf::from_hex(
1671 "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c",
1672 )
1673 .unwrap(),
1674 }],
1675 };
1676
1677 let mut psbt = Psbt::from_unsigned_tx(tx).unwrap();
1678 assert_eq!(
1679 psbt.update_output_with_descriptor(1, &desc),
1680 Err(OutputUpdateError::IndexOutOfBounds(1, 1)),
1681 "output index doesn't exist"
1682 );
1683 assert_eq!(
1684 psbt.update_output_with_descriptor(0, &desc),
1685 Ok(()),
1686 "script_pubkey should match"
1687 );
1688 psbt.unsigned_tx.output[0].script_pubkey = ScriptBuf::default();
1689 assert_eq!(
1690 psbt.update_output_with_descriptor(0, &desc),
1691 Err(OutputUpdateError::MismatchedScriptPubkey),
1692 "output script_pubkey no longer matches"
1693 );
1694 }
1695}