Skip to main content

ark/vtxo/policy/
clause.rs

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
17/// A trait describing a VTXO policy clause.
18///
19/// It can be used when creating the VTXO, specifying the script pubkey,
20/// and check the satisfaction weight when spending it.
21pub trait TapScriptClause: Sized + Clone {
22	/// The type of witness data required to sign the clause.
23	type WitnessData;
24
25	/// Returns the tapscript for the clause.
26	fn tapscript(&self) -> ScriptBuf;
27
28	/// Construct the taproot control block for spending the VTXO using this clause
29	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	/// Computes the total witness size in bytes for spending via this clause.
36	fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize;
37
38	/// Constructs the witness for the clause.
39	fn witness(
40		&self,
41		data: &Self::WitnessData,
42		control_block: &ControlBlock,
43	) -> Witness;
44}
45
46/// A clause that allows to sign and spend the UTXO after a relative
47/// timelock.
48#[derive(Debug, Clone)]
49pub struct DelayedSignClause {
50	pub pubkey: PublicKey,
51	pub block_delta: BlockDelta,
52}
53
54impl DelayedSignClause {
55	/// Returns the input sequence value for this clause.
56	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 // byte for the number of witness elements
86		+ 1  // schnorr signature size byte
87		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
88		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
89		+ tapscript_size // tapscript bytes
90		+ VarInt::from(cb_size).size()  // control block size bytes
91		+ cb_size // control block bytes
92	}
93}
94
95impl Into<VtxoClause> for DelayedSignClause {
96	fn into(self) -> VtxoClause {
97		VtxoClause::DelayedSign(self)
98	}
99}
100
101/// A clause that allows to sign and spend the UTXO after an absolute
102/// timelock.
103#[derive(Debug, Clone)]
104pub struct TimelockSignClause {
105	pub pubkey: PublicKey,
106	pub timelock_height: BlockHeight,
107}
108
109impl TimelockSignClause {
110	/// Returns the absolute locktime for this clause.
111	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 // byte for the number of witness elements
140		+ 1  // schnorr signature size byte
141		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
142		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
143		+ tapscript_size // tapscript bytes
144		+ VarInt::from(cb_size).size()  // control block size bytes
145		+ cb_size // control block bytes
146	}
147}
148
149impl Into<VtxoClause> for TimelockSignClause {
150	fn into(self) -> VtxoClause {
151		VtxoClause::TimelockSign(self)
152	}
153}
154
155/// A clause that allows to sign and spend the UTXO after a relative
156/// timelock, with an additional absolute one.
157#[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	/// Returns the input sequence for this clause.
166	pub fn sequence(&self) -> Sequence {
167		Sequence::from_height(self.block_delta)
168	}
169
170	/// Returns the absolute locktime for this clause.
171	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 // byte for the number of witness elements
204		+ 1  // schnorr signature size byte
205		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
206		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
207		+ tapscript_size // tapscript bytes
208		+ VarInt::from(cb_size).size()  // control block size bytes
209		+ cb_size // control block bytes
210	}
211}
212
213impl Into<VtxoClause> for DelayedTimelockSignClause {
214	fn into(self) -> VtxoClause {
215		VtxoClause::DelayedTimelockSign(self)
216	}
217}
218
219/// A clause that allows to sign and spend the UTXO after a relative
220/// timelock, if preimage matching the hash is provided.
221#[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	/// Returns the input sequence for this clause.
230	pub fn sequence(&self) -> Sequence {
231		Sequence::from_height(self.block_delta)
232	}
233
234	/// Try to extract the preimage from a witness that spends this clause.
235	///
236	/// Witness layout: `[signature, preimage, tapscript, control_block]`.
237	/// Returns the preimage if it is 32 bytes and hashes to the given payment hash.
238	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 // byte for the number of witness elements
288		+ 1  // schnorr signature size byte
289		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
290		+ 1  // preimage size byte
291		+ 32 // preimage bytes
292		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
293		+ tapscript_size // tapscript bytes
294		+ VarInt::from(cb_size).size()  // control block size bytes
295		+ cb_size // control block bytes
296	}
297}
298
299impl Into<VtxoClause> for HashDelaySignClause {
300	fn into(self) -> VtxoClause {
301		VtxoClause::HashDelaySign(self)
302	}
303}
304
305/// A clause that allows spending by revealing a preimage and providing a signature.
306///
307/// This is used for the unlock clause in hArk leaf outputs, where the aggregate
308/// pubkey of user+server must sign, and a preimage must be revealed.
309#[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 // byte for the number of witness elements
343		+ 1  // schnorr signature size byte
344		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
345		+ 1  // preimage size byte
346		+ 32 // preimage bytes
347		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
348		+ tapscript_size // tapscript bytes
349		+ VarInt::from(cb_size).size()  // control block size bytes
350		+ cb_size // control block bytes
351	}
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	/// Returns the public key associated with this clause.
371	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	/// Returns the tapscript for this clause.
383	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	/// Returns the input sequence for this clause, if applicable.
394	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	/// Computes the total witness size in bytes for spending the VTXO via this clause.
405	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	/// Computes the total witness size in bytes for spending the VTXO via this clause.
416	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		// NB: matcher to ensure all clauses are tested
450		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		// We compute taproot material for the clause
513		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		// We build transaction spending input containing clause
520		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		// We compute the signature for the transaction
529		let signature = signature(&tx, &tx_in, clause.tapscript());
530		tx.input[0].witness = clause.witness(&signature, &cb);
531
532		// We verify the transaction
533		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		// We compute taproot material for the clause
544		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		// We build transaction spending input containing clause
551		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		// We compute the signature for the transaction
561		let signature = signature(&tx, &tx_in, clause.tapscript());
562		tx.input[0].witness = clause.witness(&signature, &cb);
563
564		// We verify the transaction
565		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		// We compute taproot material for the clause
577		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		// We build transaction spending input containing clause
584		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		// We compute the signature for the transaction
594		let signature = signature(&tx, &tx_in, clause.tapscript());
595		tx.input[0].witness = clause.witness(&signature, &cb);
596
597		// We verify the transaction
598		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		// We compute taproot material for the clause
612		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		// We build transaction spending input containing clause
619		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		// We compute the signature for the transaction
628		let signature = signature(&tx, &tx_in, clause.tapscript());
629		tx.input[0].witness = clause.witness(&(signature, preimage), &cb);
630
631		// We verify the transaction
632		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		// Build a valid witness via the clause
647		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		// Extract should succeed with correct payment hash
665		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		// Extract should fail with wrong payment hash
673		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		// Extract should fail with wrong witness length
681		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		// HashSignClause uses an x-only aggregate public key
695		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		// We compute taproot material for the clause
703		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		// We build transaction spending input containing clause
710		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, // HashSignClause has no relative timelock
715			witness: Witness::new(),
716		});
717
718		// For HashSignClause, we need a MuSig signature from both parties
719		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		// Create MuSig signature
730		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		// We verify the transaction
754		verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
755	}
756}