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