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;
37
38 fn witness(
40 &self,
41 data: &Self::WitnessData,
42 control_block: &ControlBlock,
43 ) -> Witness;
44}
45
46#[derive(Debug, Clone)]
49pub struct DelayedSignClause {
50 pub pubkey: PublicKey,
51 pub block_delta: BlockDelta,
52}
53
54impl DelayedSignClause {
55 pub fn sequence(&self) -> Sequence {
57 Sequence::from_height(self.block_delta)
58 }
59}
60
61impl TapScriptClause for DelayedSignClause {
62 type WitnessData = schnorr::Signature;
63
64 fn tapscript(&self) -> ScriptBuf {
65 scripts::delayed_sign(self.block_delta, self.pubkey.x_only_public_key().0)
66 }
67
68 fn witness(
69 &self,
70 signature: &Self::WitnessData,
71 control_block: &ControlBlock,
72 ) -> Witness {
73 Witness::from_slice(&[
74 &signature[..],
75 self.tapscript().as_bytes(),
76 &control_block.serialize()[..],
77 ])
78 }
79
80
81 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
82 let cb_size = self.control_block(vtxo).size();
83 let tapscript_size = self.tapscript().as_bytes().len();
84
85 1 + 1 + SCHNORR_SIGNATURE_SIZE + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
93}
94
95impl Into<VtxoClause> for DelayedSignClause {
96 fn into(self) -> VtxoClause {
97 VtxoClause::DelayedSign(self)
98 }
99}
100
101#[derive(Debug, Clone)]
104pub struct TimelockSignClause {
105 pub pubkey: PublicKey,
106 pub timelock_height: BlockHeight,
107}
108
109impl TimelockSignClause {
110 pub fn locktime(&self) -> LockTime {
112 LockTime::from_height(self.timelock_height).expect("timelock height is valid")
113 }
114}
115
116impl TapScriptClause for TimelockSignClause {
117 type WitnessData = schnorr::Signature;
118
119 fn tapscript(&self) -> ScriptBuf {
120 scripts::timelock_sign(self.timelock_height, self.pubkey.x_only_public_key().0)
121 }
122
123 fn witness(
124 &self,
125 signature: &Self::WitnessData,
126 control_block: &ControlBlock,
127 ) -> Witness {
128 Witness::from_slice(&[
129 &signature[..],
130 self.tapscript().as_bytes(),
131 &control_block.serialize()[..],
132 ])
133 }
134
135 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
136 let cb_size = self.control_block(vtxo).size();
137 let tapscript_size = self.tapscript().as_bytes().len();
138
139 1 + 1 + SCHNORR_SIGNATURE_SIZE + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
147}
148
149impl Into<VtxoClause> for TimelockSignClause {
150 fn into(self) -> VtxoClause {
151 VtxoClause::TimelockSign(self)
152 }
153}
154
155#[derive(Debug, Clone)]
158pub struct DelayedTimelockSignClause {
159 pub pubkey: PublicKey,
160 pub timelock_height: BlockHeight,
161 pub block_delta: BlockDelta,
162}
163
164impl DelayedTimelockSignClause {
165 pub fn sequence(&self) -> Sequence {
167 Sequence::from_height(self.block_delta)
168 }
169
170 pub fn locktime(&self) -> LockTime {
172 LockTime::from_height(self.timelock_height).expect("timelock height is valid")
173 }
174}
175
176impl TapScriptClause for DelayedTimelockSignClause {
177 type WitnessData = schnorr::Signature;
178
179 fn tapscript(&self) -> ScriptBuf {
180 scripts::delay_timelock_sign(
181 self.block_delta,
182 self.timelock_height,
183 self.pubkey.x_only_public_key().0,
184 )
185 }
186
187 fn witness(
188 &self,
189 signature: &Self::WitnessData,
190 control_block: &ControlBlock,
191 ) -> Witness {
192 Witness::from_slice(&[
193 &signature[..],
194 self.tapscript().as_bytes(),
195 &control_block.serialize()[..],
196 ])
197 }
198
199 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
200 let cb_size = self.control_block(vtxo).size();
201 let tapscript_size = self.tapscript().as_bytes().len();
202
203 1 + 1 + SCHNORR_SIGNATURE_SIZE + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
211}
212
213impl Into<VtxoClause> for DelayedTimelockSignClause {
214 fn into(self) -> VtxoClause {
215 VtxoClause::DelayedTimelockSign(self)
216 }
217}
218
219#[derive(Debug, Clone)]
222pub struct HashDelaySignClause {
223 pub pubkey: PublicKey,
224 pub hash: sha256::Hash,
225 pub block_delta: BlockDelta,
226}
227
228impl HashDelaySignClause {
229 pub fn sequence(&self) -> Sequence {
231 Sequence::from_height(self.block_delta)
232 }
233
234 pub fn extract_preimage_from_witness(
239 witness: &Witness,
240 payment_hash: PaymentHash,
241 ) -> Option<Preimage> {
242 if witness.len() != 4 {
243 return None;
244 }
245
246 let bytes = witness.nth(1)?;
247 let bytes: [u8; 32] = bytes.try_into().ok()?;
248
249 let preimage = Preimage::from(bytes);
250 if preimage.compute_payment_hash() != payment_hash {
251 return None;
252 }
253
254 Some(preimage)
255 }
256}
257
258impl TapScriptClause for HashDelaySignClause {
259 type WitnessData = (schnorr::Signature, [u8; 32]);
260
261 fn tapscript(&self) -> ScriptBuf {
262 scripts::hash_delay_sign(
263 self.hash,
264 self.block_delta,
265 self.pubkey.x_only_public_key().0,
266 )
267 }
268
269 fn witness(
270 &self,
271 data: &Self::WitnessData,
272 control_block: &ControlBlock,
273 ) -> Witness {
274 let (signature, preimage) = data;
275 Witness::from_slice(&[
276 &signature[..],
277 &preimage[..],
278 self.tapscript().as_bytes(),
279 &control_block.serialize()[..],
280 ])
281 }
282
283 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
284 let cb_size = self.control_block(vtxo).size();
285 let tapscript_size = self.tapscript().as_bytes().len();
286
287 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
297}
298
299impl Into<VtxoClause> for HashDelaySignClause {
300 fn into(self) -> VtxoClause {
301 VtxoClause::HashDelaySign(self)
302 }
303}
304
305#[derive(Debug, Clone)]
310pub struct HashSignClause {
311 pub pubkey: PublicKey,
312 pub hash: sha256::Hash,
313}
314
315impl TapScriptClause for HashSignClause {
316 type WitnessData = (schnorr::Signature, [u8; 32]);
317
318 fn tapscript(&self) -> ScriptBuf {
319 scripts::hash_and_sign(self.hash, self.pubkey.x_only_public_key().0)
320 }
321
322 fn witness(
323 &self,
324 data: &Self::WitnessData,
325 control_block: &ControlBlock,
326 ) -> Witness {
327 let (signature, preimage) = data;
328 Witness::from_slice(&[
329 &signature[..],
330 &preimage[..],
331 self.tapscript().as_bytes(),
332 &control_block.serialize()[..],
333 ])
334 }
335
336 fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
337 let cb_size = self.control_block(vtxo).size();
338 let tapscript_size = 57;
339
340 debug_assert_eq!(tapscript_size, self.tapscript().as_bytes().len());
341
342 1 + 1 + SCHNORR_SIGNATURE_SIZE + 1 + 32 + VarInt::from(tapscript_size).size() + tapscript_size + VarInt::from(cb_size).size() + cb_size }
352}
353
354impl Into<VtxoClause> for HashSignClause {
355 fn into(self) -> VtxoClause {
356 VtxoClause::HashSign(self)
357 }
358}
359
360#[derive(Debug, Clone)]
361pub enum VtxoClause {
362 DelayedSign(DelayedSignClause),
363 TimelockSign(TimelockSignClause),
364 DelayedTimelockSign(DelayedTimelockSignClause),
365 HashDelaySign(HashDelaySignClause),
366 HashSign(HashSignClause),
367}
368
369impl VtxoClause {
370 pub fn pubkey(&self) -> PublicKey {
372 match self {
373 Self::DelayedSign(c) => c.pubkey,
374 Self::TimelockSign(c) => c.pubkey,
375 Self::DelayedTimelockSign(c) => c.pubkey,
376 Self::HashDelaySign(c) => c.pubkey,
377 Self::HashSign(c) => c.pubkey,
378 }
379 }
380
381
382 pub fn tapscript(&self) -> ScriptBuf {
384 match self {
385 Self::DelayedSign(c) => c.tapscript(),
386 Self::TimelockSign(c) => c.tapscript(),
387 Self::DelayedTimelockSign(c) => c.tapscript(),
388 Self::HashDelaySign(c) => c.tapscript(),
389 Self::HashSign(c) => c.tapscript(),
390 }
391 }
392
393 pub fn sequence(&self) -> Option<Sequence> {
395 match self {
396 Self::DelayedSign(c) => Some(c.sequence()),
397 Self::TimelockSign(_) => None,
398 Self::DelayedTimelockSign(c) => Some(c.sequence()),
399 Self::HashDelaySign(c) => Some(c.sequence()),
400 Self::HashSign(_) => None,
401 }
402 }
403
404 pub fn control_block<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> ControlBlock {
406 match self {
407 Self::DelayedSign(c) => c.control_block(vtxo),
408 Self::TimelockSign(c) => c.control_block(vtxo),
409 Self::DelayedTimelockSign(c) => c.control_block(vtxo),
410 Self::HashDelaySign(c) => c.control_block(vtxo),
411 Self::HashSign(c) => c.control_block(vtxo),
412 }
413 }
414
415 pub fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize {
417 match self {
418 Self::DelayedSign(c) => c.witness_size(vtxo),
419 Self::TimelockSign(c) => c.witness_size(vtxo),
420 Self::DelayedTimelockSign(c) => c.witness_size(vtxo),
421 Self::HashDelaySign(c) => c.witness_size(vtxo),
422 Self::HashSign(c) => c.witness_size(vtxo),
423 }
424 }
425}
426
427#[cfg(test)]
428mod tests {
429 use std::str::FromStr;
430
431 use bitcoin::taproot::TaprootSpendInfo;
432 use bitcoin::{Amount, OutPoint, Transaction, TxIn, TxOut, Txid, sighash};
433 use bitcoin::hashes::Hash;
434 use bitcoin::key::Keypair;
435 use bitcoin_ext::{TaprootSpendInfoExt, fee};
436
437 use crate::{SECP, musig};
438 use crate::test_util::verify_tx;
439
440 use super::*;
441
442 lazy_static! {
443 static ref USER_KEYPAIR: Keypair = Keypair::from_str("5255d132d6ec7d4fc2a41c8f0018bb14343489ddd0344025cc60c7aa2b3fda6a").unwrap();
444 static ref SERVER_KEYPAIR: Keypair = Keypair::from_str("1fb316e653eec61de11c6b794636d230379509389215df1ceb520b65313e5426").unwrap();
445 }
446
447 #[allow(unused)]
448 fn all_clause_tested(clause: VtxoClause) -> bool {
449 match clause {
451 VtxoClause::DelayedSign(_) => true,
452 VtxoClause::TimelockSign(_) => true,
453 VtxoClause::DelayedTimelockSign(_) => true,
454 VtxoClause::HashDelaySign(_) => true,
455 VtxoClause::HashSign(_) => true,
456 }
457 }
458
459 fn transaction() -> Transaction {
460 let address = bitcoin::Address::from_str("tb1q00h5delzqxl7xae8ufmsegghcl4jwfvdnd8530")
461 .unwrap().assume_checked();
462
463 Transaction {
464 version: bitcoin::transaction::Version(3),
465 lock_time: bitcoin::absolute::LockTime::ZERO,
466 input: vec![],
467 output: vec![TxOut {
468 script_pubkey: address.script_pubkey(),
469 value: Amount::from_sat(900_000),
470 }, fee::fee_anchor()]
471 }
472 }
473
474 fn taproot_material(clause_spk: ScriptBuf) -> (TaprootSpendInfo, ControlBlock) {
475 let user_pubkey = USER_KEYPAIR.public_key();
476 let server_pubkey = SERVER_KEYPAIR.public_key();
477
478 let combined_pk = musig::combine_keys([user_pubkey, server_pubkey])
479 .x_only_public_key().0;
480 let taproot = taproot::TaprootBuilder::new()
481 .add_leaf(0, clause_spk.clone()).unwrap()
482 .finalize(&SECP, combined_pk).unwrap();
483
484 let cb = taproot
485 .control_block(&(clause_spk.clone(), taproot::LeafVersion::TapScript))
486 .expect("script is in taproot");
487
488 (taproot, cb)
489 }
490
491 fn signature(tx: &Transaction, input: &TxOut, clause_spk: ScriptBuf) -> schnorr::Signature {
492 let leaf_hash = taproot::TapLeafHash::from_script(
493 &clause_spk,
494 taproot::LeafVersion::TapScript,
495 );
496
497 let mut shc = sighash::SighashCache::new(tx);
498 let sighash = shc.taproot_script_spend_signature_hash(
499 0, &sighash::Prevouts::All(&[input.clone()]), leaf_hash, sighash::TapSighashType::Default,
500 ).expect("all prevouts provided");
501
502 SECP.sign_schnorr(&sighash.into(), &*USER_KEYPAIR)
503 }
504
505 #[test]
506 fn test_delayed_sign_clause() {
507 let clause = DelayedSignClause {
508 pubkey: USER_KEYPAIR.public_key(),
509 block_delta: 100,
510 };
511
512 let (taproot, cb) = taproot_material(clause.tapscript());
514 let tx_in = TxOut {
515 script_pubkey: taproot.script_pubkey(),
516 value: Amount::from_sat(1_000_000),
517 };
518
519 let mut tx = transaction();
521 tx.input.push(TxIn {
522 previous_output: OutPoint::new(Txid::all_zeros(), 0),
523 script_sig: ScriptBuf::default(),
524 sequence: clause.sequence(),
525 witness: Witness::new(),
526 });
527
528 let signature = signature(&tx, &tx_in, clause.tapscript());
530 tx.input[0].witness = clause.witness(&signature, &cb);
531
532 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
534 }
535
536 #[test]
537 fn test_timelock_sign_clause() {
538 let clause = TimelockSignClause {
539 pubkey: USER_KEYPAIR.public_key(),
540 timelock_height: 100,
541 };
542
543 let (taproot, cb) = taproot_material(clause.tapscript());
545 let tx_in = TxOut {
546 script_pubkey: taproot.script_pubkey(),
547 value: Amount::from_sat(1_000_000),
548 };
549
550 let mut tx = transaction();
552 tx.lock_time = clause.locktime();
553 tx.input.push(TxIn {
554 previous_output: OutPoint::new(Txid::all_zeros(), 0),
555 script_sig: ScriptBuf::default(),
556 sequence: Sequence::ZERO,
557 witness: Witness::new(),
558 });
559
560 let signature = signature(&tx, &tx_in, clause.tapscript());
562 tx.input[0].witness = clause.witness(&signature, &cb);
563
564 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
566 }
567
568 #[test]
569 fn test_delayed_timelock_clause() {
570 let clause = DelayedTimelockSignClause {
571 pubkey: USER_KEYPAIR.public_key(),
572 timelock_height: 100,
573 block_delta: 24,
574 };
575
576 let (taproot, cb) = taproot_material(clause.tapscript());
578 let tx_in = TxOut {
579 script_pubkey: taproot.script_pubkey(),
580 value: Amount::from_sat(1_000_000),
581 };
582
583 let mut tx = transaction();
585 tx.lock_time = clause.locktime();
586 tx.input.push(TxIn {
587 previous_output: OutPoint::new(Txid::all_zeros(), 0),
588 script_sig: ScriptBuf::default(),
589 sequence: clause.sequence(),
590 witness: Witness::new(),
591 });
592
593 let signature = signature(&tx, &tx_in, clause.tapscript());
595 tx.input[0].witness = clause.witness(&signature, &cb);
596
597 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
599 }
600
601 #[test]
602 fn test_hash_delay_clause() {
603 let preimage = [0; 32];
604
605 let clause = HashDelaySignClause {
606 pubkey: USER_KEYPAIR.public_key(),
607 hash: sha256::Hash::hash(&preimage),
608 block_delta: 24,
609 };
610
611 let (taproot, cb) = taproot_material(clause.tapscript());
613 let tx_in = TxOut {
614 script_pubkey: taproot.script_pubkey(),
615 value: Amount::from_sat(1_000_000),
616 };
617
618 let mut tx = transaction();
620 tx.input.push(TxIn {
621 previous_output: OutPoint::new(Txid::all_zeros(), 0),
622 script_sig: ScriptBuf::default(),
623 sequence: clause.sequence(),
624 witness: Witness::new(),
625 });
626
627 let signature = signature(&tx, &tx_in, clause.tapscript());
629 tx.input[0].witness = clause.witness(&(signature, preimage), &cb);
630
631 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
633 }
634
635 #[test]
636 fn test_extract_preimage_from_witness() {
637 let preimage_bytes = [42u8; 32];
638 let payment_hash = sha256::Hash::hash(&preimage_bytes);
639
640 let clause = HashDelaySignClause {
641 pubkey: USER_KEYPAIR.public_key(),
642 hash: payment_hash,
643 block_delta: 24,
644 };
645
646 let (taproot, cb) = taproot_material(clause.tapscript());
648 let tx_in = TxOut {
649 script_pubkey: taproot.script_pubkey(),
650 value: Amount::from_sat(1_000_000),
651 };
652
653 let mut tx = transaction();
654 tx.input.push(TxIn {
655 previous_output: OutPoint::new(Txid::all_zeros(), 0),
656 script_sig: ScriptBuf::default(),
657 sequence: clause.sequence(),
658 witness: Witness::new(),
659 });
660
661 let sig = signature(&tx, &tx_in, clause.tapscript());
662 let witness = clause.witness(&(sig, preimage_bytes), &cb);
663
664 let extracted = HashDelaySignClause::extract_preimage_from_witness(
666 &witness,
667 payment_hash.into(),
668 );
669 assert!(extracted.is_some());
670 assert_eq!(extracted.unwrap().as_ref(), &preimage_bytes);
671
672 let wrong_hash = sha256::Hash::hash(&[0u8; 32]);
674 let extracted = HashDelaySignClause::extract_preimage_from_witness(
675 &witness,
676 wrong_hash.into(),
677 );
678 assert!(extracted.is_none());
679
680 let short_witness = Witness::from_slice(&[&sig[..], &preimage_bytes[..]]);
682 let extracted = HashDelaySignClause::extract_preimage_from_witness(
683 &short_witness,
684 payment_hash.into(),
685 );
686 assert!(extracted.is_none());
687 }
688
689 #[test]
690 fn test_hash_sign_clause() {
691 let preimage = [0u8; 32];
692 let hash = sha256::Hash::hash(&preimage);
693
694 let agg_pk = musig::combine_keys([USER_KEYPAIR.public_key(), SERVER_KEYPAIR.public_key()]);
696
697 let clause = HashSignClause {
698 pubkey: agg_pk,
699 hash,
700 };
701
702 let (taproot, cb) = taproot_material(clause.tapscript());
704 let tx_in = TxOut {
705 script_pubkey: taproot.script_pubkey(),
706 value: Amount::from_sat(1_000_000),
707 };
708
709 let mut tx = transaction();
711 tx.input.push(TxIn {
712 previous_output: OutPoint::new(Txid::all_zeros(), 0),
713 script_sig: ScriptBuf::default(),
714 sequence: Sequence::ZERO, witness: Witness::new(),
716 });
717
718 let leaf_hash = taproot::TapLeafHash::from_script(
720 &clause.tapscript(),
721 taproot::LeafVersion::TapScript,
722 );
723
724 let mut shc = sighash::SighashCache::new(&tx);
725 let sighash = shc.taproot_script_spend_signature_hash(
726 0, &sighash::Prevouts::All(&[tx_in.clone()]), leaf_hash, sighash::TapSighashType::Default,
727 ).expect("all prevouts provided");
728
729 let (user_sec_nonce, user_pub_nonce) = musig::nonce_pair(&*USER_KEYPAIR);
731 let (server_pub_nonce, server_part_sig) = musig::deterministic_partial_sign(
732 &*SERVER_KEYPAIR,
733 [USER_KEYPAIR.public_key()],
734 &[&user_pub_nonce],
735 sighash.to_byte_array(),
736 None,
737 );
738 let agg_nonce = musig::nonce_agg(&[&user_pub_nonce, &server_pub_nonce]);
739
740 let (_user_part_sig, final_sig) = musig::partial_sign(
741 [USER_KEYPAIR.public_key(), SERVER_KEYPAIR.public_key()],
742 agg_nonce,
743 &*USER_KEYPAIR,
744 user_sec_nonce,
745 sighash.to_byte_array(),
746 None,
747 Some(&[&server_part_sig]),
748 );
749 let final_sig = final_sig.expect("should have final signature");
750
751 tx.input[0].witness = clause.witness(&(final_sig, preimage), &cb);
752
753 verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
755 }
756}