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(
254 witness: &Witness,
255 payment_hash: PaymentHash,
256 ) -> Option<Preimage> {
257 if witness.len() != 4 {
258 return None;
259 }
260
261 let bytes = witness.nth(1)?;
262 let bytes: [u8; 32] = bytes.try_into().ok()?;
263
264 let preimage = Preimage::from(bytes);
265 if preimage.compute_payment_hash() != payment_hash {
266 return None;
267 }
268
269 Some(preimage)
270 }
271}
272
273impl TapScriptClause for HashDelaySignClause {
274 type WitnessData = (schnorr::Signature, [u8; 32]);
275
276 fn tapscript(&self) -> ScriptBuf {
277 scripts::hash_delay_sign(
278 self.hash,
279 self.block_delta,
280 self.pubkey.x_only_public_key().0,
281 )
282 }
283
284 fn witness(
285 &self,
286 data: &Self::WitnessData,
287 control_block: &ControlBlock,
288 ) -> Witness {
289 let (signature, preimage) = data;
290 Witness::from_slice(&[
291 &signature[..],
292 &preimage[..],
293 self.tapscript().as_bytes(),
294 &control_block.serialize()[..],
295 ])
296 }
297
298 #[allow(clippy::arithmetic_side_effects)]
300 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
301 let cb_size = self.control_block(vtxo).size();
302 let tapscript_size = self.tapscript().as_bytes().len();
303
304 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
314}
315
316impl Into<VtxoClause> for HashDelaySignClause {
317 fn into(self) -> VtxoClause {
318 VtxoClause::HashDelaySign(self)
319 }
320}
321
322#[derive(Debug, Clone)]
327pub struct HashSignClause {
328 pub pubkey: PublicKey,
329 pub hash: sha256::Hash,
330}
331
332impl TapScriptClause for HashSignClause {
333 type WitnessData = (schnorr::Signature, [u8; 32]);
334
335 fn tapscript(&self) -> ScriptBuf {
336 scripts::hash_and_sign(self.hash, self.pubkey.x_only_public_key().0)
337 }
338
339 fn witness(
340 &self,
341 data: &Self::WitnessData,
342 control_block: &ControlBlock,
343 ) -> Witness {
344 let (signature, preimage) = data;
345 Witness::from_slice(&[
346 &signature[..],
347 &preimage[..],
348 self.tapscript().as_bytes(),
349 &control_block.serialize()[..],
350 ])
351 }
352
353 #[allow(clippy::arithmetic_side_effects)]
355 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
356 let cb_size = self.control_block(vtxo).size();
357 let tapscript_size = 57;
358
359 debug_assert_eq!(tapscript_size, self.tapscript().as_bytes().len());
360
361 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
371}
372
373impl Into<VtxoClause> for HashSignClause {
374 fn into(self) -> VtxoClause {
375 VtxoClause::HashSign(self)
376 }
377}
378
379#[derive(Debug, Clone)]
380pub enum VtxoClause {
381 DelayedSign(DelayedSignClause),
382 TimelockSign(TimelockSignClause),
383 DelayedTimelockSign(DelayedTimelockSignClause),
384 HashDelaySign(HashDelaySignClause),
385 HashSign(HashSignClause),
386}
387
388impl VtxoClause {
389 pub fn pubkey(&self) -> PublicKey {
391 match self {
392 Self::DelayedSign(c) => c.pubkey,
393 Self::TimelockSign(c) => c.pubkey,
394 Self::DelayedTimelockSign(c) => c.pubkey,
395 Self::HashDelaySign(c) => c.pubkey,
396 Self::HashSign(c) => c.pubkey,
397 }
398 }
399
400
401 pub fn tapscript(&self) -> ScriptBuf {
403 match self {
404 Self::DelayedSign(c) => c.tapscript(),
405 Self::TimelockSign(c) => c.tapscript(),
406 Self::DelayedTimelockSign(c) => c.tapscript(),
407 Self::HashDelaySign(c) => c.tapscript(),
408 Self::HashSign(c) => c.tapscript(),
409 }
410 }
411
412 pub fn sequence(&self) -> Option<Sequence> {
414 match self {
415 Self::DelayedSign(c) => Some(c.sequence()),
416 Self::TimelockSign(_) => None,
417 Self::DelayedTimelockSign(c) => Some(c.sequence()),
418 Self::HashDelaySign(c) => Some(c.sequence()),
419 Self::HashSign(_) => None,
420 }
421 }
422
423 pub fn control_block<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> ControlBlock {
425 match self {
426 Self::DelayedSign(c) => c.control_block(vtxo),
427 Self::TimelockSign(c) => c.control_block(vtxo),
428 Self::DelayedTimelockSign(c) => c.control_block(vtxo),
429 Self::HashDelaySign(c) => c.control_block(vtxo),
430 Self::HashSign(c) => c.control_block(vtxo),
431 }
432 }
433
434 pub fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
436 match self {
437 Self::DelayedSign(c) => c.witness_size(vtxo),
438 Self::TimelockSign(c) => c.witness_size(vtxo),
439 Self::DelayedTimelockSign(c) => c.witness_size(vtxo),
440 Self::HashDelaySign(c) => c.witness_size(vtxo),
441 Self::HashSign(c) => c.witness_size(vtxo),
442 }
443 }
444}
445
446#[cfg(test)]
447mod tests {
448 use std::str::FromStr;
449
450 use bitcoin::taproot::TaprootSpendInfo;
451 use bitcoin::{Amount, OutPoint, Transaction, TxIn, TxOut, Txid, sighash};
452 use bitcoin::hashes::Hash;
453 use bitcoin::key::Keypair;
454 use bitcoin_ext::{TaprootSpendInfoExt, fee};
455
456 use crate::{SECP, musig};
457 use crate::test_util::verify_tx;
458
459 use super::*;
460
461 lazy_static! {
462 static ref USER_KEYPAIR: Keypair = Keypair::from_str("5255d132d6ec7d4fc2a41c8f0018bb14343489ddd0344025cc60c7aa2b3fda6a").unwrap();
463 static ref SERVER_KEYPAIR: Keypair = Keypair::from_str("1fb316e653eec61de11c6b794636d230379509389215df1ceb520b65313e5426").unwrap();
464 }
465
466 #[allow(unused)]
467 fn all_clause_tested(clause: VtxoClause) -> bool {
468 match clause {
470 VtxoClause::DelayedSign(_) => true,
471 VtxoClause::TimelockSign(_) => true,
472 VtxoClause::DelayedTimelockSign(_) => true,
473 VtxoClause::HashDelaySign(_) => true,
474 VtxoClause::HashSign(_) => true,
475 }
476 }
477
478 fn transaction() -> Transaction {
479 let address = bitcoin::Address::from_str("tb1q00h5delzqxl7xae8ufmsegghcl4jwfvdnd8530")
480 .unwrap().assume_checked();
481
482 Transaction {
483 version: bitcoin::transaction::Version(3),
484 lock_time: bitcoin::absolute::LockTime::ZERO,
485 input: vec![],
486 output: vec![TxOut {
487 script_pubkey: address.script_pubkey(),
488 value: Amount::from_sat(900_000),
489 }, fee::fee_anchor()]
490 }
491 }
492
493 fn taproot_material(clause_spk: ScriptBuf) -> (TaprootSpendInfo, ControlBlock) {
494 let user_pubkey = USER_KEYPAIR.public_key();
495 let server_pubkey = SERVER_KEYPAIR.public_key();
496
497 let combined_pk = musig::combine_keys([user_pubkey, server_pubkey])
498 .x_only_public_key().0;
499 let taproot = taproot::TaprootBuilder::new()
500 .add_leaf(0, clause_spk.clone()).unwrap()
501 .finalize(&SECP, combined_pk).unwrap();
502
503 let cb = taproot
504 .control_block(&(clause_spk.clone(), taproot::LeafVersion::TapScript))
505 .expect("script is in taproot");
506
507 (taproot, cb)
508 }
509
510 fn signature(tx: &Transaction, input: &TxOut, clause_spk: ScriptBuf) -> schnorr::Signature {
511 let leaf_hash = taproot::TapLeafHash::from_script(
512 &clause_spk,
513 taproot::LeafVersion::TapScript,
514 );
515
516 let mut shc = sighash::SighashCache::new(tx);
517 let sighash = shc.taproot_script_spend_signature_hash(
518 0, &sighash::Prevouts::All(&[input.clone()]), leaf_hash, sighash::TapSighashType::Default,
519 ).expect("all prevouts provided");
520
521 SECP.sign_schnorr(&sighash.into(), &*USER_KEYPAIR)
522 }
523
524 #[test]
525 fn test_delayed_sign_clause() {
526 let clause = DelayedSignClause {
527 pubkey: USER_KEYPAIR.public_key(),
528 block_delta: 100,
529 };
530
531 let (taproot, cb) = taproot_material(clause.tapscript());
533 let tx_in = TxOut {
534 script_pubkey: taproot.script_pubkey(),
535 value: Amount::from_sat(1_000_000),
536 };
537
538 let mut tx = transaction();
540 tx.input.push(TxIn {
541 previous_output: OutPoint::new(Txid::all_zeros(), 0),
542 script_sig: ScriptBuf::default(),
543 sequence: clause.sequence(),
544 witness: Witness::new(),
545 });
546
547 let signature = signature(&tx, &tx_in, clause.tapscript());
549 tx.input[0].witness = clause.witness(&signature, &cb);
550
551 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
553 }
554
555 #[test]
556 fn test_timelock_sign_clause() {
557 let clause = TimelockSignClause {
558 pubkey: USER_KEYPAIR.public_key(),
559 timelock_height: 100,
560 };
561
562 let (taproot, cb) = taproot_material(clause.tapscript());
564 let tx_in = TxOut {
565 script_pubkey: taproot.script_pubkey(),
566 value: Amount::from_sat(1_000_000),
567 };
568
569 let mut tx = transaction();
571 tx.lock_time = clause.locktime();
572 tx.input.push(TxIn {
573 previous_output: OutPoint::new(Txid::all_zeros(), 0),
574 script_sig: ScriptBuf::default(),
575 sequence: Sequence::ZERO,
576 witness: Witness::new(),
577 });
578
579 let signature = signature(&tx, &tx_in, clause.tapscript());
581 tx.input[0].witness = clause.witness(&signature, &cb);
582
583 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
585 }
586
587 #[test]
588 fn test_delayed_timelock_clause() {
589 let clause = DelayedTimelockSignClause {
590 pubkey: USER_KEYPAIR.public_key(),
591 timelock_height: 100,
592 block_delta: 24,
593 };
594
595 let (taproot, cb) = taproot_material(clause.tapscript());
597 let tx_in = TxOut {
598 script_pubkey: taproot.script_pubkey(),
599 value: Amount::from_sat(1_000_000),
600 };
601
602 let mut tx = transaction();
604 tx.lock_time = clause.locktime();
605 tx.input.push(TxIn {
606 previous_output: OutPoint::new(Txid::all_zeros(), 0),
607 script_sig: ScriptBuf::default(),
608 sequence: clause.sequence(),
609 witness: Witness::new(),
610 });
611
612 let signature = signature(&tx, &tx_in, clause.tapscript());
614 tx.input[0].witness = clause.witness(&signature, &cb);
615
616 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
618 }
619
620 #[test]
621 fn test_hash_delay_clause() {
622 let preimage = [0; 32];
623
624 let clause = HashDelaySignClause {
625 pubkey: USER_KEYPAIR.public_key(),
626 hash: sha256::Hash::hash(&preimage),
627 block_delta: 24,
628 };
629
630 let (taproot, cb) = taproot_material(clause.tapscript());
632 let tx_in = TxOut {
633 script_pubkey: taproot.script_pubkey(),
634 value: Amount::from_sat(1_000_000),
635 };
636
637 let mut tx = transaction();
639 tx.input.push(TxIn {
640 previous_output: OutPoint::new(Txid::all_zeros(), 0),
641 script_sig: ScriptBuf::default(),
642 sequence: clause.sequence(),
643 witness: Witness::new(),
644 });
645
646 let signature = signature(&tx, &tx_in, clause.tapscript());
648 tx.input[0].witness = clause.witness(&(signature, preimage), &cb);
649
650 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
652 }
653
654 #[test]
655 fn test_extract_preimage_from_witness() {
656 let preimage_bytes = [42u8; 32];
657 let payment_hash = sha256::Hash::hash(&preimage_bytes);
658
659 let clause = HashDelaySignClause {
660 pubkey: USER_KEYPAIR.public_key(),
661 hash: payment_hash,
662 block_delta: 24,
663 };
664
665 let (taproot, cb) = taproot_material(clause.tapscript());
667 let tx_in = TxOut {
668 script_pubkey: taproot.script_pubkey(),
669 value: Amount::from_sat(1_000_000),
670 };
671
672 let mut tx = transaction();
673 tx.input.push(TxIn {
674 previous_output: OutPoint::new(Txid::all_zeros(), 0),
675 script_sig: ScriptBuf::default(),
676 sequence: clause.sequence(),
677 witness: Witness::new(),
678 });
679
680 let sig = signature(&tx, &tx_in, clause.tapscript());
681 let witness = clause.witness(&(sig, preimage_bytes), &cb);
682
683 let extracted = HashDelaySignClause::extract_preimage_from_witness(
685 &witness,
686 payment_hash.into(),
687 );
688 assert!(extracted.is_some());
689 assert_eq!(extracted.unwrap().as_ref(), &preimage_bytes);
690
691 let wrong_hash = sha256::Hash::hash(&[0u8; 32]);
693 let extracted = HashDelaySignClause::extract_preimage_from_witness(
694 &witness,
695 wrong_hash.into(),
696 );
697 assert!(extracted.is_none());
698
699 let short_witness = Witness::from_slice(&[&sig[..], &preimage_bytes[..]]);
701 let extracted = HashDelaySignClause::extract_preimage_from_witness(
702 &short_witness,
703 payment_hash.into(),
704 );
705 assert!(extracted.is_none());
706 }
707
708 #[test]
709 fn test_hash_sign_clause() {
710 let preimage = [0u8; 32];
711 let hash = sha256::Hash::hash(&preimage);
712
713 let agg_pk = musig::combine_keys([USER_KEYPAIR.public_key(), SERVER_KEYPAIR.public_key()]);
715
716 let clause = HashSignClause {
717 pubkey: agg_pk,
718 hash,
719 };
720
721 let (taproot, cb) = taproot_material(clause.tapscript());
723 let tx_in = TxOut {
724 script_pubkey: taproot.script_pubkey(),
725 value: Amount::from_sat(1_000_000),
726 };
727
728 let mut tx = transaction();
730 tx.input.push(TxIn {
731 previous_output: OutPoint::new(Txid::all_zeros(), 0),
732 script_sig: ScriptBuf::default(),
733 sequence: Sequence::ZERO, witness: Witness::new(),
735 });
736
737 let leaf_hash = taproot::TapLeafHash::from_script(
739 &clause.tapscript(),
740 taproot::LeafVersion::TapScript,
741 );
742
743 let mut shc = sighash::SighashCache::new(&tx);
744 let sighash = shc.taproot_script_spend_signature_hash(
745 0, &sighash::Prevouts::All(&[tx_in.clone()]), leaf_hash, sighash::TapSighashType::Default,
746 ).expect("all prevouts provided");
747
748 let (user_sec_nonce, user_pub_nonce) = musig::nonce_pair(&*USER_KEYPAIR);
750 let (server_pub_nonce, server_part_sig) = musig::deterministic_partial_sign(
751 &*SERVER_KEYPAIR,
752 [USER_KEYPAIR.public_key()],
753 &[&user_pub_nonce],
754 sighash.to_byte_array(),
755 None,
756 );
757 let agg_nonce = musig::nonce_agg(&[&user_pub_nonce, &server_pub_nonce]);
758
759 let (_user_part_sig, final_sig) = musig::partial_sign(
760 [USER_KEYPAIR.public_key(), SERVER_KEYPAIR.public_key()],
761 agg_nonce,
762 &*USER_KEYPAIR,
763 user_sec_nonce,
764 sighash.to_byte_array(),
765 None,
766 Some(&[&server_part_sig]),
767 );
768 let final_sig = final_sig.expect("should have final signature");
769
770 tx.input[0].witness = clause.witness(&(final_sig, preimage), &cb);
771
772 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
774 }
775}