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