Skip to main content

ark/tree/
signed.rs

1
2
3use std::{cmp, fmt, io, iter};
4use std::collections::{HashMap, VecDeque};
5
6use bitcoin::hashes::{sha256, Hash};
7use bitcoin::{
8	taproot, Amount, OutPoint, ScriptBuf, Sequence, TapLeafHash, Transaction, TxIn, TxOut, Txid, Weight, Witness
9};
10use bitcoin::secp256k1::{schnorr, Keypair, PublicKey, XOnlyPublicKey};
11use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType};
12use secp256k1_musig::musig::{AggregatedNonce, PartialSignature, PublicNonce, SecretNonce};
13
14use bitcoin_ext::{fee, BlockDelta, BlockHeight, TaprootSpendInfoExt, TransactionExt, TxOutExt};
15
16use crate::{musig, scripts, ServerVtxoPolicy, Vtxo, VtxoId, VtxoPolicy, VtxoRequest, SECP};
17use crate::encode::{
18	LengthPrefixedVector, OversizedVectorError, ProtocolDecodingError, ProtocolEncoding, ReadExt, WriteExt
19};
20use crate::error::IncorrectSigningKeyError;
21use crate::tree::{self, Tree};
22use crate::vtxo::{self, Full, GenesisItem, GenesisTransition, HarkLeafVtxoPolicy, MaybePreimage, ServerVtxo, TapScriptClause};
23use crate::vtxo::policy::{check_block_delta, check_block_height, HarkLeaf_v0_VtxoPolicy};
24use crate::vtxo::policy::clause::TimelockSignClause;
25
26
27/// Hash to lock hArk VTXOs from users before forfeits
28pub type UnlockHash = sha256::Hash;
29
30/// Preimage to unlock hArk VTXOs
31pub type UnlockPreimage = [u8; 32];
32
33/// The version of the hashlock clauses used in the leaves of a VTXO tree.
34///
35/// Trees created before the `PROTOCOL_VERSION_HASHLOCK_CLAUSES` protocol
36/// version used the v0 unlock scripts.
37///
38/// We forgot to properly encode the difference in the trees, so version
39/// used is detected at runtime and then stored inside the tree.
40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub enum HashlockVersion {
42	V0,
43	V1,
44}
45
46/// The upper bound witness weight to spend a node transaction.
47pub const NODE_SPEND_WEIGHT: Weight = Weight::from_wu(140);
48
49/// The expiry clause hidden in the node taproot as only script.
50pub fn expiry_clause(server_pubkey: PublicKey, expiry_height: BlockHeight) -> ScriptBuf {
51	TimelockSignClause { pubkey: server_pubkey, timelock_height: expiry_height }.tapscript()
52}
53
54/// The hash-based unlock clause that requires a signature and a preimage
55///
56/// It is used hidden in the leaf taproot as only script or used in the forfeit output.
57pub fn unlock_clause(pubkey: XOnlyPublicKey, unlock_hash: UnlockHash) -> ScriptBuf {
58	scripts::hash_and_sign(unlock_hash, pubkey)
59}
60
61/// The taproot of the leaf policy, i.e. of the output that is spent by the leaf tx
62///
63/// This output is guarded by user+server key and a hash preimage.
64///
65/// The internal key is set to the MuSig of user's VTXO key + server pubkey,
66/// but the keyspend clause is currently not used in the protocol.
67pub fn leaf_cosign_taproot(
68	user_pubkey: PublicKey,
69	server_pubkey: PublicKey,
70	expiry_height: BlockHeight,
71	unlock_hash: UnlockHash,
72) -> taproot::TaprootSpendInfo {
73	HarkLeafVtxoPolicy { user_pubkey, unlock_hash }.taproot(server_pubkey, expiry_height)
74}
75
76/// The hash-based unlock clause that requires a signature and a preimage
77///
78/// It is used hidden in the leaf taproot as only script or used in the forfeit output.
79pub fn unlock_clause_v0(pubkey: XOnlyPublicKey, unlock_hash: UnlockHash) -> ScriptBuf {
80	scripts::hash_and_sign_v0(unlock_hash, pubkey)
81}
82
83/// The taproot of the leaf policy, i.e. of the output that is spent by the leaf tx
84///
85/// This output is guarded by user+server key and a hash preimage.
86///
87/// The internal key is set to the MuSig of user's VTXO key + server pubkey,
88/// but the keyspend clause is currently not used in the protocol.
89pub fn leaf_cosign_taproot_v0(
90	user_pubkey: PublicKey,
91	server_pubkey: PublicKey,
92	expiry_height: BlockHeight,
93	unlock_hash: UnlockHash,
94) -> taproot::TaprootSpendInfo {
95	HarkLeaf_v0_VtxoPolicy { user_pubkey, unlock_hash }.taproot(server_pubkey, expiry_height)
96}
97
98/// The taproot spend info of an output that is spent by an internal node tx
99pub fn cosign_taproot(
100	agg_pk: XOnlyPublicKey,
101	server_pubkey: PublicKey,
102	expiry_height: BlockHeight,
103) -> taproot::TaprootSpendInfo {
104	taproot::TaprootBuilder::new()
105		.add_leaf(0, expiry_clause(server_pubkey, expiry_height)).unwrap()
106		.finalize(&SECP, agg_pk).unwrap()
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
110pub struct VtxoLeafSpec {
111	/// The actual VTXO request.
112	pub vtxo: VtxoRequest,
113
114	/// The public key used by the client to cosign the internal txs of the tree
115	///
116	/// Only interactive participants have a cosign key here.
117	///
118	/// The client SHOULD forget this key after signing the transaction tree.
119	/// Non-interactive participants don't have a cosign pubkey.
120	pub cosign_pubkey: Option<PublicKey>,
121
122	/// The unlock hash used to lock the VTXO before forfeits are signed
123	pub unlock_hash: UnlockHash,
124}
125
126impl ProtocolEncoding for VtxoLeafSpec {
127	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
128		self.vtxo.policy.encode(w)?;
129		w.emit_u64(self.vtxo.amount.to_sat())?;
130		self.cosign_pubkey.encode(w)?;
131		self.unlock_hash.encode(w)?;
132		Ok(())
133	}
134
135	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
136		Ok(VtxoLeafSpec {
137			vtxo: VtxoRequest {
138				policy: VtxoPolicy::decode(r)?,
139				amount: Amount::from_sat(r.read_u64()?),
140			},
141			cosign_pubkey: Option::<PublicKey>::decode(r)?,
142			unlock_hash: sha256::Hash::decode(r)?,
143		})
144	}
145}
146
147/// All the information that uniquely specifies a VTXO tree before it has been signed.
148#[derive(Debug, Clone, Eq, PartialEq)]
149pub struct VtxoTreeSpec {
150	pub vtxos: Vec<VtxoLeafSpec>,
151	pub expiry_height: BlockHeight,
152	pub server_pubkey: PublicKey,
153	pub exit_delta: BlockDelta,
154	pub global_cosign_pubkeys: Vec<PublicKey>,
155	/// The hashlock clause version used in the leaf outputs.
156	/// Detected at decoding time because we forgot to properly encode this info.
157	pub hashlock_version: HashlockVersion,
158}
159
160#[derive(Clone, Copy)]
161enum ChildSpec<'a> {
162	Leaf {
163		spec: &'a VtxoLeafSpec,
164	},
165	Internal {
166		output_value: Amount,
167		agg_pk: PublicKey,
168	},
169}
170
171impl VtxoTreeSpec {
172	pub fn new(
173		vtxos: Vec<VtxoLeafSpec>,
174		server_pubkey: PublicKey,
175		expiry_height: BlockHeight,
176		exit_delta: BlockDelta,
177		global_cosign_pubkeys: Vec<PublicKey>,
178	) -> VtxoTreeSpec {
179		assert_ne!(vtxos.len(), 0);
180		VtxoTreeSpec {
181			vtxos, server_pubkey, expiry_height, exit_delta, global_cosign_pubkeys,
182			hashlock_version: HashlockVersion::V1,
183		}
184	}
185
186	pub fn nb_leaves(&self) -> usize {
187		self.vtxos.len()
188	}
189
190	pub fn nb_nodes(&self) -> usize {
191		Tree::nb_nodes_for_leaves(self.nb_leaves())
192	}
193
194	pub fn nb_internal_nodes(&self) -> usize {
195		Tree::nb_nodes_for_leaves(self.nb_leaves()).checked_sub(self.nb_leaves())
196			.expect("tree can't have less nodes than leaves")
197	}
198
199	pub fn iter_vtxos(&self) -> impl Iterator<Item = &VtxoLeafSpec> {
200		self.vtxos.iter()
201	}
202
203	/// Get the leaf index of the given leaf spec.
204	pub fn leaf_idx_of(&self, leaf_spec: &VtxoLeafSpec) -> Option<usize> {
205		self.vtxos.iter().position(|e| e == leaf_spec)
206	}
207
208	/// Get the leaf index of the given vtxo request.
209	///
210	/// Note that in the case of duplicate vtxo requests, this function can
211	/// return any of the indices of these requests.
212	pub fn leaf_idx_of_req(&self, vtxo_request: &VtxoRequest) -> Option<usize> {
213		self.vtxos.iter().position(|e| e.vtxo == *vtxo_request)
214	}
215
216	/// Calculate the total value needed in the tree.
217	///
218	/// This accounts for
219	/// - all vtxos getting their value
220	pub fn total_required_value(&self) -> Amount {
221		self.vtxos.iter().map(|d| d.vtxo.amount).sum::<Amount>()
222	}
223
224	/// Calculate the taproot spend info for a leaf node
225	pub fn leaf_taproot(
226		&self,
227		user_pubkey: PublicKey,
228		unlock_hash: UnlockHash,
229	) -> taproot::TaprootSpendInfo {
230		match self.hashlock_version {
231			HashlockVersion::V1 => leaf_cosign_taproot(
232				user_pubkey, self.server_pubkey, self.expiry_height, unlock_hash,
233			),
234			HashlockVersion::V0 => leaf_cosign_taproot_v0(
235				user_pubkey, self.server_pubkey, self.expiry_height, unlock_hash,
236			),
237		}
238	}
239
240	/// Calculate the taproot spend info for internal nodes
241	pub fn internal_taproot(&self, agg_pk: XOnlyPublicKey) -> taproot::TaprootSpendInfo {
242		cosign_taproot(agg_pk, self.server_pubkey, self.expiry_height)
243	}
244
245	/// The cosign pubkey used on the vtxo output of the tx funding the tree
246	///
247	/// In Ark rounds this will be the round funding tx scriptPubkey.
248	pub fn funding_tx_cosign_pubkey(&self) -> XOnlyPublicKey {
249		let keys = self.vtxos.iter()
250			.filter_map(|v| v.cosign_pubkey)
251			.chain(self.global_cosign_pubkeys.iter().copied());
252		musig::combine_keys(keys).x_only_public_key().0
253	}
254
255	/// The scriptPubkey used on the vtxo output of the tx funding the tree
256	///
257	/// In Ark rounds this will be the round funding tx scriptPubkey.
258	pub fn funding_tx_script_pubkey(&self) -> ScriptBuf {
259		let agg_pk = self.funding_tx_cosign_pubkey();
260		self.internal_taproot(agg_pk).script_pubkey()
261	}
262
263	/// The output of the tx funding the tree
264	///
265	/// In Ark rounds this will be the round funding tx output.
266	pub fn funding_tx_txout(&self) -> TxOut {
267		TxOut {
268			script_pubkey: self.funding_tx_script_pubkey(),
269			value: self.total_required_value(),
270		}
271	}
272
273	/// Create a node tx
274	///
275	/// The children are an iterator over the next tx, its cosign pubkey
276	/// and the unlock hash if the child is a leaf.
277	fn node_tx<'a>(
278		&self,
279		children: impl Iterator<Item = ChildSpec<'a>>,
280	) -> Transaction {
281		Transaction {
282			version: bitcoin::transaction::Version(3),
283			lock_time: bitcoin::absolute::LockTime::ZERO,
284			input: vec![TxIn {
285				previous_output: OutPoint::null(), // we will fill this later
286				sequence: Sequence::ZERO,
287				script_sig: ScriptBuf::new(),
288				witness: Witness::new(),
289			}],
290			output: children.map(|child| match child {
291				ChildSpec::Leaf { spec } => {
292					let taproot = self.leaf_taproot(
293						spec.vtxo.policy.user_pubkey(),
294						spec.unlock_hash,
295					);
296					TxOut {
297						script_pubkey: taproot.script_pubkey(),
298						value: spec.vtxo.amount,
299					}
300				},
301				ChildSpec::Internal { output_value, agg_pk } => {
302					let taproot = self.internal_taproot(agg_pk.x_only_public_key().0);
303					TxOut {
304						script_pubkey: taproot.script_pubkey(),
305						value: output_value,
306					}
307				},
308			}).chain(Some(fee::fee_anchor())).collect(),
309		}
310	}
311
312	fn leaf_tx(&self, vtxo: &VtxoRequest) -> Transaction {
313		let txout = TxOut {
314			value: vtxo.amount,
315			script_pubkey: vtxo.policy.script_pubkey(self.server_pubkey, self.exit_delta, self.expiry_height),
316		};
317
318		// We collect fees in rounds by the difference in value between the inputs and outputs which
319		// is enforced by the round payment validation code. Therefore, we can leave fees set to
320		// zero for the leaf tx.
321		vtxo::create_exit_tx(OutPoint::null(), txout, None, Amount::ZERO)
322	}
323
324	/// Calculate all the aggregate cosign pubkeys by aggregating the leaf and server pubkeys.
325	///
326	/// Pubkeys expected and returned ordered from leaves to root.
327	pub fn cosign_agg_pks(&self)
328		-> impl Iterator<Item = PublicKey> + iter::DoubleEndedIterator + iter::ExactSizeIterator + '_
329	{
330		Tree::new(self.nb_leaves()).into_iter().map(|node| {
331			if node.is_leaf() {
332				musig::combine_keys([
333					self.vtxos[node.idx()].vtxo.policy.user_pubkey(),
334					self.server_pubkey,
335				])
336			} else {
337				musig::combine_keys(
338					node.leaves().filter_map(|i| self.vtxos[i].cosign_pubkey)
339						.chain(self.global_cosign_pubkeys.iter().copied())
340				)
341			}
342		})
343	}
344
345	/// Return unsigned transactions for all nodes from leaves to root.
346	pub fn unsigned_transactions(&self, utxo: OutPoint) -> Vec<Transaction> {
347		let tree = Tree::new(self.nb_leaves());
348
349		let cosign_agg_pks = self.cosign_agg_pks().collect::<Vec<_>>();
350
351		let mut txs = Vec::<Transaction>::with_capacity(tree.nb_nodes());
352		for node in tree.iter() {
353			let tx = if node.is_leaf() {
354				self.leaf_tx(&self.vtxos[node.idx()].vtxo).clone()
355			} else {
356				let mut buf = [None; tree::RADIX];
357				for (idx, child) in node.children().enumerate() {
358					let child = if let Some(spec) = self.vtxos.get(child) {
359						ChildSpec::Leaf { spec }
360					} else {
361						ChildSpec::Internal {
362							output_value: txs[child].output_value(),
363							agg_pk: cosign_agg_pks[child],
364						}
365					};
366					buf[idx] = Some(child);
367				}
368				self.node_tx(buf.iter().filter_map(|x| *x))
369			};
370			txs.push(tx.clone());
371		};
372
373		// set the prevouts
374		txs.last_mut().unwrap().input[0].previous_output = utxo;
375		for node in tree.iter().rev() {
376			let txid = txs[node.idx()].compute_txid();
377			for (i, child) in node.children().enumerate() {
378				let point = OutPoint::new(txid, u32::try_from(i).expect("tree child index fits in u32"));
379				txs[child].input[0].previous_output = point;
380			}
381		}
382
383		txs
384	}
385
386	/// Return all final transactions for all nodes from leaves to root
387	///
388	/// Internal transactions are signed, leaf txs not.
389	pub fn final_transactions(
390		&self,
391		utxo: OutPoint,
392		internal_signatures: &[schnorr::Signature],
393	) -> Vec<Transaction> {
394		let mut txs = self.unsigned_transactions(utxo);
395		for (tx, sig) in txs.iter_mut().skip(self.nb_leaves()).zip(internal_signatures) {
396			tx.input[0].witness.push(&sig[..]);
397		}
398		txs
399	}
400
401	/// Calculate all the aggregate cosign nonces by aggregating the leaf and server nonces.
402	///
403	/// Nonces expected and returned for all internal nodes ordered from leaves to root.
404	pub fn calculate_cosign_agg_nonces(
405		&self,
406		leaf_cosign_nonces: &HashMap<PublicKey, Vec<PublicNonce>>,
407		global_signer_cosign_nonces: &[impl AsRef<[PublicNonce]>],
408	) -> Result<Vec<AggregatedNonce>, String> {
409		if global_signer_cosign_nonces.len() != self.global_cosign_pubkeys.len() {
410			return Err("missing global signer nonces".into());
411		}
412
413		Tree::new(self.nb_leaves()).iter_internal().enumerate().map(|(idx, node)| {
414			let mut nonces = Vec::new();
415			for pk in node.leaves().filter_map(|i| self.vtxos[i].cosign_pubkey) {
416				nonces.push(leaf_cosign_nonces.get(&pk)
417					.ok_or_else(|| format!("missing nonces for leaf pk {}", pk))?
418					// note that we skip some nonces for some leaves that are at the edges
419					// and skip some levels
420					.get(node.internal_level())
421					.ok_or_else(|| format!("not enough nonces for leaf_pk {}", pk))?
422				);
423			}
424			for glob in global_signer_cosign_nonces {
425				nonces.push(glob.as_ref().get(idx).ok_or("not enough global cosign nonces")?);
426			}
427			Ok(musig::nonce_agg(&nonces))
428		}).collect()
429	}
430
431	/// Convert this spec into an unsigned tree by providing the
432	/// root outpoint and the nodes' aggregate nonces.
433	///
434	/// Nonces expected ordered from leaves to root.
435	pub fn into_unsigned_tree(
436		self,
437		utxo: OutPoint,
438	) -> UnsignedVtxoTree {
439		UnsignedVtxoTree::new(self, utxo)
440	}
441}
442
443/// A VTXO tree ready to be signed.
444///
445/// This type contains various cached values required to sign the tree.
446#[derive(Debug, Clone)]
447pub struct UnsignedVtxoTree {
448	pub spec: VtxoTreeSpec,
449	pub utxo: OutPoint,
450
451	// the following fields are calculated from the above
452
453	/// Aggregate pubkeys for the inputs to all nodes, leaves to root.
454	pub cosign_agg_pks: Vec<PublicKey>,
455	/// Transactions for all nodes, leaves to root.
456	pub txs: Vec<Transaction>,
457	/// Sighashes for the only input of the tx for all internal nodes,
458	/// leaves to root.
459	pub internal_sighashes: Vec<TapSighash>,
460
461	tree: Tree,
462}
463
464impl UnsignedVtxoTree {
465	pub fn new(
466		spec: VtxoTreeSpec,
467		utxo: OutPoint,
468	) -> UnsignedVtxoTree {
469		let tree = Tree::new(spec.nb_leaves());
470
471		let cosign_agg_pks = spec.cosign_agg_pks().collect::<Vec<_>>();
472		let txs = spec.unsigned_transactions(utxo);
473
474		let root_txout = spec.funding_tx_txout();
475		let internal_sighashes = tree.iter_internal().map(|node| {
476			let prev = if let Some((parent, sibling_idx))
477				= tree.parent_idx_of_with_sibling_idx(node.idx())
478			{
479				assert!(!node.is_root());
480				&txs[parent].output[sibling_idx]
481			} else {
482				assert!(node.is_root());
483				&root_txout
484			};
485
486			let mut shc = SighashCache::new(&txs[node.idx()]);
487			shc.taproot_key_spend_signature_hash(
488				0, // input idx is always 0
489				&sighash::Prevouts::All(&[prev]),
490				TapSighashType::Default,
491			).expect("sighash error")
492		}).collect();
493
494		UnsignedVtxoTree { spec, utxo, txs, internal_sighashes, cosign_agg_pks, tree }
495	}
496
497	pub fn nb_leaves(&self) -> usize {
498		self.tree.nb_leaves()
499	}
500
501	/// The number of leaves that have a cosign pubkey
502	pub fn nb_cosigned_leaves(&self) -> usize {
503		self.spec.vtxos.iter()
504			.filter(|v| v.cosign_pubkey.is_some())
505			.count()
506	}
507
508	pub fn nb_nodes(&self) -> usize {
509		self.tree.nb_nodes()
510	}
511
512	pub fn nb_internal_nodes(&self) -> usize {
513		self.tree.nb_internal_nodes()
514	}
515
516	/// Generate partial musig signatures for the nodes in the tree branch of the given
517	/// vtxo request.
518	///
519	/// Note that the signatures are indexed by their place in the tree and thus do not
520	/// necessarily match up with the indices in the secret nonces vector.
521	///
522	/// Aggregate nonces expected for all nodes, ordered from leaves to root.
523	/// Secret nonces expected for branch, ordered from leaf to root.
524	///
525	/// Returns [None] if the vtxo request is not part of the tree.
526	/// Returned signatures over the branch from leaf to root.
527	//TODO(stevenroose) streamline indices of nonces and sigs
528	pub fn cosign_branch(
529		&self,
530		cosign_agg_nonces: &[AggregatedNonce],
531		leaf_idx: usize,
532		cosign_key: &Keypair,
533		cosign_sec_nonces: Vec<SecretNonce>,
534	) -> Result<Vec<PartialSignature>, IncorrectSigningKeyError> {
535		let req = self.spec.vtxos.get(leaf_idx).expect("leaf idx out of bounds");
536		if Some(cosign_key.public_key()) != req.cosign_pubkey {
537			return Err(IncorrectSigningKeyError {
538				required: req.cosign_pubkey,
539				provided: cosign_key.public_key(),
540			});
541		}
542
543		let mut nonce_iter = cosign_sec_nonces.into_iter().enumerate();
544		let mut ret = Vec::with_capacity(self.tree.root().level().saturating_add(1));
545		// skip the leaf
546		for node in self.tree.iter_branch(leaf_idx).skip(1) {
547			// Since we can skip a level, we sometimes have to skip a nonce.
548			// NB We can't just use the index into the sec_nonces vector, because
549			// musig requires us to use the owned SecNonce type to prevent footgun
550			// by reusing secret nonces.
551			let sec_nonce = loop {
552				let next = nonce_iter.next().expect("level overflow");
553				if next.0 == node.internal_level() {
554					break next.1;
555				}
556			};
557
558			let cosign_pubkeys = node.leaves()
559				.filter_map(|i| self.spec.vtxos[i].cosign_pubkey)
560				.chain(self.spec.global_cosign_pubkeys.iter().copied());
561			let sighash = self.internal_sighashes[node.internal_idx()];
562
563			let agg_pk = self.cosign_agg_pks[node.idx()].x_only_public_key().0;
564			let tweak = self.spec.internal_taproot(agg_pk).tap_tweak().to_byte_array();
565			let sig = musig::partial_sign(
566				cosign_pubkeys,
567				cosign_agg_nonces[node.internal_idx()],
568				&cosign_key,
569				sec_nonce,
570				sighash.to_byte_array(),
571				Some(tweak),
572				None,
573			).0;
574			ret.push(sig);
575		}
576
577		Ok(ret)
578	}
579
580	/// Generate partial musig signatures for all internal nodes in the tree.
581	///
582	/// Nonces expected for all internal nodes, ordered from leaves to root.
583	///
584	/// Returns [None] if the vtxo request is not part of the tree.
585	pub fn cosign_tree(
586		&self,
587		cosign_agg_nonces: &[AggregatedNonce],
588		keypair: &Keypair,
589		cosign_sec_nonces: Vec<SecretNonce>,
590	) -> Vec<PartialSignature> {
591		debug_assert_eq!(cosign_agg_nonces.len(), self.nb_internal_nodes());
592		debug_assert_eq!(cosign_sec_nonces.len(), self.nb_internal_nodes());
593
594		let nonces = cosign_sec_nonces.into_iter().zip(cosign_agg_nonces);
595		self.tree.iter_internal().zip(nonces).map(|(node, (sec_nonce, agg_nonce))| {
596			let sighash = self.internal_sighashes[node.internal_idx()];
597
598			let cosign_pubkeys = node.leaves()
599				.filter_map(|i| self.spec.vtxos[i].cosign_pubkey)
600				.chain(self.spec.global_cosign_pubkeys.iter().copied());
601			let agg_pk = self.cosign_agg_pks[node.idx()];
602			debug_assert_eq!(agg_pk, musig::combine_keys(cosign_pubkeys.clone()));
603			let taproot = self.spec.internal_taproot(agg_pk.x_only_public_key().0);
604			musig::partial_sign(
605				cosign_pubkeys,
606				*agg_nonce,
607				&keypair,
608				sec_nonce,
609				sighash.to_byte_array(),
610				Some(taproot.tap_tweak().to_byte_array()),
611				None,
612			).0
613		}).collect()
614	}
615
616	/// Verify partial cosign signature of a single internal node
617	fn verify_internal_node_cosign_partial_sig(
618		&self,
619		node: &tree::Node,
620		pk: PublicKey,
621		agg_nonces: &[AggregatedNonce],
622		part_sig: PartialSignature,
623		pub_nonce: PublicNonce,
624	) -> Result<(), CosignSignatureError> {
625		debug_assert!(!node.is_leaf());
626
627		let sighash = self.internal_sighashes[node.internal_idx()];
628
629		let key_agg = {
630			let cosign_pubkeys = node.leaves()
631				.filter_map(|i| self.spec.vtxos[i].cosign_pubkey)
632				.chain(self.spec.global_cosign_pubkeys.iter().copied());
633			let agg_pk = self.cosign_agg_pks[node.idx()].x_only_public_key().0;
634			let taproot = self.spec.internal_taproot(agg_pk);
635			let taptweak = taproot.tap_tweak().to_byte_array();
636			musig::tweaked_key_agg(cosign_pubkeys, taptweak).0
637		};
638		let agg_nonce = agg_nonces.get(node.internal_idx())
639			.ok_or(CosignSignatureError::NotEnoughNonces)?;
640		let session = musig::Session::new(&key_agg, *agg_nonce, &sighash.to_byte_array());
641		let ok = session.partial_verify(&key_agg, &part_sig, &pub_nonce, musig::pubkey_to(pk));
642		if !ok {
643			return Err(CosignSignatureError::invalid_sig(pk));
644		}
645		Ok(())
646	}
647
648	/// Verify the partial cosign signatures from one of the leaves.
649	///
650	/// Nonces and partial signatures expected for all internal nodes,
651	/// ordered from leaves to root.
652	pub fn verify_branch_cosign_partial_sigs(
653		&self,
654		cosign_agg_nonces: &[AggregatedNonce],
655		request: &VtxoLeafSpec,
656		cosign_pub_nonces: &[PublicNonce],
657		cosign_part_sigs: &[PartialSignature],
658	) -> Result<(), String> {
659		assert_eq!(cosign_agg_nonces.len(), self.nb_internal_nodes());
660
661		let cosign_pubkey = request.cosign_pubkey.ok_or("no cosign pubkey for request")?;
662		let leaf_idx = self.spec.leaf_idx_of(request).ok_or("request not in tree")?;
663
664		// skip the leaf of the branch we verify
665		let internal_branch = self.tree.iter_branch(leaf_idx).skip(1);
666
667		// quickly check if the number of sigs is sane
668		match internal_branch.clone().count().cmp(&cosign_part_sigs.len()) {
669			cmp::Ordering::Less => return Err("too few partial signatures".into()),
670			cmp::Ordering::Greater => return Err("too many partial signatures".into()),
671			cmp::Ordering::Equal => {},
672		}
673
674		let mut part_sigs_iter = cosign_part_sigs.iter();
675		let mut pub_nonce_iter = cosign_pub_nonces.iter().enumerate();
676		for node in internal_branch {
677			let pub_nonce = loop {
678				let next = pub_nonce_iter.next().ok_or("not enough pub nonces")?;
679				if next.0 == node.internal_level() {
680					break next.1;
681				}
682			};
683			self.verify_internal_node_cosign_partial_sig(
684				node,
685				cosign_pubkey,
686				cosign_agg_nonces,
687				part_sigs_iter.next().ok_or("not enough sigs")?.clone(),
688				*pub_nonce,
689			).map_err(|e| format!("part sig verification failed: {}", e))?;
690		}
691
692		Ok(())
693	}
694
695	/// Verify the partial cosign signatures for all nodes.
696	///
697	/// Nonces and partial signatures expected for all internal nodes,
698	/// ordered from leaves to root.
699	pub fn verify_global_cosign_partial_sigs(
700		&self,
701		pk: PublicKey,
702		agg_nonces: &[AggregatedNonce],
703		pub_nonces: &[PublicNonce],
704		part_sigs: &[PartialSignature],
705	) -> Result<(), CosignSignatureError> {
706		for node in self.tree.iter_internal() {
707			let sigs = *part_sigs.get(node.internal_idx())
708				.ok_or_else(|| CosignSignatureError::missing_sig(pk))?;
709			let nonces = *pub_nonces.get(node.internal_idx())
710				.ok_or_else(|| CosignSignatureError::NotEnoughNonces)?;
711			self.verify_internal_node_cosign_partial_sig(node, pk, agg_nonces, sigs, nonces)?;
712		}
713
714		Ok(())
715	}
716
717	/// Combine all partial cosign signatures.
718	///
719	/// Nonces expected for all internal nodes, ordered from leaves to root.
720	///
721	/// Branch signatures expected for internal nodes in branch ordered from leaf to root.
722	///
723	/// Server signatures expected for all internal nodes ordered from leaves to root,
724	/// in the same order as `global_cosign_pubkeys`.
725	pub fn combine_partial_signatures(
726		&self,
727		cosign_agg_nonces: &[AggregatedNonce],
728		branch_part_sigs: &HashMap<PublicKey, Vec<PartialSignature>>,
729		global_signer_part_sigs: &[impl AsRef<[PartialSignature]>],
730	) -> Result<Vec<schnorr::Signature>, CosignSignatureError> {
731		// to ease implementation, we're reconstructing the part sigs map with dequeues
732		let mut leaf_part_sigs = branch_part_sigs.iter()
733			.map(|(pk, sigs)| (pk, sigs.iter().collect()))
734			.collect::<HashMap<_, VecDeque<_>>>();
735
736		if global_signer_part_sigs.len() != self.spec.global_cosign_pubkeys.len() {
737			return Err(CosignSignatureError::Invalid(
738				"invalid nb of global cosigner partial signatures",
739			));
740		}
741		for (pk, sigs) in self.spec.global_cosign_pubkeys.iter().zip(global_signer_part_sigs) {
742			if sigs.as_ref().len() != self.nb_internal_nodes() {
743				// NB if the called didn't order part sigs identically as global_cosign_pubkeys,
744				// this pubkey indication is actually wrong..
745				return Err(CosignSignatureError::MissingSignature { pk: *pk });
746			}
747		}
748
749		let max_level = match self.tree.root().is_leaf() {
750			true => 0,
751			false => self.tree.root().internal_level(),
752		};
753		self.tree.iter_internal().map(|node| {
754			let mut cosign_pks = Vec::with_capacity(max_level.saturating_add(1));
755			let mut part_sigs = Vec::with_capacity(max_level.saturating_add(1));
756			for leaf in node.leaves() {
757				if let Some(cosign_pk) = self.spec.vtxos[leaf].cosign_pubkey {
758					let part_sig = leaf_part_sigs.get_mut(&cosign_pk)
759						.ok_or(CosignSignatureError::missing_sig(cosign_pk))?
760						.pop_front()
761						.ok_or(CosignSignatureError::missing_sig(cosign_pk))?;
762					cosign_pks.push(cosign_pk);
763					part_sigs.push(part_sig);
764				}
765			}
766			// add global signers
767			cosign_pks.extend(&self.spec.global_cosign_pubkeys);
768			for sigs in global_signer_part_sigs {
769				part_sigs.push(sigs.as_ref().get(node.internal_idx()).expect("checked before"));
770			}
771
772			let agg_pk = self.cosign_agg_pks[node.idx()].x_only_public_key().0;
773			let taproot = self.spec.internal_taproot(agg_pk);
774			let agg_nonce = *cosign_agg_nonces.get(node.internal_idx())
775				.ok_or(CosignSignatureError::NotEnoughNonces)?;
776			let sighash = self.internal_sighashes[node.internal_idx()].to_byte_array();
777			let tweak = taproot.tap_tweak().to_byte_array();
778			Ok(musig::combine_partial_signatures(
779				cosign_pks, agg_nonce, sighash, Some(tweak), &part_sigs,
780			))
781		}).collect()
782	}
783
784	/// Verify the signatures of all the internal node txs.
785	///
786	/// Signatures expected for all internal nodes, ordered from leaves to root.
787	pub fn verify_cosign_sigs(
788		&self,
789		signatures: &[schnorr::Signature],
790	) -> Result<(), XOnlyPublicKey> {
791		for node in self.tree.iter_internal() {
792			let sighash = self.internal_sighashes[node.internal_idx()];
793			let agg_pk = &self.cosign_agg_pks[node.idx()].x_only_public_key().0;
794			let pk = self.spec.internal_taproot(*agg_pk).output_key().to_x_only_public_key();
795			let sig = signatures.get(node.internal_idx()).ok_or_else(|| pk)?;
796			if SECP.verify_schnorr(sig, &sighash.into(), &pk).is_err() {
797				return Err(pk);
798			}
799		}
800		Ok(())
801	}
802
803	/// Convert into a [SignedVtxoTreeSpec] by providing the signatures.
804	///
805	/// Signatures expected for all internal nodes, ordered from leaves to root.
806	pub fn into_signed_tree(
807		self,
808		signatures: Vec<schnorr::Signature>,
809	) -> SignedVtxoTreeSpec {
810		SignedVtxoTreeSpec {
811			spec: self.spec,
812			utxo: self.utxo,
813			cosign_sigs: signatures,
814		}
815	}
816}
817
818/// Error returned from cosigning a VTXO tree.
819#[derive(PartialEq, Eq, thiserror::Error)]
820pub enum CosignSignatureError {
821	#[error("missing cosign signature from pubkey {pk}")]
822	MissingSignature { pk: PublicKey },
823	#[error("invalid cosign signature from pubkey {pk}")]
824	InvalidSignature { pk: PublicKey },
825	#[error("not enough nonces")]
826	NotEnoughNonces,
827	#[error("invalid cosign signatures: {0}")]
828	Invalid(&'static str),
829}
830
831impl fmt::Debug for CosignSignatureError {
832	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
833	    fmt::Display::fmt(self, f)
834	}
835}
836
837impl CosignSignatureError {
838	fn missing_sig(cosign_pk: PublicKey) -> CosignSignatureError {
839		CosignSignatureError::MissingSignature { pk: cosign_pk }
840	}
841	fn invalid_sig(cosign_pk: PublicKey) -> CosignSignatureError {
842		CosignSignatureError::InvalidSignature { pk: cosign_pk }
843	}
844}
845
846/// All the information needed to uniquely specify a fully signed VTXO tree.
847#[derive(Debug, Clone, PartialEq)]
848pub struct SignedVtxoTreeSpec {
849	pub spec: VtxoTreeSpec,
850	pub utxo: OutPoint,
851	/// The signatures for the internal txs, from leaves to root.
852	pub cosign_sigs: Vec<schnorr::Signature>,
853}
854
855impl SignedVtxoTreeSpec {
856	/// Signatures expected for internal nodes ordered from leaves to root.
857	pub fn new(
858		spec: VtxoTreeSpec,
859		utxo: OutPoint,
860		cosign_signatures: Vec<schnorr::Signature>,
861	) -> SignedVtxoTreeSpec {
862		SignedVtxoTreeSpec { spec, utxo, cosign_sigs: cosign_signatures }
863	}
864
865	pub fn nb_leaves(&self) -> usize {
866		self.spec.nb_leaves()
867	}
868
869	/// Construct the exit branch starting from the root ending in the leaf.
870	///
871	/// Panics if `leaf_idx` is out of range.
872	///
873	/// This call is quite inefficient and if you want to make repeated calls,
874	/// it is advised to use [CachedSignedVtxoTree::exit_branch] instead.
875	pub fn exit_branch(&self, leaf_idx: usize) -> Vec<Transaction> {
876		let txs = self.all_final_txs();
877		let tree = Tree::new(self.spec.nb_leaves());
878		let mut ret = tree.iter_branch(leaf_idx)
879			.map(|n| txs[n.idx()].clone())
880			.collect::<Vec<_>>();
881		ret.reverse();
882		ret
883	}
884
885	/// Get all final txs in this tree, starting with the leaves, towards the root
886	pub fn all_final_txs(&self) -> Vec<Transaction> {
887		self.spec.final_transactions(self.utxo, &self.cosign_sigs)
888	}
889
890	pub fn into_cached_tree(self) -> CachedSignedVtxoTree {
891		CachedSignedVtxoTree {
892			txs: self.all_final_txs(),
893			spec: self,
894		}
895	}
896
897	/// Detect the hashlock version this tree was signed with.
898	///
899	///	We forgot to properly encode this, so it detects it by looking at the
900	///	first signature and seeing which version it is valid for.
901	///
902	///	Falls back to v1 for empty trees, they shouldn't exist.
903	pub fn detect_hashlock_version(&self) -> Result<HashlockVersion, HashlockVersionDetectError> {
904		if self.spec.nb_leaves() == 1 {
905			return Ok(HashlockVersion::V1);
906		}
907		let sig = self.cosign_sigs.first().ok_or(HashlockVersionDetectError)?;
908
909		for version in [HashlockVersion::V1, HashlockVersion::V0] {
910			let mut spec = self.spec.clone();
911			spec.hashlock_version = version;
912			let unsigned = spec.into_unsigned_tree(self.utxo);
913			let sighash = unsigned.internal_sighashes[0];
914			let agg_pk = unsigned.cosign_agg_pks[unsigned.nb_leaves()].x_only_public_key().0;
915			let pk = unsigned.spec.internal_taproot(agg_pk).output_key().to_x_only_public_key();
916			if SECP.verify_schnorr(sig, &sighash.into(), &pk).is_ok() {
917				return Ok(version);
918			}
919		}
920		Err(HashlockVersionDetectError)
921	}
922
923	/// Return this tree with its hashlock version detected from the cosign
924	/// signatures.
925	///
926	/// Use this before rebuilding transactions or VTXOs from a stored tree
927	/// that may predate the v1 hashlock clauses; see
928	/// [Self::detect_hashlock_version].
929	pub fn with_detected_hashlock_version(mut self) -> Result<Self, HashlockVersionDetectError> {
930		self.spec.hashlock_version = self.detect_hashlock_version()?;
931		Ok(self)
932	}
933}
934
935/// The hashlock version of a tree couldn't be determined because its cosign
936/// signatures don't verify for any version. This means the tree is corrupt.
937#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
938#[error("tree cosign signatures don't verify for any hashlock version")]
939pub struct HashlockVersionDetectError;
940
941/// A fully signed VTXO tree, with all the transaction cached.
942///
943/// This is useful for cheap extraction of VTXO branches.
944pub struct CachedSignedVtxoTree {
945	pub spec: SignedVtxoTreeSpec,
946	/// All signed txs in this tree, starting with the leaves, towards the root.
947	pub txs: Vec<Transaction>,
948}
949
950impl CachedSignedVtxoTree {
951	/// Construct the exit branch starting from the root ending in the leaf.
952	///
953	/// Panics if `leaf_idx` is out of range.
954	pub fn exit_branch(&self, leaf_idx: usize) -> Vec<&Transaction> {
955		let tree = Tree::new(self.spec.spec.nb_leaves());
956		let mut ret = tree.iter_branch(leaf_idx)
957			.map(|n| &self.txs[n.idx()])
958			.collect::<Vec<_>>();
959		ret.reverse();
960		ret
961	}
962
963	pub fn nb_leaves(&self) -> usize {
964		self.spec.nb_leaves()
965	}
966
967	pub fn nb_nodes(&self) -> usize {
968		Tree::nb_nodes_for_leaves(self.spec.nb_leaves())
969	}
970
971	/// Get all final txs in this tree, starting with the leaves, towards the root.
972	///
973	/// The leaf transactions are unsigned and the node transactions are signed.
974	/// This is equivalent to `unsigned_leaf_txs` chained with `signed_node_txs`
975	pub fn all_final_txs(&self) -> &[Transaction] {
976		&self.txs
977	}
978
979	/// Returns all leaf transactions
980	///
981	/// These transactions aren't signed (yet)
982	pub fn unsigned_leaf_txs(&self) -> &[Transaction] {
983		&self.txs[..self.nb_leaves()]
984	}
985
986	/// Returns all internal node transactions
987	///
988	/// These transactions are fully signed
989	pub fn internal_node_txs(&self) -> &[Transaction] {
990		&self.txs[self.nb_leaves()..]
991	}
992
993	/// Build the genesis item for the given node tx and its output idx
994	fn build_genesis_item_at<'a>(&self, tree: &Tree, node_idx: usize, output_idx: u8) -> GenesisItem {
995		debug_assert_eq!(self.nb_leaves(), tree.nb_leaves(), "tree corresponds to self");
996		debug_assert!(node_idx < tree.nb_nodes(), "Node index is in tree");
997
998		let other_outputs = self.txs.get(node_idx).expect("Each node has a tx")
999			.output.iter().enumerate()
1000			.filter(|(i, _)| *i != output_idx as usize) // Exclude this output
1001			.filter(|(_, out)| !out.is_p2a_fee_anchor())    // Exclude the fee-anchor
1002			.map(|(_, out)| out)
1003			.cloned()
1004			.collect();
1005
1006		let node = tree.node_at(node_idx);
1007
1008		let transition = if node.is_leaf() {
1009			debug_assert_eq!(output_idx, 0, "Leafs have a single output");
1010			let req = self.spec.spec.vtxos.get(node_idx).expect("Every leaf has a spec");
1011			match self.spec.spec.hashlock_version {
1012				HashlockVersion::V1 => GenesisTransition::new_hash_locked_cosigned(
1013					req.vtxo.policy.user_pubkey(),
1014					None,
1015					MaybePreimage::Hash(req.unlock_hash),
1016				),
1017				HashlockVersion::V0 => GenesisTransition::new_hash_locked_cosigned_v0(
1018					req.vtxo.policy.user_pubkey(),
1019					None,
1020					MaybePreimage::Hash(req.unlock_hash),
1021				),
1022			}
1023		} else {
1024			let pubkeys = node.leaves()
1025				.filter_map(|i| self.spec.spec.vtxos[i].cosign_pubkey)
1026				.chain(self.spec.spec.global_cosign_pubkeys.iter().copied())
1027				.collect();
1028
1029			let sig = self.spec.cosign_sigs.get(node.internal_idx())
1030				.expect("enough sigs for all nodes");
1031
1032			GenesisTransition::new_cosigned(pubkeys, Some(*sig))
1033		};
1034
1035		let fee_amount = Amount::ZERO;
1036		GenesisItem {transition, output_idx, other_outputs, fee_amount }
1037	}
1038
1039	/// Construct the server vtxo at the given node index.
1040	///
1041	/// The index corresponds to the prevout of self.txs[index]
1042	///
1043	/// Panics if `node_idx` is out of range.
1044	fn build_internal_vtxo(&self, node_idx: usize) -> ServerVtxo<Full> {
1045		let tree = Tree::new(self.spec.spec.nb_leaves());
1046		assert!(node_idx < tree.nb_nodes(), "node_idx out of range");
1047
1048		let mut genesis = tree.iter_branch_with_output(node_idx)
1049			.map(|(idx, child_idx)| self.build_genesis_item_at(&tree, idx, u8::try_from(child_idx).expect("tree child index fits in u8")))
1050			.collect::<Vec<_>>();
1051		genesis.reverse();
1052
1053		let node = tree.node_at(node_idx);
1054		let spec = &self.spec.spec;
1055		let (point, amount) = match tree.parent_idx_of_with_sibling_idx(node_idx) {
1056			None => (self.spec.utxo, spec.total_required_value()),
1057			Some((parent_idx, child_idx)) => {
1058				let parent_tx = self.txs.get(parent_idx).expect("parent tx exists");
1059				let point = OutPoint::new(parent_tx.compute_txid(), u32::try_from(child_idx).expect("tree child index fits in u32"));
1060				(point, parent_tx.output[child_idx].value)
1061			}
1062		};
1063
1064		let policy = if node.is_leaf() {
1065			let req = spec.vtxos.get(node_idx).expect("one vtxo request for every leaf");
1066			match spec.hashlock_version {
1067				HashlockVersion::V1 => ServerVtxoPolicy::new_hark_leaf(
1068					req.vtxo.policy.user_pubkey(), req.unlock_hash,
1069				),
1070				HashlockVersion::V0 => ServerVtxoPolicy::new_hark_leaf_v0(
1071					req.vtxo.policy.user_pubkey(), req.unlock_hash,
1072				),
1073			}
1074		} else {
1075			let agg_pk = musig::combine_keys(
1076				node.leaves().filter_map(|i| self.spec.spec.vtxos[i].cosign_pubkey)
1077					.chain(self.spec.spec.global_cosign_pubkeys.iter().copied())
1078			);
1079			ServerVtxoPolicy::new_expiry(agg_pk.x_only_public_key().0)
1080		};
1081
1082		ServerVtxo {
1083			policy,
1084			amount,
1085			expiry_height: self.spec.spec.expiry_height,
1086			server_pubkey: self.spec.spec.server_pubkey,
1087			exit_delta: self.spec.spec.exit_delta,
1088			anchor_point: self.spec.utxo,
1089			genesis: Full { items: genesis },
1090			point,
1091		}
1092	}
1093
1094	/// Construct the VTXO at the given leaf index.
1095	///
1096	/// Panics if `leaf_idx` is out of range.
1097	pub fn build_vtxo(&self, leaf_idx: usize) -> Vtxo<Full> {
1098		let req = self.spec.spec.vtxos.get(leaf_idx).expect("index is not a leaf");
1099
1100		let genesis = {
1101			let tree = Tree::new(self.spec.spec.nb_leaves());
1102			let leaf = self.build_genesis_item_at(&tree, leaf_idx, 0);
1103			let internal = tree.iter_branch_with_output(leaf_idx)
1104				.map(|(node_idx, child_idx)| {
1105					self.build_genesis_item_at(&tree, node_idx, u8::try_from(child_idx).expect("tree child index fits in u8"))
1106				});
1107
1108			let mut genesis = [leaf].into_iter().chain(internal).collect::<Vec<_>>();
1109			genesis.reverse();
1110			genesis
1111		};
1112
1113		Vtxo {
1114			amount: req.vtxo.amount,
1115			expiry_height: self.spec.spec.expiry_height,
1116			server_pubkey: self.spec.spec.server_pubkey,
1117			exit_delta: self.spec.spec.exit_delta,
1118			anchor_point: self.spec.utxo,
1119			genesis: Full { items: genesis },
1120			policy: req.vtxo.policy.clone(),
1121			point: {
1122				let leaf_tx = self.txs.get(leaf_idx).expect("leaf idx exists");
1123				OutPoint::new(leaf_tx.compute_txid(), 0)
1124			},
1125		}
1126	}
1127
1128	/// Construct all internal ServerVtxos, each paired with the txid
1129	/// of the transaction that spends it.
1130	pub fn internal_vtxos(&self) -> impl Iterator<Item = (ServerVtxo<Full>, Txid)> + '_ {
1131		(0..self.nb_nodes()).map(|idx| {
1132			let vtxo = self.build_internal_vtxo(idx);
1133			let spending_txid = self.txs[idx].compute_txid();
1134			(vtxo, spending_txid)
1135		})
1136	}
1137
1138	/// Construct all individual vtxos from this round.
1139	pub fn output_vtxos(&self) -> impl Iterator<Item = Vtxo<Full>> + ExactSizeIterator + '_ {
1140		(0..self.nb_leaves()).map(|idx| self.build_vtxo(idx))
1141	}
1142
1143	pub fn spend_info(&self) -> impl Iterator<Item = (VtxoId, Txid)> + '_ {
1144		self.internal_vtxos()
1145			.map(|(vtxo, spending_txid)| (vtxo.id(), spending_txid))
1146	}
1147}
1148
1149/// Calculate the scriptspend sighash of a hArk leaf transaction
1150pub fn hashlocked_leaf_sighash(
1151	leaf_tx: &Transaction,
1152	user_pubkey: PublicKey,
1153	server_pubkey: PublicKey,
1154	unlock_hash: UnlockHash,
1155	prev_txout: &TxOut,
1156) -> TapSighash {
1157	let agg_pk = musig::combine_keys([user_pubkey, server_pubkey])
1158		.x_only_public_key().0;
1159	let clause = unlock_clause(agg_pk, unlock_hash);
1160	let leaf_hash = TapLeafHash::from_script(&clause, bitcoin::taproot::LeafVersion::TapScript);
1161	let mut shc = SighashCache::new(leaf_tx);
1162	shc.taproot_script_spend_signature_hash(
1163		0, // input idx is always 0
1164		&sighash::Prevouts::All(&[prev_txout]),
1165		leaf_hash,
1166		TapSighashType::Default,
1167	).expect("sighash error")
1168}
1169
1170/// Calculate the scriptspend sighash of a hArk leaf transaction
1171pub fn hashlocked_leaf_sighash_v0(
1172	leaf_tx: &Transaction,
1173	user_pubkey: PublicKey,
1174	server_pubkey: PublicKey,
1175	unlock_hash: UnlockHash,
1176	prev_txout: &TxOut,
1177) -> TapSighash {
1178	let agg_pk = musig::combine_keys([user_pubkey, server_pubkey])
1179		.x_only_public_key().0;
1180	let clause = unlock_clause_v0(agg_pk, unlock_hash);
1181	let leaf_hash = TapLeafHash::from_script(&clause, bitcoin::taproot::LeafVersion::TapScript);
1182	let mut shc = SighashCache::new(leaf_tx);
1183	shc.taproot_script_spend_signature_hash(
1184		0, // input idx is always 0
1185		&sighash::Prevouts::All(&[prev_txout]),
1186		leaf_hash,
1187		TapSighashType::Default,
1188	).expect("sighash error")
1189}
1190
1191/// Create the leaf tx sighash from an existing VTXO
1192///
1193/// This is used after the interactive part of the round is finished by
1194/// both user and server to cosign the leaf input script-spend before
1195/// exchanging forfeit signatures for the unlock preimage.
1196fn hashlocked_leaf_sighash_from_vtxo(
1197	vtxo: &Vtxo<Full>,
1198	chain_anchor: &Transaction,
1199) -> TapSighash {
1200	assert_eq!(chain_anchor.compute_txid(), vtxo.chain_anchor().txid);
1201
1202	// we need the penultimate TxOut and last tx
1203	let mut preleaf_txout = chain_anchor.output[vtxo.chain_anchor().vout as usize].clone();
1204	let mut leaf_tx = None;
1205	let mut peekable_iter = vtxo.transactions().peekable();
1206	while let Some(item) = peekable_iter.next() {
1207		// we don't know when we're penultimate, update txout
1208		// each time except last
1209		if peekable_iter.peek().is_some() {
1210			preleaf_txout = item.tx.output[item.output_idx].clone();
1211		}
1212
1213		// then only take the last tx
1214		if peekable_iter.peek().is_none() {
1215			leaf_tx = Some(item.tx);
1216		}
1217	}
1218	let leaf_tx = leaf_tx.expect("at least one tx");
1219
1220	let last_genesis = vtxo.genesis.items.last().expect("at least one genesis item");
1221	match &last_genesis.transition {
1222		GenesisTransition::HashLockedCosigned(inner) => {
1223			debug_assert_eq!(inner.user_pubkey, vtxo.user_pubkey());
1224			hashlocked_leaf_sighash(
1225				&leaf_tx, inner.user_pubkey, vtxo.server_pubkey(), inner.unlock.hash(),
1226				&preleaf_txout,
1227			)
1228		},
1229		GenesisTransition::HashLockedCosigned_v0(inner) => {
1230			debug_assert_eq!(inner.user_pubkey, vtxo.user_pubkey());
1231			hashlocked_leaf_sighash_v0(
1232				&leaf_tx, inner.user_pubkey, vtxo.server_pubkey(), inner.unlock.hash(),
1233				&preleaf_txout,
1234			)
1235		},
1236		_ => panic!("VTXO is not a HashLockedCosigned VTXO"),
1237	}
1238}
1239
1240#[derive(Debug)]
1241pub struct LeafVtxoCosignRequest {
1242	pub vtxo_id: VtxoId,
1243	pub pub_nonce: musig::PublicNonce,
1244}
1245
1246pub struct LeafVtxoCosignContext<'a> {
1247	key: &'a Keypair,
1248	pub_nonce: musig::PublicNonce,
1249	sec_nonce: musig::SecretNonce,
1250	sighash: TapSighash,
1251}
1252
1253impl<'a> LeafVtxoCosignContext<'a> {
1254	/// Create a new [LeafVtxoCosignRequest] for the given VTXO
1255	///
1256	/// Panics if the chain_anchor tx is incorrect or if this VTXO is not a
1257	/// hArk leaf VTXO.
1258	pub fn new(
1259		vtxo: &Vtxo<Full>,
1260		chain_anchor: &Transaction,
1261		key: &'a Keypair,
1262	) -> (Self, LeafVtxoCosignRequest) {
1263		let sighash = hashlocked_leaf_sighash_from_vtxo(&vtxo, chain_anchor);
1264		let (sec_nonce, pub_nonce) = musig::nonce_pair_with_msg(key, &sighash.to_byte_array());
1265		let vtxo_id = vtxo.id();
1266		let req = LeafVtxoCosignRequest { vtxo_id, pub_nonce };
1267		let ret = Self { key, pub_nonce, sec_nonce, sighash };
1268		(ret, req)
1269	}
1270
1271	/// Finalize the VTXO using the response from the server
1272	pub fn finalize(
1273		self,
1274		vtxo: &mut Vtxo<Full>,
1275		response: LeafVtxoCosignResponse,
1276	) -> bool {
1277		let agg_nonce = musig::nonce_agg(&[&self.pub_nonce, &response.public_nonce]);
1278		let (_part_sig, final_sig) = musig::partial_sign(
1279			[vtxo.user_pubkey(), vtxo.server_pubkey()],
1280			agg_nonce,
1281			self.key,
1282			self.sec_nonce,
1283			self.sighash.to_byte_array(),
1284			None,
1285			Some(&[&response.partial_signature]),
1286		);
1287		let final_sig = final_sig.expect("has other sigs");
1288
1289		let pubkey = musig::combine_keys([vtxo.user_pubkey(), vtxo.server_pubkey()])
1290			.x_only_public_key().0;
1291		debug_assert_eq!(pubkey, leaf_cosign_taproot(
1292			vtxo.user_pubkey(),
1293			vtxo.server_pubkey(),
1294			vtxo.expiry_height(),
1295			vtxo.unlock_hash().expect("checked is hark vtxo"),
1296		).internal_key());
1297		if SECP.verify_schnorr(&final_sig, &self.sighash.into(), &pubkey).is_err() {
1298			return false;
1299		}
1300
1301		vtxo.provide_unlock_signature(final_sig)
1302	}
1303}
1304
1305#[derive(Debug)]
1306pub struct LeafVtxoCosignResponse {
1307	pub public_nonce: musig::PublicNonce,
1308	pub partial_signature: musig::PartialSignature,
1309}
1310
1311impl LeafVtxoCosignResponse {
1312	/// Cosign a [LeafVtxoCosignRequest]
1313	pub fn new_cosign(
1314		request: &LeafVtxoCosignRequest,
1315		vtxo: &Vtxo<Full>,
1316		chain_anchor: &Transaction,
1317		server_key: &Keypair,
1318	) -> Self {
1319		debug_assert_eq!(server_key.public_key(), vtxo.server_pubkey());
1320		let sighash = hashlocked_leaf_sighash_from_vtxo(&vtxo, chain_anchor);
1321		let (public_nonce, partial_signature) = musig::deterministic_partial_sign(
1322			server_key,
1323			[vtxo.user_pubkey()],
1324			&[&request.pub_nonce],
1325			sighash.to_byte_array(),
1326			None,
1327		);
1328		Self { public_nonce, partial_signature }
1329	}
1330}
1331
1332pub mod builder {
1333	//! This module allows a single party to construct his own signed
1334	//! VTXO tree, to then request signatures from the server.
1335	//!
1336	//! This is not used for rounds, where the tree is created with
1337	//! many users at once.
1338
1339	use std::collections::HashMap;
1340	use std::marker::PhantomData;
1341
1342	use bitcoin::{Amount, OutPoint, ScriptBuf, TxOut};
1343	use bitcoin::hashes::{sha256, Hash};
1344	use bitcoin::secp256k1::{Keypair, PublicKey};
1345	use bitcoin_ext::{BlockDelta, BlockHeight};
1346
1347	use crate::tree::signed::{UnlockHash, UnlockPreimage, VtxoLeafSpec};
1348	use crate::{musig, VtxoRequest};
1349	use crate::error::IncorrectSigningKeyError;
1350
1351	use super::{CosignSignatureError, SignedVtxoTreeSpec, UnsignedVtxoTree, VtxoTreeSpec};
1352
1353	pub mod state {
1354		mod sealed {
1355			/// Just a trait to seal the BuilderState trait
1356			pub trait Sealed {}
1357			impl Sealed for super::Preparing {}
1358			impl Sealed for super::CanGenerateNonces {}
1359			impl Sealed for super::ServerCanCosign {}
1360			impl Sealed for super::CanFinish {}
1361		}
1362
1363		/// A marker trait used as a generic for [super::SignedTreeBuilder]
1364		pub trait BuilderState: sealed::Sealed {}
1365
1366		/// The user is preparing the funding tx
1367		pub struct Preparing;
1368		impl BuilderState for Preparing {}
1369
1370		/// The UTXO that will be used to fund the tree is known, so the
1371		/// user's signing nonces can be generated
1372		pub struct CanGenerateNonces;
1373		impl BuilderState for CanGenerateNonces {}
1374
1375		/// All the information for the server to cosign the tree is known
1376		pub struct ServerCanCosign;
1377		impl BuilderState for ServerCanCosign {}
1378
1379		/// The user is ready to build the tree as soon as it has
1380		/// a cosign response from the server
1381		pub struct CanFinish;
1382		impl BuilderState for CanFinish {}
1383
1384		/// Trait to capture all states that have sufficient information
1385		/// for either party to create signatures
1386		pub trait CanSign: BuilderState {}
1387		impl CanSign for ServerCanCosign {}
1388		impl CanSign for CanFinish {}
1389	}
1390
1391	/// Just an enum to hold either a tree spec or an unsigned tree
1392	enum BuilderTree {
1393		Spec(VtxoTreeSpec),
1394		Unsigned(UnsignedVtxoTree),
1395	}
1396
1397	impl BuilderTree {
1398		fn unsigned_tree(&self) -> Option<&UnsignedVtxoTree> {
1399			match self {
1400				BuilderTree::Spec(_) => None,
1401				BuilderTree::Unsigned(t) => Some(t),
1402			}
1403		}
1404
1405		fn into_unsigned_tree(self) -> Option<UnsignedVtxoTree> {
1406			match self {
1407				BuilderTree::Spec(_) => None,
1408				BuilderTree::Unsigned(t) => Some(t),
1409			}
1410		}
1411	}
1412
1413	/// A builder for a single party to construct a VTXO tree
1414	///
1415	/// For more information, see the module documentation.
1416	pub struct SignedTreeBuilder<S: state::BuilderState> {
1417		pub expiry_height: BlockHeight,
1418		pub server_pubkey: PublicKey,
1419		pub exit_delta: BlockDelta,
1420		/// The cosign pubkey used to cosign all nodes in the tree
1421		pub cosign_pubkey: PublicKey,
1422		/// The unlock hash used to unlock all VTXOs in the tree
1423		pub unlock_preimage: UnlockPreimage,
1424
1425		tree: BuilderTree,
1426
1427		/// users public nonces, leaves to the root
1428		user_pub_nonces: Vec<musig::PublicNonce>,
1429		/// users secret nonces, leaves to the root
1430		/// this field is empty on the server side
1431		user_sec_nonces: Option<Vec<musig::SecretNonce>>,
1432		_state: PhantomData<S>,
1433	}
1434
1435	impl<T: state::BuilderState> SignedTreeBuilder<T> {
1436		fn tree_spec(&self) -> &VtxoTreeSpec {
1437			match self.tree {
1438				BuilderTree::Spec(ref s) => s,
1439				BuilderTree::Unsigned(ref t) => &t.spec,
1440			}
1441		}
1442
1443		/// The total value required for the tree to be funded
1444		pub fn total_required_value(&self) -> Amount {
1445			self.tree_spec().total_required_value()
1446		}
1447
1448		/// The scriptPubkey to send the board funds to
1449		pub fn funding_script_pubkey(&self) -> ScriptBuf {
1450			self.tree_spec().funding_tx_script_pubkey()
1451		}
1452
1453		/// The TxOut to create in the funding tx
1454		pub fn funding_txout(&self) -> TxOut {
1455			let spec = self.tree_spec();
1456			TxOut {
1457				value: spec.total_required_value(),
1458				script_pubkey: spec.funding_tx_script_pubkey(),
1459			}
1460		}
1461	}
1462
1463	impl<T: state::CanSign> SignedTreeBuilder<T> {
1464		/// Get the user's public nonces
1465		pub fn user_pub_nonces(&self) -> &[musig::PublicNonce] {
1466			&self.user_pub_nonces
1467		}
1468	}
1469
1470	#[derive(Debug, thiserror::Error)]
1471	#[error("signed VTXO tree builder error: {0}")]
1472	pub struct SignedTreeBuilderError(&'static str);
1473
1474	impl SignedTreeBuilder<state::Preparing> {
1475		/// Construct the spec to be used in [SignedTreeBuilder]
1476		pub fn construct_tree_spec(
1477			vtxos: impl IntoIterator<Item = VtxoRequest>,
1478			cosign_pubkey: PublicKey,
1479			unlock_hash: UnlockHash,
1480			expiry_height: BlockHeight,
1481			server_pubkey: PublicKey,
1482			server_cosign_pubkey: PublicKey,
1483			exit_delta: BlockDelta,
1484		) -> Result<VtxoTreeSpec, SignedTreeBuilderError> {
1485			let reqs = vtxos.into_iter()
1486				.map(|vtxo| VtxoLeafSpec {
1487					vtxo: vtxo,
1488					cosign_pubkey: None,
1489					unlock_hash: unlock_hash,
1490				})
1491				.collect::<Vec<_>>();
1492			if reqs.len() < 2 {
1493				return Err(SignedTreeBuilderError("need to have at least 2 VTXOs in tree"));
1494			}
1495			Ok(VtxoTreeSpec::new(
1496				reqs,
1497				server_pubkey,
1498				expiry_height,
1499				exit_delta,
1500				// NB we place server last because then it looks closer like
1501				// a regular user-signed tree which Vtxo::validate relies on
1502				vec![cosign_pubkey, server_cosign_pubkey],
1503			))
1504		}
1505
1506		/// Create a new [SignedTreeBuilder]
1507		pub fn new(
1508			vtxos: impl IntoIterator<Item = VtxoRequest>,
1509			cosign_pubkey: PublicKey,
1510			unlock_preimage: UnlockPreimage,
1511			expiry_height: BlockHeight,
1512			server_pubkey: PublicKey,
1513			server_cosign_pubkey: PublicKey,
1514			exit_delta: BlockDelta,
1515		) -> Result<SignedTreeBuilder<state::Preparing>, SignedTreeBuilderError> {
1516			let tree = Self::construct_tree_spec(
1517				vtxos,
1518				cosign_pubkey,
1519				sha256::Hash::hash(&unlock_preimage),
1520				expiry_height,
1521				server_pubkey,
1522				server_cosign_pubkey,
1523				exit_delta,
1524			)?;
1525
1526			Ok(SignedTreeBuilder {
1527				expiry_height, server_pubkey, exit_delta, cosign_pubkey, unlock_preimage,
1528				tree: BuilderTree::Spec(tree),
1529				user_pub_nonces: Vec::new(),
1530				user_sec_nonces: None,
1531				_state: PhantomData,
1532			})
1533		}
1534
1535		/// Set the utxo from which the tree will be created
1536		pub fn set_utxo(self, utxo: OutPoint) -> SignedTreeBuilder<state::CanGenerateNonces> {
1537			let unsigned_tree = match self.tree {
1538				BuilderTree::Spec(s) => s.into_unsigned_tree(utxo),
1539				BuilderTree::Unsigned(t) => t, // should not happen
1540			};
1541			SignedTreeBuilder {
1542				tree: BuilderTree::Unsigned(unsigned_tree),
1543
1544				expiry_height: self.expiry_height,
1545				server_pubkey: self.server_pubkey,
1546				exit_delta: self.exit_delta,
1547				cosign_pubkey: self.cosign_pubkey,
1548				unlock_preimage: self.unlock_preimage,
1549				user_pub_nonces: self.user_pub_nonces,
1550				user_sec_nonces: self.user_sec_nonces,
1551				_state: PhantomData,
1552			}
1553		}
1554	}
1555
1556	impl SignedTreeBuilder<state::CanGenerateNonces> {
1557		/// Generate user nonces
1558		pub fn generate_user_nonces(
1559			self,
1560			cosign_key: &Keypair,
1561		) -> SignedTreeBuilder<state::CanFinish> {
1562			let unsigned_tree = self.tree.unsigned_tree().expect("state invariant");
1563
1564			let mut cosign_sec_nonces = Vec::with_capacity(unsigned_tree.internal_sighashes.len());
1565			let mut cosign_pub_nonces = Vec::with_capacity(unsigned_tree.internal_sighashes.len());
1566			for sh in &unsigned_tree.internal_sighashes {
1567				let pair = musig::nonce_pair_with_msg(&cosign_key, &sh.to_byte_array());
1568				cosign_sec_nonces.push(pair.0);
1569				cosign_pub_nonces.push(pair.1);
1570			}
1571
1572			SignedTreeBuilder {
1573				user_pub_nonces: cosign_pub_nonces,
1574				user_sec_nonces: Some(cosign_sec_nonces),
1575
1576				expiry_height: self.expiry_height,
1577				server_pubkey: self.server_pubkey,
1578				exit_delta: self.exit_delta,
1579				cosign_pubkey: self.cosign_pubkey,
1580				unlock_preimage: self.unlock_preimage,
1581				tree: self.tree,
1582				_state: PhantomData,
1583			}
1584		}
1585	}
1586
1587	/// Holds the cosignature information of the server
1588	#[derive(Debug, Clone)]
1589	pub struct SignedTreeCosignResponse {
1590		pub pub_nonces: Vec<musig::PublicNonce>,
1591		pub partial_signatures: Vec<musig::PartialSignature>,
1592	}
1593
1594	impl SignedTreeBuilder<state::ServerCanCosign> {
1595		/// Create a new [SignedTreeBuilder] for the server to cosign
1596		pub fn new_for_cosign(
1597			vtxos: impl IntoIterator<Item = VtxoRequest>,
1598			cosign_pubkey: PublicKey,
1599			unlock_preimage: UnlockPreimage,
1600			expiry_height: BlockHeight,
1601			server_pubkey: PublicKey,
1602			server_cosign_pubkey: PublicKey,
1603			exit_delta: BlockDelta,
1604			utxo: OutPoint,
1605			user_pub_nonces: Vec<musig::PublicNonce>,
1606		) -> Result<SignedTreeBuilder<state::ServerCanCosign>, SignedTreeBuilderError> {
1607			let unsigned_tree = SignedTreeBuilder::construct_tree_spec(
1608				vtxos,
1609				cosign_pubkey,
1610				sha256::Hash::hash(&unlock_preimage),
1611				expiry_height,
1612				server_pubkey,
1613				server_cosign_pubkey,
1614				exit_delta,
1615			)?.into_unsigned_tree(utxo);
1616
1617			Ok(SignedTreeBuilder {
1618				expiry_height,
1619				server_pubkey,
1620				exit_delta,
1621				cosign_pubkey,
1622				unlock_preimage,
1623				user_pub_nonces,
1624				tree: BuilderTree::Unsigned(unsigned_tree),
1625				user_sec_nonces: None,
1626				_state: PhantomData,
1627			})
1628		}
1629
1630		/// The server cosigns the tree nodes
1631		pub fn server_cosign(&self, server_cosign_key: &Keypair) -> SignedTreeCosignResponse {
1632			let unsigned_tree = self.tree.unsigned_tree().expect("state invariant");
1633
1634			let mut sec_nonces = Vec::with_capacity(unsigned_tree.internal_sighashes.len());
1635			let mut pub_nonces = Vec::with_capacity(unsigned_tree.internal_sighashes.len());
1636			for sh in &unsigned_tree.internal_sighashes {
1637				let pair = musig::nonce_pair_with_msg(&server_cosign_key, &sh.to_byte_array());
1638				sec_nonces.push(pair.0);
1639				pub_nonces.push(pair.1);
1640			}
1641
1642			let agg_nonces = self.user_pub_nonces().iter().zip(&pub_nonces)
1643				.map(|(u, s)| musig::AggregatedNonce::new(&[u, s]))
1644				.collect::<Vec<_>>();
1645
1646			let sigs = unsigned_tree.cosign_tree(&agg_nonces, &server_cosign_key, sec_nonces);
1647
1648			SignedTreeCosignResponse {
1649				pub_nonces,
1650				partial_signatures: sigs,
1651			}
1652		}
1653	}
1654
1655	impl SignedTreeBuilder<state::CanFinish> {
1656		/// Validate the server's partial signatures
1657		pub fn verify_cosign_response(
1658			&self,
1659			server_cosign: &SignedTreeCosignResponse,
1660		) -> Result<(), CosignSignatureError> {
1661			let unsigned_tree = self.tree.unsigned_tree().expect("state invariant");
1662
1663			let agg_nonces = self.user_pub_nonces().iter()
1664				.zip(&server_cosign.pub_nonces)
1665				.map(|(u, s)| musig::AggregatedNonce::new(&[u, s]))
1666				.collect::<Vec<_>>();
1667
1668			unsigned_tree.verify_global_cosign_partial_sigs(
1669				*unsigned_tree.spec.global_cosign_pubkeys.get(1).expect("state invariant"),
1670				&agg_nonces,
1671				&server_cosign.pub_nonces,
1672				&server_cosign.partial_signatures,
1673			)
1674		}
1675
1676		pub fn build_tree(
1677			self,
1678			server_cosign: &SignedTreeCosignResponse,
1679			cosign_key: &Keypair,
1680		) -> Result<SignedVtxoTreeSpec, IncorrectSigningKeyError> {
1681			if cosign_key.public_key() != self.cosign_pubkey {
1682				return Err(IncorrectSigningKeyError {
1683					required: Some(self.cosign_pubkey),
1684					provided: cosign_key.public_key(),
1685				});
1686			}
1687
1688			let agg_nonces = self.user_pub_nonces().iter().zip(&server_cosign.pub_nonces)
1689				.map(|(u, s)| musig::AggregatedNonce::new(&[u, s]))
1690				.collect::<Vec<_>>();
1691
1692			let unsigned_tree = self.tree.into_unsigned_tree().expect("state invariant");
1693			let sec_nonces = self.user_sec_nonces.expect("state invariant");
1694			let partial_sigs = unsigned_tree.cosign_tree(&agg_nonces, cosign_key, sec_nonces);
1695
1696			debug_assert!(unsigned_tree.verify_global_cosign_partial_sigs(
1697				self.cosign_pubkey,
1698				&agg_nonces,
1699				&self.user_pub_nonces,
1700				&partial_sigs,
1701			).is_ok(), "produced invalid partial signatures");
1702
1703			let sigs = unsigned_tree.combine_partial_signatures(
1704				&agg_nonces,
1705				&HashMap::new(),
1706				&[&server_cosign.partial_signatures, &partial_sigs],
1707			).expect("should work with correct cosign signatures");
1708
1709			Ok(unsigned_tree.into_signed_tree(sigs))
1710		}
1711	}
1712}
1713
1714/// The serialization version of [VtxoTreeSpec].
1715const VTXO_TREE_SPEC_VERSION: u8 = 0x02;
1716
1717impl ProtocolEncoding for VtxoTreeSpec {
1718	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
1719		w.emit_u8(VTXO_TREE_SPEC_VERSION)?;
1720		w.emit_u32(self.expiry_height)?;
1721		self.server_pubkey.encode(w)?;
1722		w.emit_u16(self.exit_delta)?;
1723		LengthPrefixedVector::new(&self.global_cosign_pubkeys).encode(w)?;
1724		LengthPrefixedVector::new(&self.vtxos).encode(w)?;
1725		Ok(())
1726	}
1727
1728	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
1729		let version = r.read_u8()?;
1730
1731		if version != VTXO_TREE_SPEC_VERSION {
1732			return Err(ProtocolDecodingError::invalid(format_args!(
1733				"invalid VtxoTreeSpec encoding version byte: {version:#x}",
1734			)));
1735		}
1736
1737		let expiry_height = check_block_height(r.read_u32()?)
1738			.map_err(|e| ProtocolDecodingError::invalid_err(e, "expiry_height"))?;
1739		let server_pubkey = PublicKey::decode(r)?;
1740		let exit_delta = check_block_delta(r.read_u16()?)
1741			.map_err(|e| ProtocolDecodingError::invalid_err(e, "exit_delta"))?;
1742		let global_cosign_pubkeys = LengthPrefixedVector::decode(r)?.into_inner();
1743		let vtxos = LengthPrefixedVector::decode(r)?.into_inner();
1744		if vtxos.is_empty() {
1745			return Err(ProtocolDecodingError::invalid(
1746				"vtxo tree spec must have at least one leaf",
1747			));
1748		}
1749		Ok(VtxoTreeSpec {
1750			vtxos, expiry_height, server_pubkey, exit_delta, global_cosign_pubkeys,
1751			// not part of the encoding; see the field docs for how to handle
1752			// trees that might predate the v1 clauses
1753			hashlock_version: HashlockVersion::V1,
1754		})
1755	}
1756}
1757
1758/// The serialization version of [SignedVtxoTreeSpec].
1759const SIGNED_VTXO_TREE_SPEC_VERSION: u8 = 0x02;
1760
1761/// The serialization version of [SignedVtxoTreeSpec] with u32 as signature count
1762const SIGNED_VTXO_TREE_SPEC_VERSION_U32_SIZE: u8 = 0x01;
1763
1764impl ProtocolEncoding for SignedVtxoTreeSpec {
1765	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
1766		w.emit_u8(SIGNED_VTXO_TREE_SPEC_VERSION)?;
1767		self.spec.encode(w)?;
1768		self.utxo.encode(w)?;
1769		LengthPrefixedVector::new(&self.cosign_sigs).encode(w)?;
1770		Ok(())
1771	}
1772
1773	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
1774		let version = r.read_u8()?;
1775		if version != SIGNED_VTXO_TREE_SPEC_VERSION
1776			&& version != SIGNED_VTXO_TREE_SPEC_VERSION_U32_SIZE
1777		{
1778			return Err(ProtocolDecodingError::invalid(format_args!(
1779				"invalid SignedVtxoTreeSpec encoding version byte: {version:#x}",
1780			)));
1781		}
1782		let spec = VtxoTreeSpec::decode(r)?;
1783		let utxo = OutPoint::decode(r)?;
1784		let cosign_sigs = if version == SIGNED_VTXO_TREE_SPEC_VERSION_U32_SIZE {
1785			let nb_cosign_sigs = r.read_u32()?;
1786			OversizedVectorError::check::<schnorr::Signature>(nb_cosign_sigs as usize)?;
1787			let mut cosign_sigs = Vec::with_capacity(nb_cosign_sigs as usize);
1788			for _ in 0..nb_cosign_sigs {
1789				cosign_sigs.push(schnorr::Signature::decode(r)?);
1790			}
1791			cosign_sigs
1792		} else {
1793			LengthPrefixedVector::decode(r)?.into_inner()
1794		};
1795		Ok(SignedVtxoTreeSpec { spec, utxo, cosign_sigs })
1796	}
1797}
1798
1799
1800#[cfg(test)]
1801mod test {
1802	use std::iter;
1803	use std::collections::HashMap;
1804	use std::str::FromStr;
1805
1806	use bitcoin::hashes::{siphash24, sha256, Hash, HashEngine};
1807	use bitcoin::key::rand::Rng;
1808	use bitcoin::secp256k1::{self, rand, Keypair};
1809	use bitcoin::{absolute, transaction};
1810	use rand::SeedableRng;
1811
1812	use crate::encode;
1813	use crate::test_util::{encoding_roundtrip, json_roundtrip};
1814	use crate::tree::signed::builder::SignedTreeBuilder;
1815	use crate::vtxo::policy::{ServerVtxoPolicy, VtxoPolicy};
1816
1817	use super::*;
1818
1819	fn test_tree_amounts(
1820		tree: &UnsignedVtxoTree,
1821		root_value: Amount,
1822	) {
1823		let map = tree.txs.iter().map(|tx| (tx.compute_txid(), tx)).collect::<HashMap<_, _>>();
1824
1825		// skip the root
1826		for (idx, tx) in tree.txs.iter().take(tree.txs.len().saturating_sub(1)).enumerate() {
1827			println!("tx #{idx}: {}", bitcoin::consensus::encode::serialize_hex(tx));
1828			let input = tx.input.iter().map(|i| {
1829				let prev = i.previous_output;
1830				map.get(&prev.txid).expect(&format!("tx {} not found", prev.txid))
1831					.output[prev.vout as usize].value
1832			}).sum::<Amount>();
1833			let output = tx.output_value();
1834			assert!(input >= output);
1835			assert_eq!(input, output);
1836		}
1837
1838		// check the root
1839		let root = tree.txs.last().unwrap();
1840		assert_eq!(root_value, root.output_value());
1841	}
1842
1843	#[test]
1844	fn vtxo_tree() {
1845		let secp = secp256k1::Secp256k1::new();
1846		let mut rand = rand::rngs::StdRng::seed_from_u64(42);
1847		let random_sig = {
1848			let key = Keypair::new(&secp, &mut rand);
1849			let sha = sha256::Hash::from_str("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a").unwrap();
1850			let msg = secp256k1::Message::from_digest(sha.to_byte_array());
1851			secp.sign_schnorr(&msg, &key)
1852		};
1853
1854		let server_key = Keypair::new(&secp, &mut rand);
1855		let server_cosign_key = Keypair::new(&secp, &mut rand);
1856
1857		struct Req {
1858			key: Keypair,
1859			cosign_key: Keypair,
1860			amount: Amount,
1861			hash: sha256::Hash,
1862		}
1863		impl Req {
1864			fn to_vtxo(&self) -> VtxoLeafSpec {
1865				VtxoLeafSpec {
1866					vtxo: VtxoRequest {
1867						amount: self.amount,
1868						policy: VtxoPolicy::new_pubkey(self.key.public_key()),
1869					},
1870					cosign_pubkey: Some(self.cosign_key.public_key()),
1871					unlock_hash: self.hash,
1872				}
1873			}
1874		}
1875
1876		let nb_leaves = 27;
1877		let reqs = iter::repeat_with(|| Req {
1878			key: Keypair::new(&secp, &mut rand),
1879			cosign_key:  Keypair::new(&secp, &mut rand),
1880			amount: Amount::from_sat(100_000),
1881			hash: sha256::Hash::from_byte_array(rand.r#gen()),
1882		}).take(nb_leaves).collect::<Vec<_>>();
1883		let point = "0000000000000000000000000000000000000000000000000000000000000001:1".parse().unwrap();
1884
1885		let spec = VtxoTreeSpec::new(
1886			reqs.iter().map(|r| r.to_vtxo()).collect(),
1887			server_key.public_key(),
1888			101_000,
1889			2016,
1890			vec![server_cosign_key.public_key()],
1891		);
1892		assert_eq!(spec.nb_leaves(), nb_leaves);
1893		assert_eq!(spec.total_required_value().to_sat(), 2700000);
1894		let nb_nodes = spec.nb_nodes();
1895
1896		encoding_roundtrip(&spec);
1897
1898		let unsigned = spec.into_unsigned_tree(point);
1899
1900		test_tree_amounts(&unsigned, unsigned.spec.total_required_value());
1901
1902		let sighashes_hash = {
1903			let mut eng = siphash24::Hash::engine();
1904			unsigned.internal_sighashes.iter().for_each(|h| eng.input(&h[..]));
1905			siphash24::Hash::from_engine(eng)
1906		};
1907		assert_eq!(sighashes_hash.to_string(), "78ae911f557c0b86");
1908
1909		let signed = unsigned.into_signed_tree(vec![random_sig; nb_nodes]);
1910
1911		encoding_roundtrip(&signed);
1912
1913		#[derive(Debug, PartialEq, Serialize, Deserialize)]
1914		struct JsonSignedVtxoTreeSpec {
1915			#[serde(with = "encode::serde")]
1916			pub spec: SignedVtxoTreeSpec,
1917		}
1918
1919		json_roundtrip(&JsonSignedVtxoTreeSpec { spec: signed.clone() });
1920
1921		for l in 0..nb_leaves {
1922			let exit = signed.exit_branch(l);
1923
1924			// Assert it's a valid chain.
1925			let mut iter = exit.iter().enumerate().peekable();
1926			while let Some((i, cur)) = iter.next() {
1927				if let Some((_, next)) = iter.peek() {
1928					assert_eq!(next.input[0].previous_output.txid, cur.compute_txid(), "{}", i);
1929				}
1930			}
1931		}
1932
1933		let cached = signed.into_cached_tree();
1934		for vtxo in cached.output_vtxos() {
1935			encoding_roundtrip(&vtxo);
1936		}
1937	}
1938
1939	#[test]
1940	fn test_tree_builder() {
1941		let expiry = 100_000;
1942		let exit_delta = 24;
1943
1944		let vtxo_key = Keypair::from_str("985247fb0ef008f8043b6be28add87710d42d482433ef287235bfe041ee6cc11").unwrap();
1945		let policy = VtxoPolicy::new_pubkey(vtxo_key.public_key());
1946		let user_cosign_key = Keypair::from_str("5255d132d6ec7d4fc2a41c8f0018bb14343489ddd0344025cc60c7aa2b3fda6a").unwrap();
1947		let user_cosign_pubkey = user_cosign_key.public_key();
1948		println!("user_cosign_pubkey: {}", user_cosign_pubkey);
1949
1950		let server_key = Keypair::from_str("1fb316e653eec61de11c6b794636d230379509389215df1ceb520b65313e5426").unwrap();
1951		let server_pubkey = server_key.public_key();
1952		println!("server_pubkey: {}", server_pubkey);
1953
1954		let server_cosign_key = Keypair::from_str("52a506fbae3b725749d2486afd4761841ec685b841c2967e30f24182c4b02eed").unwrap();
1955		let server_cosign_pubkey = server_cosign_key.public_key();
1956		println!("server_cosign_pubkey: {}", server_cosign_pubkey);
1957
1958		let unlock_preimage = rand::random::<UnlockPreimage>();
1959		let unlock_hash = sha256::Hash::hash(&unlock_preimage);
1960		println!("unlock_hash: {}", unlock_hash);
1961
1962		// we test different number of nodes
1963		for nb_vtxos in [2, 3, 4, 5, 10, 50] {
1964			println!("building tree with {} vtxos", nb_vtxos);
1965			let vtxos = (0..nb_vtxos).map(|i| VtxoRequest {
1966				amount: Amount::from_sat(1000 * (i + 1)),
1967				policy: policy.clone(),
1968			}).collect::<Vec<_>>();
1969
1970			let builder = SignedTreeBuilder::new(
1971				vtxos.iter().cloned(), user_cosign_pubkey, unlock_preimage, expiry, server_pubkey,
1972				server_cosign_pubkey, exit_delta,
1973			).unwrap();
1974
1975			let funding_tx = Transaction {
1976				version: transaction::Version::TWO,
1977				lock_time: absolute::LockTime::ZERO,
1978				input: vec![],
1979				output: vec![builder.funding_txout()],
1980			};
1981			let utxo = OutPoint::new(funding_tx.compute_txid(), 0);
1982			let builder = builder.set_utxo(utxo).generate_user_nonces(&user_cosign_key);
1983			let user_pub_nonces = builder.user_pub_nonces().to_vec();
1984
1985			let cosign = {
1986				let builder = SignedTreeBuilder::new_for_cosign(
1987					vtxos.iter().cloned(), user_cosign_pubkey, unlock_preimage, expiry, server_pubkey,
1988					server_cosign_pubkey, exit_delta, utxo, user_pub_nonces,
1989				).unwrap();
1990				builder.server_cosign(&server_cosign_key)
1991			};
1992
1993			builder.verify_cosign_response(&cosign).unwrap();
1994			let tree = builder.build_tree(&cosign, &user_cosign_key).unwrap().into_cached_tree();
1995
1996			// finalize vtxos and check
1997			for mut vtxo in tree.output_vtxos() {
1998				{
1999					// check that with just the preimage, the VTXO is not valid
2000					let mut with_preimage = vtxo.clone();
2001					assert!(with_preimage.provide_unlock_preimage(unlock_preimage));
2002					assert!(with_preimage.validate(&funding_tx).is_err());
2003				}
2004
2005				let (ctx, req) = LeafVtxoCosignContext::new(&vtxo, &funding_tx, &vtxo_key);
2006				let cosign = LeafVtxoCosignResponse::new_cosign(&req, &vtxo, &funding_tx, &server_key);
2007				assert!(ctx.finalize(&mut vtxo, cosign));
2008
2009
2010				// We still miss some signatures. But the tree should be vaild
2011				assert!(!vtxo.has_all_witnesses());
2012				vtxo.validate_unsigned(&funding_tx).expect("Tree is valid if we ignore sigs");
2013				vtxo.validate(&funding_tx).expect_err("The signature check must fail");
2014
2015				assert!(vtxo.provide_unlock_preimage(unlock_preimage));
2016
2017				println!("vtxo debug: {:#?}", vtxo);
2018				println!("vtxo hex: {}", vtxo.serialize_hex());
2019				assert!(vtxo.has_all_witnesses());
2020				vtxo.validate(&funding_tx).expect("should be value");
2021
2022				vtxo.invalidate_final_sig();
2023				assert!(vtxo.has_all_witnesses(), "still has all witnesses, just an invalid one");
2024				vtxo.validate_unsigned(&funding_tx).expect("unsigned still valid");
2025				vtxo.validate(&funding_tx).expect_err("but not fully valid anymore");
2026			}
2027
2028			for (idx, (vtxo, _spending_txid)) in tree.internal_vtxos().enumerate() {
2029				// Verify transactions with consensus checks
2030				let mut prev_txout = funding_tx.output[vtxo.chain_anchor().vout as usize].clone();
2031
2032				// Verify that all vtxo.transactions() are consensus valid
2033				for item in vtxo.transactions() {
2034					crate::test_util::verify_tx(&[prev_txout], 0, &item.tx)
2035						.expect("Invalid transaction");
2036					prev_txout = item.tx.output[item.output_idx].clone();
2037				}
2038
2039				// Verify the policies
2040				if idx < nb_vtxos as usize {
2041					// All leafs have the HarkLeafPolicy
2042					matches!(vtxo.policy(), ServerVtxoPolicy::HarkLeaf(_));
2043				} else {
2044					matches!(vtxo.policy(), ServerVtxoPolicy::Expiry(_));
2045				}
2046			}
2047		}
2048	}
2049
2050	#[test]
2051	fn tree_hashlock_version_detection() {
2052		let secp = secp256k1::Secp256k1::new();
2053		let mut rand = rand::rngs::StdRng::seed_from_u64(43);
2054
2055		let user_key = Keypair::new(&secp, &mut rand);
2056		let user_cosign_key = Keypair::new(&secp, &mut rand);
2057		let server_key = Keypair::new(&secp, &mut rand);
2058		let server_cosign_key = Keypair::new(&secp, &mut rand);
2059		let preimage: UnlockPreimage = rand.r#gen();
2060		let unlock_hash = sha256::Hash::hash(&preimage);
2061
2062		// 6 leaves make a tree with two internal nodes, so detection has to
2063		// work on a first internal node that isn't the root
2064		let outputs = (1..=6u64).map(|i| VtxoRequest {
2065			amount: Amount::from_sat(10_000 * i),
2066			policy: VtxoPolicy::new_pubkey(user_key.public_key()),
2067		}).collect::<Vec<_>>();
2068
2069		let (v1_tree, _) = crate::test_util::build_signed_tree(
2070			HashlockVersion::V1, outputs.iter().cloned(),
2071			&user_cosign_key, &server_key, &server_cosign_key, unlock_hash,
2072		);
2073		let (v0_tree, v0_funding_tx) = crate::test_util::build_signed_tree(
2074			HashlockVersion::V0, outputs.iter().cloned(),
2075			&user_cosign_key, &server_key, &server_cosign_key, unlock_hash,
2076		);
2077
2078		// the version changes the leaf taproots and thus the vtxo ids,
2079		// so building with the wrong version yields the wrong vtxos
2080		assert_ne!(
2081			v1_tree.clone().into_cached_tree().build_vtxo(0).id(),
2082			v0_tree.clone().into_cached_tree().build_vtxo(0).id(),
2083		);
2084
2085		// detection recovers the version, also after an encoding roundtrip,
2086		// which drops it
2087		for (tree, version) in [(&v1_tree, HashlockVersion::V1), (&v0_tree, HashlockVersion::V0)] {
2088			assert_eq!(tree.detect_hashlock_version(), Ok(version));
2089
2090			let decoded = SignedVtxoTreeSpec::deserialize(&tree.serialize()).unwrap();
2091			assert_eq!(decoded.spec.hashlock_version, HashlockVersion::V1);
2092			let restored = decoded.with_detected_hashlock_version().unwrap();
2093			assert_eq!(restored.spec.hashlock_version, version);
2094			assert_eq!(&restored.spec, &tree.spec);
2095		}
2096
2097		// a tree with an invalid first cosign signature can't be detected
2098		let garbage_sig = {
2099			let sha = sha256::Hash::hash(b"not a tree sighash");
2100			let msg = secp256k1::Message::from_digest(sha.to_byte_array());
2101			secp.sign_schnorr(&msg, &Keypair::new(&secp, &mut rand))
2102		};
2103		let mut broken = v0_tree.clone();
2104		broken.cosign_sigs[0] = garbage_sig;
2105		assert_eq!(broken.detect_hashlock_version(), Err(HashlockVersionDetectError));
2106
2107		// detection only checks the first signature, it's not an integrity
2108		// check, so a corrupt later signature doesn't affect it
2109		let mut half_broken = v0_tree.clone();
2110		half_broken.cosign_sigs[1] = garbage_sig;
2111		assert_eq!(half_broken.detect_hashlock_version(), Ok(HashlockVersion::V0));
2112
2113		// the v0 leaves carry the v0 policy and genesis transition and can
2114		// complete the post-round cosign and unlock flow
2115		let cached = v0_tree.into_cached_tree();
2116		for (idx, (vtxo, _)) in cached.internal_vtxos().enumerate() {
2117			if idx < cached.nb_leaves() {
2118				assert!(matches!(vtxo.policy(), ServerVtxoPolicy::HarkLeaf_v0(_)));
2119			}
2120		}
2121		for mut vtxo in cached.output_vtxos() {
2122			assert_eq!(vtxo.unlock_hash(), Some(unlock_hash));
2123			assert!(matches!(
2124				vtxo.genesis.items.last().unwrap().transition,
2125				GenesisTransition::HashLockedCosigned_v0(_),
2126			));
2127
2128			let (ctx, req) = LeafVtxoCosignContext::new(&vtxo, &v0_funding_tx, &user_key);
2129			let resp = LeafVtxoCosignResponse::new_cosign(&req, &vtxo, &v0_funding_tx, &server_key);
2130			assert!(ctx.finalize(&mut vtxo, resp));
2131			assert!(vtxo.provide_unlock_preimage(preimage));
2132			vtxo.validate(&v0_funding_tx).expect("unlocked v0 leaf vtxo should be valid");
2133		}
2134	}
2135
2136	#[test]
2137	fn vtxo_leaf_spec_encoding() {
2138		let pk1: PublicKey = "020aceb65eed0ee5c512d3718e6f4bd868a7efb58ede7899ffd9bcba09555d4eb8".parse().unwrap();
2139		let pk2: PublicKey = "02e4ed0ca35c3b8a2ff675b9b23f4961964b57e130afa607e32a83d2d9a510622b".parse().unwrap();
2140		let hash = sha256::Hash::from_str("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a").unwrap();
2141
2142		// Test with Some(cosign_pubkey)
2143		let spec_with_cosign = VtxoLeafSpec {
2144			vtxo: VtxoRequest {
2145				amount: Amount::from_sat(100_000),
2146				policy: VtxoPolicy::new_pubkey(pk1),
2147			},
2148			cosign_pubkey: Some(pk2),
2149			unlock_hash: hash,
2150		};
2151		encoding_roundtrip(&spec_with_cosign);
2152
2153		// Test with None cosign_pubkey
2154		let spec_without_cosign = VtxoLeafSpec {
2155			vtxo: VtxoRequest {
2156				amount: Amount::from_sat(200_000),
2157				policy: VtxoPolicy::new_pubkey(pk1),
2158			},
2159			cosign_pubkey: None,
2160			unlock_hash: hash,
2161		};
2162		encoding_roundtrip(&spec_without_cosign);
2163	}
2164
2165	#[test]
2166	fn vtxo_tree_spec_rejects_empty_vtxos() {
2167		let pk1: PublicKey = "020aceb65eed0ee5c512d3718e6f4bd868a7efb58ede7899ffd9bcba09555d4eb8"
2168			.parse().unwrap();
2169		let pk2: PublicKey = "02e4ed0ca35c3b8a2ff675b9b23f4961964b57e130afa607e32a83d2d9a510622b"
2170			.parse().unwrap();
2171		let hash = sha256::Hash::from_str(
2172			"4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a",
2173		).unwrap();
2174
2175		// Build a valid spec and verify it roundtrips.
2176		let leaf = VtxoLeafSpec {
2177			vtxo: VtxoRequest {
2178				amount: Amount::from_sat(100_000),
2179				policy: VtxoPolicy::new_pubkey(pk1),
2180			},
2181			cosign_pubkey: Some(pk2),
2182			unlock_hash: hash,
2183		};
2184		let spec = VtxoTreeSpec::new(vec![leaf], pk1, 100_000, 2016, vec![]);
2185		encoding_roundtrip(&spec);
2186
2187		// Empty the vtxos and verify decode rejects it.
2188		let empty_spec = VtxoTreeSpec { vtxos: vec![], ..spec };
2189		let buf = empty_spec.serialize();
2190		let err = VtxoTreeSpec::deserialize(&buf)
2191			.expect_err("decoding a VtxoTreeSpec with zero vtxos must fail");
2192		let msg = err.to_string();
2193		assert!(msg.contains("at least one leaf"), "unexpected error message: {msg}");
2194	}
2195
2196	#[test]
2197	fn test_compat_u32_size_signed_spec() {
2198		//! check the backwards compatibility of parsing SignedVtxoTreeSpec with u32 as size prefix
2199		let hex = "0102888a0100035b0ef8c9bd756af433edc3129975888f6f18b8185b2afbaabc8bb3029a00cf81e0070102f8112234026e68b1e4d1565540d7b791ced1b64c5f30525cbe14f21dd7aa8c78030003c48b53afac0d2d5169cd6848f03f67a21db6f506f8b8fc2dbef2552b6a7dc111a08601000000000002c6c80e198e170ca6f8fa17810d8ee23c7c0d85c5d2febc95c3e24b1878ca733fbfd032abc31b253f5063521fd5b4c431f2cdd3fee1b4ec00a9b00f69d3b033e7000296dfec4c92e831ffe3619285646a46c545577f19dbc27c2fc0950bffb0f4a362a08601000000000003850a7d2bf22e6ba669695410a8b03c5800a0d4c2bec814b9eb21b0cddd2af5c935395dea8bd6dcac26a8a417b553b18d13027c23e8016c3466b81e70832254360002415f712d6e551b715542422b975a2ae7c635b44a1e3747d5a8674231fa10a841a08601000000000002a3d4de26a87f8bb9d5c0b9f1e3409a635b35f656575d8ad60a6a2294ac4e50b87c0cc2177dfce6432efa42ca6c04c0b774dbb3c5ca2573cd893443e10e393bfd0100000000000000000000000000000000000000000000000000000000000000010000000400000002cc1980aba21f65a51342cbaa3beb69d930eac87fe3086c45df4e642f2dd07cd19e0e4c7b9584b9e952eb4fb02e7f43364ee9bbfc667236aa166fd10a97dcbb02cc1980aba21f65a51342cbaa3beb69d930eac87fe3086c45df4e642f2dd07cd19e0e4c7b9584b9e952eb4fb02e7f43364ee9bbfc667236aa166fd10a97dcbb02cc1980aba21f65a51342cbaa3beb69d930eac87fe3086c45df4e642f2dd07cd19e0e4c7b9584b9e952eb4fb02e7f43364ee9bbfc667236aa166fd10a97dcbb02cc1980aba21f65a51342cbaa3beb69d930eac87fe3086c45df4e642f2dd07cd19e0e4c7b9584b9e952eb4fb02e7f43364ee9bbfc667236aa166fd10a97dcbb";
2200		let ret = SignedVtxoTreeSpec::deserialize_hex(hex).unwrap();
2201		assert_eq!(ret.cosign_sigs.len(), 4);
2202	}
2203}