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	///
37	/// Implementations sum bounded components and so cannot overflow `usize`
38	/// on any supported platform:
39	///   tapscript_size: <= MAX_STANDARD_TAPSCRIPT_SIZE (10_000 bytes)
40	///   cb_size: <= TAPROOT_CONTROL_MAX_SIZE (33 + 32*128 = 4_129 bytes)
41	///   VarInt sizes: <= 9 bytes each
42	///   constants: <= 1 + 1 + 64 (+ 1 + 32 for hash variants)
43	/// Sum is on the order of ~14 KB, well below u32::MAX, so the
44	/// usize addition cannot overflow even when usize is 32 bits.
45	fn witness_size<G, P: Policy>(&self, vtxo: &Vtxo<G, P>) -> usize;
46
47	/// Constructs the witness for the clause.
48	fn witness(
49		&self,
50		data: &Self::WitnessData,
51		control_block: &ControlBlock,
52	) -> Witness;
53}
54
55/// A clause that allows to sign and spend the UTXO after a relative
56/// timelock.
57#[derive(Debug, Clone)]
58pub struct DelayedSignClause {
59	pub pubkey: PublicKey,
60	pub block_delta: BlockDelta,
61}
62
63impl DelayedSignClause {
64	/// Returns the input sequence value for this clause.
65	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	// See `TapScriptClause::witness_size` for the overflow analysis.
91	#[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 // byte for the number of witness elements
97		+ 1  // schnorr signature size byte
98		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
99		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
100		+ tapscript_size // tapscript bytes
101		+ VarInt::from(cb_size).size()  // control block size bytes
102		+ cb_size // control block bytes
103	}
104}
105
106impl Into<VtxoClause> for DelayedSignClause {
107	fn into(self) -> VtxoClause {
108		VtxoClause::DelayedSign(self)
109	}
110}
111
112/// A clause that allows to sign and spend the UTXO after an absolute
113/// timelock.
114#[derive(Debug, Clone)]
115pub struct TimelockSignClause {
116	pub pubkey: PublicKey,
117	pub timelock_height: BlockHeight,
118}
119
120impl TimelockSignClause {
121	/// Returns the absolute locktime for this clause.
122	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	// See `TapScriptClause::witness_size` for the overflow analysis.
147	#[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 // byte for the number of witness elements
153		+ 1  // schnorr signature size byte
154		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
155		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
156		+ tapscript_size // tapscript bytes
157		+ VarInt::from(cb_size).size()  // control block size bytes
158		+ cb_size // control block bytes
159	}
160}
161
162impl Into<VtxoClause> for TimelockSignClause {
163	fn into(self) -> VtxoClause {
164		VtxoClause::TimelockSign(self)
165	}
166}
167
168/// A clause that allows to sign and spend the UTXO after a relative
169/// timelock, with an additional absolute one.
170#[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	/// Returns the input sequence for this clause.
179	pub fn sequence(&self) -> Sequence {
180		Sequence::from_height(self.block_delta)
181	}
182
183	/// Returns the absolute locktime for this clause.
184	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	// See `TapScriptClause::witness_size` for the overflow analysis.
213	#[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 // byte for the number of witness elements
219		+ 1  // schnorr signature size byte
220		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
221		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
222		+ tapscript_size // tapscript bytes
223		+ VarInt::from(cb_size).size()  // control block size bytes
224		+ cb_size // control block bytes
225	}
226}
227
228impl Into<VtxoClause> for DelayedTimelockSignClause {
229	fn into(self) -> VtxoClause {
230		VtxoClause::DelayedTimelockSign(self)
231	}
232}
233
234/// A clause that allows to sign and spend the UTXO after a relative
235/// timelock, if preimage matching the hash is provided.
236#[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	/// Returns the input sequence for this clause.
245	pub fn sequence(&self) -> Sequence {
246		Sequence::from_height(self.block_delta)
247	}
248
249	/// Try to extract the preimage from a witness that spends this clause.
250	///
251	/// Our own clauses build the witness `[signature, preimage, tapscript,
252	/// control_block]`. Bitcoin accepts more than that one shape for the same spend.
253	/// BIP341 permits an optional annex as the final witness item, and script
254	/// execution removes the annex before the tapscript runs. So `[signature,
255	/// preimage, tapscript, control_block, annex]` satisfies the same clause, and
256	/// consensus accepts it.
257	///
258	/// A 32-byte item that hashes to the payment hash is the preimage, whatever its
259	/// position. The witness is already mined, so the preimage is public either way.
260	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	// See `TapScriptClause::witness_size` for the overflow analysis.
296	#[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 // byte for the number of witness elements
302		+ 1  // schnorr signature size byte
303		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
304		+ 1  // preimage size byte
305		+ 32 // preimage bytes
306		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
307		+ tapscript_size // tapscript bytes
308		+ VarInt::from(cb_size).size()  // control block size bytes
309		+ cb_size // control block bytes
310	}
311}
312
313impl Into<VtxoClause> for HashDelaySignClause {
314	fn into(self) -> VtxoClause {
315		VtxoClause::HashDelaySign(self)
316	}
317}
318
319/// A clause that allows to sign and spend the UTXO after a relative
320/// timelock, if preimage matching the hash is provided.
321#[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	/// Returns the input sequence for this clause.
331	pub fn sequence(&self) -> Sequence {
332		Sequence::from_height(self.block_delta)
333	}
334
335	/// Try to extract the preimage from a witness that spends this clause.
336	///
337	/// Our own clauses build the witness `[signature, preimage, tapscript,
338	/// control_block]`. Bitcoin accepts more than that one shape for the same spend.
339	/// BIP341 permits an optional annex as the final witness item, and script
340	/// execution removes the annex before the tapscript runs. So `[signature,
341	/// preimage, tapscript, control_block, annex]` satisfies the same clause, and
342	/// consensus accepts it.
343	///
344	/// A 32-byte item that hashes to the payment hash is the preimage, whatever its
345	/// position. The witness is already mined, so the preimage is public either way.
346	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	// See `TapScriptClause::witness_size` for the overflow analysis.
382	#[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 // byte for the number of witness elements
388		+ 1  // schnorr signature size byte
389		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
390		+ 1  // preimage size byte
391		+ 32 // preimage bytes
392		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
393		+ tapscript_size // tapscript bytes
394		+ VarInt::from(cb_size).size()  // control block size bytes
395		+ cb_size // control block bytes
396	}
397}
398
399impl Into<VtxoClause> for HashDelaySignClause_v0 {
400	fn into(self) -> VtxoClause {
401		VtxoClause::HashDelaySign_v0(self)
402	}
403}
404
405/// A clause that allows spending by revealing a preimage and providing a signature.
406///
407/// This is used for the unlock clause in hArk leaf outputs, where the aggregate
408/// pubkey of user+server must sign, and a preimage must be revealed.
409#[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	// See `TapScriptClause::witness_size` for the overflow analysis.
437	#[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 // byte for the number of witness elements
443		+ 1  // schnorr signature size byte
444		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
445		+ 1  // preimage size byte
446		+ 32 // preimage bytes
447		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
448		+ tapscript_size // tapscript bytes
449		+ VarInt::from(cb_size).size()  // control block size bytes
450		+ cb_size // control block bytes
451	}
452}
453
454impl Into<VtxoClause> for HashSignClause {
455	fn into(self) -> VtxoClause {
456		VtxoClause::HashSign(self)
457	}
458}
459
460/// A clause that allows spending by revealing a preimage and providing a signature.
461///
462/// This is used for the unlock clause in hArk leaf outputs, where the aggregate
463/// pubkey of user+server must sign, and a preimage must be revealed.
464#[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	// See `TapScriptClause::witness_size` for the overflow analysis.
493	#[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 // byte for the number of witness elements
501		+ 1  // schnorr signature size byte
502		+ SCHNORR_SIGNATURE_SIZE // schnorr sig bytes
503		+ 1  // preimage size byte
504		+ 32 // preimage bytes
505		+ VarInt::from(tapscript_size).size()  // tapscript size bytes
506		+ tapscript_size // tapscript bytes
507		+ VarInt::from(cb_size).size()  // control block size bytes
508		+ cb_size // control block bytes
509	}
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	/// Returns the public key associated with this clause.
533	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	/// Returns the tapscript for this clause.
547	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	/// Returns the input sequence for this clause, if applicable.
560	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	/// Computes the total witness size in bytes for spending the VTXO via this clause.
573	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	/// Computes the total witness size in bytes for spending the VTXO via this clause.
586	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		// NB: matcher to ensure all clauses are tested
622		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		// We compute taproot material for the clause
687		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		// We build transaction spending input containing clause
694		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		// We compute the signature for the transaction
703		let signature = signature(&tx, &tx_in, clause.tapscript());
704		tx.input[0].witness = clause.witness(&signature, &cb);
705
706		// We verify the transaction
707		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		// We compute taproot material for the clause
718		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		// We build transaction spending input containing clause
725		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		// We compute the signature for the transaction
735		let signature = signature(&tx, &tx_in, clause.tapscript());
736		tx.input[0].witness = clause.witness(&signature, &cb);
737
738		// We verify the transaction
739		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		// We compute taproot material for the clause
751		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		// We build transaction spending input containing clause
758		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		// We compute the signature for the transaction
768		let signature = signature(&tx, &tx_in, clause.tapscript());
769		tx.input[0].witness = clause.witness(&signature, &cb);
770
771		// We verify the transaction
772		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		// We compute taproot material for the clause
786		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		// We build transaction spending input containing clause
793		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		// We compute the signature for the transaction
802		let signature = signature(&tx, &tx_in, clause.tapscript());
803		tx.input[0].witness = clause.witness(&(signature, preimage), &cb);
804
805		// We verify the transaction
806		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		// Build a valid witness via the clause
821		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		// Extract should succeed with correct payment hash
839		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		// Extract should fail with wrong payment hash
847		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		// Extract should fail on a witness that reveals no matching preimage
855		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	/// Build a script-path spend of a hash-delay tapscript that carries a BIP341
870	/// annex, and return its witness.
871	///
872	/// Panics if consensus rejects the spend. A caller therefore always asserts
873	/// against a witness that a miner can confirm.
874	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		// A final witness item that starts with 0x50 is the annex. The sighash
894		// commits to the annex, but script execution removes it before the
895		// tapscript runs. The stack the tapscript reads is unchanged.
896		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		// The annex makes this spend nonstandard to relay, but not invalid.
923		// Consensus accepts it, so a miner can confirm a spend that a parser
924		// which expects a four-item witness does not recognize.
925		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		// HashSignClause uses an x-only aggregate public key
970		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		// We compute taproot material for the clause
978		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		// We build transaction spending input containing clause
985		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, // HashSignClause has no relative timelock
990			witness: Witness::new(),
991		});
992
993		// For HashSignClause, we need a MuSig signature from both parties
994		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		// Create MuSig signature
1005		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		// We verify the transaction
1029		verify_tx(&[tx_in], 0, &tx).expect("transaction is invalid");
1030	}
1031}