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