1
2use bitcoin::absolute::LockTime;
3use bitcoin::hashes::sha256;
4use bitcoin::key::constants::SCHNORR_SIGNATURE_SIZE;
5use bitcoin::secp256k1::schnorr;
6use bitcoin::taproot::{self, ControlBlock};
7use bitcoin::{Sequence, VarInt, Witness};
8use bitcoin::{secp256k1::PublicKey, ScriptBuf};
9
10use bitcoin_ext::{BlockDelta, BlockHeight};
11
12use crate::lightning::{PaymentHash, Preimage};
13use crate::vtxo::policy::Policy;
14use crate::Vtxo;
15use crate::scripts;
16
17pub trait TapScriptClause: Sized + Clone {
22 type WitnessData;
24
25 fn tapscript(&self) -> ScriptBuf;
27
28 fn control_block<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> ControlBlock {
30 vtxo.output_taproot()
31 .control_block(&(self.tapscript(), taproot::LeafVersion::TapScript))
32 .expect("clause is not in taproot tree")
33 }
34
35 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize;
46
47 fn witness(
49 &self,
50 data: &Self::WitnessData,
51 control_block: &ControlBlock,
52 ) -> Witness;
53}
54
55#[derive(Debug, Clone)]
58pub struct DelayedSignClause {
59 pub pubkey: PublicKey,
60 pub block_delta: BlockDelta,
61}
62
63impl DelayedSignClause {
64 pub fn sequence(&self) -> Sequence {
66 Sequence::from_height(self.block_delta)
67 }
68}
69
70impl TapScriptClause for DelayedSignClause {
71 type WitnessData = schnorr::Signature;
72
73 fn tapscript(&self) -> ScriptBuf {
74 scripts::delayed_sign(self.block_delta, self.pubkey.x_only_public_key().0)
75 }
76
77 fn witness(
78 &self,
79 signature: &Self::WitnessData,
80 control_block: &ControlBlock,
81 ) -> Witness {
82 Witness::from_slice(&[
83 &signature[..],
84 self.tapscript().as_bytes(),
85 &control_block.serialize()[..],
86 ])
87 }
88
89
90 #[allow(clippy::arithmetic_side_effects)]
92 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
93 let cb_size = self.control_block(vtxo).size();
94 let tapscript_size = self.tapscript().as_bytes().len();
95
96 1 + 1 + SCHNORR_SIGNATURE_SIZE + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
104}
105
106impl Into<VtxoClause> for DelayedSignClause {
107 fn into(self) -> VtxoClause {
108 VtxoClause::DelayedSign(self)
109 }
110}
111
112#[derive(Debug, Clone)]
115pub struct TimelockSignClause {
116 pub pubkey: PublicKey,
117 pub timelock_height: BlockHeight,
118}
119
120impl TimelockSignClause {
121 pub fn locktime(&self) -> LockTime {
123 LockTime::from_height(self.timelock_height).expect("timelock height is valid")
124 }
125}
126
127impl TapScriptClause for TimelockSignClause {
128 type WitnessData = schnorr::Signature;
129
130 fn tapscript(&self) -> ScriptBuf {
131 scripts::timelock_sign(self.timelock_height, self.pubkey.x_only_public_key().0)
132 }
133
134 fn witness(
135 &self,
136 signature: &Self::WitnessData,
137 control_block: &ControlBlock,
138 ) -> Witness {
139 Witness::from_slice(&[
140 &signature[..],
141 self.tapscript().as_bytes(),
142 &control_block.serialize()[..],
143 ])
144 }
145
146 #[allow(clippy::arithmetic_side_effects)]
148 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
149 let cb_size = self.control_block(vtxo).size();
150 let tapscript_size = self.tapscript().as_bytes().len();
151
152 1 + 1 + SCHNORR_SIGNATURE_SIZE + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
160}
161
162impl Into<VtxoClause> for TimelockSignClause {
163 fn into(self) -> VtxoClause {
164 VtxoClause::TimelockSign(self)
165 }
166}
167
168#[derive(Debug, Clone)]
171pub struct DelayedTimelockSignClause {
172 pub pubkey: PublicKey,
173 pub timelock_height: BlockHeight,
174 pub block_delta: BlockDelta,
175}
176
177impl DelayedTimelockSignClause {
178 pub fn sequence(&self) -> Sequence {
180 Sequence::from_height(self.block_delta)
181 }
182
183 pub fn locktime(&self) -> LockTime {
185 LockTime::from_height(self.timelock_height).expect("timelock height is valid")
186 }
187}
188
189impl TapScriptClause for DelayedTimelockSignClause {
190 type WitnessData = schnorr::Signature;
191
192 fn tapscript(&self) -> ScriptBuf {
193 scripts::delay_timelock_sign(
194 self.block_delta,
195 self.timelock_height,
196 self.pubkey.x_only_public_key().0,
197 )
198 }
199
200 fn witness(
201 &self,
202 signature: &Self::WitnessData,
203 control_block: &ControlBlock,
204 ) -> Witness {
205 Witness::from_slice(&[
206 &signature[..],
207 self.tapscript().as_bytes(),
208 &control_block.serialize()[..],
209 ])
210 }
211
212 #[allow(clippy::arithmetic_side_effects)]
214 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
215 let cb_size = self.control_block(vtxo).size();
216 let tapscript_size = self.tapscript().as_bytes().len();
217
218 1 + 1 + SCHNORR_SIGNATURE_SIZE + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
226}
227
228impl Into<VtxoClause> for DelayedTimelockSignClause {
229 fn into(self) -> VtxoClause {
230 VtxoClause::DelayedTimelockSign(self)
231 }
232}
233
234#[derive(Debug, Clone)]
237pub struct HashDelaySignClause {
238 pub pubkey: PublicKey,
239 pub hash: sha256::Hash,
240 pub block_delta: BlockDelta,
241}
242
243impl HashDelaySignClause {
244 pub fn sequence(&self) -> Sequence {
246 Sequence::from_height(self.block_delta)
247 }
248
249 pub fn extract_preimage_from_witness(
261 witness: &Witness,
262 payment_hash: PaymentHash,
263 ) -> Option<Preimage> {
264 witness.iter()
265 .filter_map(|item| Preimage::try_from(item).ok())
266 .find(|preimage| preimage.compute_payment_hash() == payment_hash)
267 }
268}
269
270impl TapScriptClause for HashDelaySignClause {
271 type WitnessData = (schnorr::Signature, [u8; 32]);
272
273 fn tapscript(&self) -> ScriptBuf {
274 scripts::hash_delay_sign(
275 self.hash,
276 self.block_delta,
277 self.pubkey.x_only_public_key().0,
278 )
279 }
280
281 fn witness(
282 &self,
283 data: &Self::WitnessData,
284 control_block: &ControlBlock,
285 ) -> Witness {
286 let (signature, preimage) = data;
287 Witness::from_slice(&[
288 &signature[..],
289 &preimage[..],
290 self.tapscript().as_bytes(),
291 &control_block.serialize()[..],
292 ])
293 }
294
295 #[allow(clippy::arithmetic_side_effects)]
297 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
298 let cb_size = self.control_block(vtxo).size();
299 let tapscript_size = self.tapscript().as_bytes().len();
300
301 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
311}
312
313impl Into<VtxoClause> for HashDelaySignClause {
314 fn into(self) -> VtxoClause {
315 VtxoClause::HashDelaySign(self)
316 }
317}
318
319#[derive(Debug, Clone)]
322#[allow(non_camel_case_types)]
323pub struct HashDelaySignClause_v0 {
324 pub pubkey: PublicKey,
325 pub hash: sha256::Hash,
326 pub block_delta: BlockDelta,
327}
328
329impl HashDelaySignClause_v0 {
330 pub fn sequence(&self) -> Sequence {
332 Sequence::from_height(self.block_delta)
333 }
334
335 pub fn extract_preimage_from_witness(
347 witness: &Witness,
348 payment_hash: PaymentHash,
349 ) -> Option<Preimage> {
350 witness.iter()
351 .filter_map(|item| Preimage::try_from(item).ok())
352 .find(|preimage| preimage.compute_payment_hash() == payment_hash)
353 }
354}
355
356impl TapScriptClause for HashDelaySignClause_v0 {
357 type WitnessData = (schnorr::Signature, [u8; 32]);
358
359 fn tapscript(&self) -> ScriptBuf {
360 scripts::hash_delay_sign_v0(
361 self.hash,
362 self.block_delta,
363 self.pubkey.x_only_public_key().0,
364 )
365 }
366
367 fn witness(
368 &self,
369 data: &Self::WitnessData,
370 control_block: &ControlBlock,
371 ) -> Witness {
372 let (signature, preimage) = data;
373 Witness::from_slice(&[
374 &signature[..],
375 &preimage[..],
376 self.tapscript().as_bytes(),
377 &control_block.serialize()[..],
378 ])
379 }
380
381 #[allow(clippy::arithmetic_side_effects)]
383 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
384 let cb_size = self.control_block(vtxo).size();
385 let tapscript_size = self.tapscript().as_bytes().len();
386
387 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
397}
398
399impl Into<VtxoClause> for HashDelaySignClause_v0 {
400 fn into(self) -> VtxoClause {
401 VtxoClause::HashDelaySign_v0(self)
402 }
403}
404
405#[derive(Debug, Clone)]
410pub struct HashSignClause {
411 pub pubkey: PublicKey,
412 pub hash: sha256::Hash,
413}
414
415impl TapScriptClause for HashSignClause {
416 type WitnessData = (schnorr::Signature, [u8; 32]);
417
418 fn tapscript(&self) -> ScriptBuf {
419 scripts::hash_and_sign(self.hash, self.pubkey.x_only_public_key().0)
420 }
421
422 fn witness(
423 &self,
424 data: &Self::WitnessData,
425 control_block: &ControlBlock,
426 ) -> Witness {
427 let (signature, preimage) = data;
428 Witness::from_slice(&[
429 &signature[..],
430 &preimage[..],
431 self.tapscript().as_bytes(),
432 &control_block.serialize()[..],
433 ])
434 }
435
436 #[allow(clippy::arithmetic_side_effects)]
438 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
439 let cb_size = self.control_block(vtxo).size();
440 let tapscript_size = self.tapscript().as_bytes().len();
441
442 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
452}
453
454impl Into<VtxoClause> for HashSignClause {
455 fn into(self) -> VtxoClause {
456 VtxoClause::HashSign(self)
457 }
458}
459
460#[derive(Debug, Clone)]
465#[allow(non_camel_case_types)]
466pub struct HashSignClause_v0 {
467 pub pubkey: PublicKey,
468 pub hash: sha256::Hash,
469}
470
471impl TapScriptClause for HashSignClause_v0 {
472 type WitnessData = (schnorr::Signature, [u8; 32]);
473
474 fn tapscript(&self) -> ScriptBuf {
475 scripts::hash_and_sign_v0(self.hash, self.pubkey.x_only_public_key().0)
476 }
477
478 fn witness(
479 &self,
480 data: &Self::WitnessData,
481 control_block: &ControlBlock,
482 ) -> Witness {
483 let (signature, preimage) = data;
484 Witness::from_slice(&[
485 &signature[..],
486 &preimage[..],
487 self.tapscript().as_bytes(),
488 &control_block.serialize()[..],
489 ])
490 }
491
492 #[allow(clippy::arithmetic_side_effects)]
494 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
495 let cb_size = self.control_block(vtxo).size();
496 let tapscript_size = 57;
497
498 debug_assert_eq!(tapscript_size, self.tapscript().as_bytes().len());
499
500 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
510}
511
512impl Into<VtxoClause> for HashSignClause_v0 {
513 fn into(self) -> VtxoClause {
514 VtxoClause::HashSign_v0(self)
515 }
516}
517
518#[derive(Debug, Clone)]
519pub enum VtxoClause {
520 DelayedSign(DelayedSignClause),
521 TimelockSign(TimelockSignClause),
522 DelayedTimelockSign(DelayedTimelockSignClause),
523 HashDelaySign(HashDelaySignClause),
524 HashSign(HashSignClause),
525 #[allow(non_camel_case_types)]
526 HashDelaySign_v0(HashDelaySignClause_v0),
527 #[allow(non_camel_case_types)]
528 HashSign_v0(HashSignClause_v0),
529}
530
531impl VtxoClause {
532 pub fn pubkey(&self) -> PublicKey {
534 match self {
535 Self::DelayedSign(c) => c.pubkey,
536 Self::TimelockSign(c) => c.pubkey,
537 Self::DelayedTimelockSign(c) => c.pubkey,
538 Self::HashDelaySign(c) => c.pubkey,
539 Self::HashSign(c) => c.pubkey,
540 Self::HashDelaySign_v0(c) => c.pubkey,
541 Self::HashSign_v0(c) => c.pubkey,
542 }
543 }
544
545
546 pub fn tapscript(&self) -> ScriptBuf {
548 match self {
549 Self::DelayedSign(c) => c.tapscript(),
550 Self::TimelockSign(c) => c.tapscript(),
551 Self::DelayedTimelockSign(c) => c.tapscript(),
552 Self::HashDelaySign(c) => c.tapscript(),
553 Self::HashSign(c) => c.tapscript(),
554 Self::HashDelaySign_v0(c) => c.tapscript(),
555 Self::HashSign_v0(c) => c.tapscript(),
556 }
557 }
558
559 pub fn sequence(&self) -> Option<Sequence> {
561 match self {
562 Self::DelayedSign(c) => Some(c.sequence()),
563 Self::TimelockSign(_) => None,
564 Self::DelayedTimelockSign(c) => Some(c.sequence()),
565 Self::HashDelaySign(c) => Some(c.sequence()),
566 Self::HashSign(_) => None,
567 Self::HashDelaySign_v0(c) => Some(c.sequence()),
568 Self::HashSign_v0(_) => None,
569 }
570 }
571
572 pub fn control_block<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> ControlBlock {
574 match self {
575 Self::DelayedSign(c) => c.control_block(vtxo),
576 Self::TimelockSign(c) => c.control_block(vtxo),
577 Self::DelayedTimelockSign(c) => c.control_block(vtxo),
578 Self::HashDelaySign(c) => c.control_block(vtxo),
579 Self::HashSign(c) => c.control_block(vtxo),
580 Self::HashDelaySign_v0(c) => c.control_block(vtxo),
581 Self::HashSign_v0(c) => c.control_block(vtxo),
582 }
583 }
584
585 pub fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
587 match self {
588 Self::DelayedSign(c) => c.witness_size(vtxo),
589 Self::TimelockSign(c) => c.witness_size(vtxo),
590 Self::DelayedTimelockSign(c) => c.witness_size(vtxo),
591 Self::HashDelaySign(c) => c.witness_size(vtxo),
592 Self::HashSign(c) => c.witness_size(vtxo),
593 Self::HashDelaySign_v0(c) => c.witness_size(vtxo),
594 Self::HashSign_v0(c) => c.witness_size(vtxo),
595 }
596 }
597}
598
599#[cfg(test)]
600mod tests {
601 use std::str::FromStr;
602
603 use bitcoin::taproot::TaprootSpendInfo;
604 use bitcoin::{Amount, OutPoint, Transaction, TxIn, TxOut, Txid, sighash};
605 use bitcoin::hashes::Hash;
606 use bitcoin::key::Keypair;
607 use bitcoin_ext::{TaprootSpendInfoExt, fee};
608
609 use crate::{SECP, musig};
610 use crate::test_util::verify_tx;
611
612 use super::*;
613
614 lazy_static! {
615 static ref USER_KEYPAIR: Keypair = Keypair::from_str("5255d132d6ec7d4fc2a41c8f0018bb14343489ddd0344025cc60c7aa2b3fda6a").unwrap();
616 static ref SERVER_KEYPAIR: Keypair = Keypair::from_str("1fb316e653eec61de11c6b794636d230379509389215df1ceb520b65313e5426").unwrap();
617 }
618
619 #[allow(unused)]
620 fn all_clause_tested(clause: VtxoClause) -> bool {
621 match clause {
623 VtxoClause::DelayedSign(_) => true,
624 VtxoClause::TimelockSign(_) => true,
625 VtxoClause::DelayedTimelockSign(_) => true,
626 VtxoClause::HashDelaySign(_) => true,
627 VtxoClause::HashSign(_) => true,
628 VtxoClause::HashDelaySign_v0(_) => true,
629 VtxoClause::HashSign_v0(_) => true,
630 }
631 }
632
633 fn transaction() -> Transaction {
634 let address = bitcoin::Address::from_str("tb1q00h5delzqxl7xae8ufmsegghcl4jwfvdnd8530")
635 .unwrap().assume_checked();
636
637 Transaction {
638 version: bitcoin::transaction::Version(3),
639 lock_time: bitcoin::absolute::LockTime::ZERO,
640 input: vec![],
641 output: vec![TxOut {
642 script_pubkey: address.script_pubkey(),
643 value: Amount::from_sat(900_000),
644 }, fee::fee_anchor()]
645 }
646 }
647
648 fn taproot_material(clause_spk: ScriptBuf) -> (TaprootSpendInfo, ControlBlock) {
649 let user_pubkey = USER_KEYPAIR.public_key();
650 let server_pubkey = SERVER_KEYPAIR.public_key();
651
652 let combined_pk = musig::combine_keys([user_pubkey, server_pubkey])
653 .x_only_public_key().0;
654 let taproot = taproot::TaprootBuilder::new()
655 .add_leaf(0, clause_spk.clone()).unwrap()
656 .finalize(&SECP, combined_pk).unwrap();
657
658 let cb = taproot
659 .control_block(&(clause_spk.clone(), taproot::LeafVersion::TapScript))
660 .expect("script is in taproot");
661
662 (taproot, cb)
663 }
664
665 fn signature(tx: &Transaction, input: &TxOut, clause_spk: ScriptBuf) -> schnorr::Signature {
666 let leaf_hash = taproot::TapLeafHash::from_script(
667 &clause_spk,
668 taproot::LeafVersion::TapScript,
669 );
670
671 let mut shc = sighash::SighashCache::new(tx);
672 let sighash = shc.taproot_script_spend_signature_hash(
673 0, &sighash::Prevouts::All(&[input.clone()]), leaf_hash, sighash::TapSighashType::Default,
674 ).expect("all prevouts provided");
675
676 SECP.sign_schnorr(&sighash.into(), &*USER_KEYPAIR)
677 }
678
679 #[test]
680 fn test_delayed_sign_clause() {
681 let clause = DelayedSignClause {
682 pubkey: USER_KEYPAIR.public_key(),
683 block_delta: 100,
684 };
685
686 let (taproot, cb) = taproot_material(clause.tapscript());
688 let tx_in = TxOut {
689 script_pubkey: taproot.script_pubkey(),
690 value: Amount::from_sat(1_000_000),
691 };
692
693 let mut tx = transaction();
695 tx.input.push(TxIn {
696 previous_output: OutPoint::new(Txid::all_zeros(), 0),
697 script_sig: ScriptBuf::default(),
698 sequence: clause.sequence(),
699 witness: Witness::new(),
700 });
701
702 let signature = signature(&tx, &tx_in, clause.tapscript());
704 tx.input[0].witness = clause.witness(&signature, &cb);
705
706 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
708 }
709
710 #[test]
711 fn test_timelock_sign_clause() {
712 let clause = TimelockSignClause {
713 pubkey: USER_KEYPAIR.public_key(),
714 timelock_height: 100,
715 };
716
717 let (taproot, cb) = taproot_material(clause.tapscript());
719 let tx_in = TxOut {
720 script_pubkey: taproot.script_pubkey(),
721 value: Amount::from_sat(1_000_000),
722 };
723
724 let mut tx = transaction();
726 tx.lock_time = clause.locktime();
727 tx.input.push(TxIn {
728 previous_output: OutPoint::new(Txid::all_zeros(), 0),
729 script_sig: ScriptBuf::default(),
730 sequence: Sequence::ZERO,
731 witness: Witness::new(),
732 });
733
734 let signature = signature(&tx, &tx_in, clause.tapscript());
736 tx.input[0].witness = clause.witness(&signature, &cb);
737
738 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
740 }
741
742 #[test]
743 fn test_delayed_timelock_clause() {
744 let clause = DelayedTimelockSignClause {
745 pubkey: USER_KEYPAIR.public_key(),
746 timelock_height: 100,
747 block_delta: 24,
748 };
749
750 let (taproot, cb) = taproot_material(clause.tapscript());
752 let tx_in = TxOut {
753 script_pubkey: taproot.script_pubkey(),
754 value: Amount::from_sat(1_000_000),
755 };
756
757 let mut tx = transaction();
759 tx.lock_time = clause.locktime();
760 tx.input.push(TxIn {
761 previous_output: OutPoint::new(Txid::all_zeros(), 0),
762 script_sig: ScriptBuf::default(),
763 sequence: clause.sequence(),
764 witness: Witness::new(),
765 });
766
767 let signature = signature(&tx, &tx_in, clause.tapscript());
769 tx.input[0].witness = clause.witness(&signature, &cb);
770
771 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
773 }
774
775 #[test]
776 fn test_hash_delay_clause() {
777 let preimage = [0; 32];
778
779 let clause = HashDelaySignClause_v0 {
780 pubkey: USER_KEYPAIR.public_key(),
781 hash: sha256::Hash::hash(&preimage),
782 block_delta: 24,
783 };
784
785 let (taproot, cb) = taproot_material(clause.tapscript());
787 let tx_in = TxOut {
788 script_pubkey: taproot.script_pubkey(),
789 value: Amount::from_sat(1_000_000),
790 };
791
792 let mut tx = transaction();
794 tx.input.push(TxIn {
795 previous_output: OutPoint::new(Txid::all_zeros(), 0),
796 script_sig: ScriptBuf::default(),
797 sequence: clause.sequence(),
798 witness: Witness::new(),
799 });
800
801 let signature = signature(&tx, &tx_in, clause.tapscript());
803 tx.input[0].witness = clause.witness(&(signature, preimage), &cb);
804
805 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
807 }
808
809 #[test]
810 fn test_extract_preimage_from_witness() {
811 let preimage_bytes = [42u8; 32];
812 let payment_hash = sha256::Hash::hash(&preimage_bytes);
813
814 let clause = HashDelaySignClause_v0 {
815 pubkey: USER_KEYPAIR.public_key(),
816 hash: payment_hash,
817 block_delta: 24,
818 };
819
820 let (taproot, cb) = taproot_material(clause.tapscript());
822 let tx_in = TxOut {
823 script_pubkey: taproot.script_pubkey(),
824 value: Amount::from_sat(1_000_000),
825 };
826
827 let mut tx = transaction();
828 tx.input.push(TxIn {
829 previous_output: OutPoint::new(Txid::all_zeros(), 0),
830 script_sig: ScriptBuf::default(),
831 sequence: clause.sequence(),
832 witness: Witness::new(),
833 });
834
835 let sig = signature(&tx, &tx_in, clause.tapscript());
836 let witness = clause.witness(&(sig, preimage_bytes), &cb);
837
838 let extracted = HashDelaySignClause_v0::extract_preimage_from_witness(
840 &witness,
841 payment_hash.into(),
842 );
843 assert!(extracted.is_some());
844 assert_eq!(extracted.unwrap().as_ref(), &preimage_bytes);
845
846 let wrong_hash = sha256::Hash::hash(&[0u8; 32]);
848 let extracted = HashDelaySignClause_v0::extract_preimage_from_witness(
849 &witness,
850 wrong_hash.into(),
851 );
852 assert!(extracted.is_none());
853
854 let other_preimage = [7u8; 32];
856 let no_preimage = Witness::from_slice(&[
857 &sig[..],
858 &other_preimage[..],
859 clause.tapscript().as_bytes(),
860 &cb.serialize()[..],
861 ]);
862 let extracted = HashDelaySignClause_v0::extract_preimage_from_witness(
863 &no_preimage,
864 payment_hash.into(),
865 );
866 assert!(extracted.is_none());
867 }
868
869 fn annexed_hash_delay_spend(
875 tapscript: ScriptBuf,
876 sequence: Sequence,
877 preimage: [u8; 32],
878 ) -> Witness {
879 let (taproot, cb) = taproot_material(tapscript.clone());
880 let tx_in = TxOut {
881 script_pubkey: taproot.script_pubkey(),
882 value: Amount::from_sat(1_000_000),
883 };
884
885 let mut tx = transaction();
886 tx.input.push(TxIn {
887 previous_output: OutPoint::new(Txid::all_zeros(), 0),
888 script_sig: ScriptBuf::default(),
889 sequence,
890 witness: Witness::new(),
891 });
892
893 let annex = [0x50u8, 0xde, 0xad, 0xbe, 0xef];
897
898 let leaf_hash = taproot::TapLeafHash::from_script(
899 &tapscript,
900 taproot::LeafVersion::TapScript,
901 );
902 let mut shc = sighash::SighashCache::new(&tx);
903 let sighash = shc.taproot_signature_hash(
904 0,
905 &sighash::Prevouts::All(&[tx_in.clone()]),
906 Some(sighash::Annex::new(&annex).unwrap()),
907 Some((leaf_hash, 0xFFFFFFFF)),
908 sighash::TapSighashType::Default,
909 ).expect("all prevouts provided");
910 let sig = SECP.sign_schnorr(&sighash.into(), &*USER_KEYPAIR);
911
912 let witness = Witness::from_slice(&[
913 &sig[..],
914 &preimage[..],
915 tapscript.as_bytes(),
916 &cb.serialize()[..],
917 &annex[..],
918 ]);
919 assert!(witness.taproot_annex().is_some());
920 tx.input[0].witness = witness.clone();
921
922 verify_tx(&[tx_in], 0, &tx).expect("annexed spend is invalid");
926
927 witness
928 }
929
930 #[test]
931 fn test_extract_preimage_from_annexed_witness() {
932 let preimage_bytes = [42u8; 32];
933 let payment_hash = sha256::Hash::hash(&preimage_bytes);
934
935 let clause = HashDelaySignClause {
936 pubkey: USER_KEYPAIR.public_key(),
937 hash: payment_hash,
938 block_delta: 24,
939 };
940 let witness = annexed_hash_delay_spend(
941 clause.tapscript(), clause.sequence(), preimage_bytes,
942 );
943 let extracted = HashDelaySignClause::extract_preimage_from_witness(
944 &witness,
945 payment_hash.into(),
946 ).expect("no preimage extracted from annexed witness");
947 assert_eq!(extracted.as_ref(), &preimage_bytes);
948
949 let clause_v0 = HashDelaySignClause_v0 {
950 pubkey: USER_KEYPAIR.public_key(),
951 hash: payment_hash,
952 block_delta: 24,
953 };
954 let witness = annexed_hash_delay_spend(
955 clause_v0.tapscript(), clause_v0.sequence(), preimage_bytes,
956 );
957 let extracted = HashDelaySignClause_v0::extract_preimage_from_witness(
958 &witness,
959 payment_hash.into(),
960 ).expect("no preimage extracted from annexed witness");
961 assert_eq!(extracted.as_ref(), &preimage_bytes);
962 }
963
964 #[test]
965 fn test_hash_sign_clause() {
966 let preimage = [0u8; 32];
967 let hash = sha256::Hash::hash(&preimage);
968
969 let agg_pk = musig::combine_keys([USER_KEYPAIR.public_key(), SERVER_KEYPAIR.public_key()]);
971
972 let clause = HashSignClause_v0 {
973 pubkey: agg_pk,
974 hash,
975 };
976
977 let (taproot, cb) = taproot_material(clause.tapscript());
979 let tx_in = TxOut {
980 script_pubkey: taproot.script_pubkey(),
981 value: Amount::from_sat(1_000_000),
982 };
983
984 let mut tx = transaction();
986 tx.input.push(TxIn {
987 previous_output: OutPoint::new(Txid::all_zeros(), 0),
988 script_sig: ScriptBuf::default(),
989 sequence: Sequence::ZERO, witness: Witness::new(),
991 });
992
993 let leaf_hash = taproot::TapLeafHash::from_script(
995 &clause.tapscript(),
996 taproot::LeafVersion::TapScript,
997 );
998
999 let mut shc = sighash::SighashCache::new(&tx);
1000 let sighash = shc.taproot_script_spend_signature_hash(
1001 0, &sighash::Prevouts::All(&[tx_in.clone()]), leaf_hash, sighash::TapSighashType::Default,
1002 ).expect("all prevouts provided");
1003
1004 let (user_sec_nonce, user_pub_nonce) = musig::nonce_pair(&*USER_KEYPAIR);
1006 let (server_pub_nonce, server_part_sig) = musig::deterministic_partial_sign(
1007 &*SERVER_KEYPAIR,
1008 [USER_KEYPAIR.public_key()],
1009 &[&user_pub_nonce],
1010 sighash.to_byte_array(),
1011 None,
1012 );
1013 let agg_nonce = musig::nonce_agg(&[&user_pub_nonce, &server_pub_nonce]);
1014
1015 let (_user_part_sig, final_sig) = musig::partial_sign(
1016 [USER_KEYPAIR.public_key(), SERVER_KEYPAIR.public_key()],
1017 agg_nonce,
1018 &*USER_KEYPAIR,
1019 user_sec_nonce,
1020 sighash.to_byte_array(),
1021 None,
1022 Some(&[&server_part_sig]),
1023 );
1024 let final_sig = final_sig.expect("should have final signature");
1025
1026 tx.input[0].witness = clause.witness(&(final_sig, preimage), &cb);
1027
1028 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
1030 }
1031}