1use std::any::Any;
2use std::convert::{TryFrom, TryInto};
3use std::sync::atomic::{AtomicU64, Ordering};
4use std::sync::{Arc, Mutex};
5
6use bitcoin::bip32::ChildNumber;
7use bitcoin::bip32::Xpub;
8use bitcoin::hashes::Hash;
9use bitcoin::psbt::Psbt;
10use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
11use bitcoin::secp256k1::{
12 ecdh::SharedSecret, ecdsa::Signature, All, PublicKey, Scalar, Secp256k1, SecretKey,
13};
14use bitcoin::WPubkeyHash;
15use bitcoin::{Transaction, TxOut};
16use lightning::ln::chan_utils::{
17 ChannelPublicKeys, ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction,
18 HTLCOutputInCommitment, HolderCommitmentTransaction,
19};
20use lightning::ln::inbound_payment::ExpandedKey;
21use lightning::ln::msgs::UnsignedChannelAnnouncement;
22use lightning::ln::msgs::UnsignedGossipMessage;
23use lightning::ln::script::ShutdownScript;
24use lightning::sign::ecdsa::EcdsaChannelSigner;
25use lightning::sign::{ChannelSigner, NodeSigner};
26use lightning::sign::{EntropySource, SignerProvider};
27use lightning::sign::{Recipient, SpendableOutputDescriptor};
28use lightning::types::payment::PaymentPreimage;
29use lightning::util::ser::{Writeable, Writer};
30use lightning_signer::bitcoin::absolute::LockTime;
31use lightning_signer::bitcoin::sighash::EcdsaSighashType;
32use lightning_signer::bitcoin::{self, ScriptBuf, Witness};
33use lightning_signer::channel::{ChannelId, CommitmentType};
34use lightning_signer::lightning;
35use lightning_signer::lightning::sign::HTLCDescriptor;
36use lightning_signer::lightning::sign::OutputSpender;
37use lightning_signer::signer::derive::KeyDerivationStyle;
38use lightning_signer::util::transaction_utils::create_spending_transaction;
39use lightning_signer::util::INITIAL_COMMITMENT_NUMBER;
40use log::{debug, error};
41
42use vls_protocol::model::{
43 Basepoints, BitcoinSignature, CloseInfo, DisclosedSecret, Htlc, PubKey, Utxo,
44};
45use vls_protocol::msgs::{
46 DeBolt, Ecdh, EcdhReply, GetChannelBasepoints, GetChannelBasepointsReply,
47 GetPerCommitmentPoint, GetPerCommitmentPoint2, GetPerCommitmentPoint2Reply,
48 GetPerCommitmentPointReply, GetSecureRandomBytes, GetSecureRandomBytesReply, HsmdInit2,
49 HsmdInit2Reply, NewChannel, NewChannelReply, SerBolt, SetupChannel, SetupChannelReply,
50 SignBolt12Invoice, SignBolt12InvoiceReply, SignChannelAnnouncement,
51 SignChannelAnnouncementReply, SignCommitmentTxReply, SignCommitmentTxWithHtlcsReply,
52 SignGossipMessage, SignGossipMessageReply, SignInvoice, SignInvoiceReply,
53 SignLocalCommitmentTx2, SignLocalHtlcTx2, SignMessage, SignMessageReply, SignMutualCloseTx2,
54 SignRemoteCommitmentTx2, SignTxReply, SignWithdrawal, SignWithdrawalReply,
55 ValidateCommitmentTx2, ValidateCommitmentTxReply, ValidateRevocation, ValidateRevocationReply,
56};
57#[cfg(feature = "developer")]
58use vls_protocol::msgs::{HsmdDevPreinit, HsmdDevPreinitReply};
59use vls_protocol::serde_bolt::{Array, ArrayBE, Octets, WireString, WithSize};
60use vls_protocol::{model, Error as ProtocolError};
61use vls_protocol_signer::util::commitment_type_to_channel_type;
62
63mod dyn_signer;
64pub mod signer_port;
65
66pub use dyn_signer::{DynKeysInterface, DynSigner, InnerSign, SpendableKeysInterface};
67use lightning_signer::lightning_invoice::RawBolt11Invoice;
68pub use signer_port::SignerPort;
69use vls_protocol::psbt::StreamedPSBT;
70
71#[derive(Debug, PartialEq)]
72pub enum Error {
73 Protocol(ProtocolError),
74 Transport,
75 TransportTransient,
76}
77
78pub type ClientResult<T> = Result<T, Error>;
79
80impl From<ProtocolError> for Error {
81 fn from(e: ProtocolError) -> Self {
82 Error::Protocol(e)
83 }
84}
85
86pub trait Transport: Send + Sync {
87 fn node_call(&self, message: Vec<u8>) -> Result<Vec<u8>, Error>;
89 fn call(&self, dbid: u64, peer_id: PubKey, message: Vec<u8>) -> Result<Vec<u8>, Error>;
91}
92
93struct SetupState {
98 done: bool,
99 deferred_validate: Option<ValidateCommitmentTx2>,
100}
101
102#[derive(Clone)]
103pub struct SignerClient {
104 transport: Arc<dyn Transport>,
105 peer_id: [u8; 33],
106 dbid: u64,
107 channel_keys: ChannelPublicKeys,
108 setup_state: Arc<Mutex<SetupState>>,
109}
110
111fn to_pubkey(pubkey: PublicKey) -> PubKey {
112 PubKey(pubkey.serialize())
113}
114
115fn to_bitcoin_sig(sig: &Signature) -> BitcoinSignature {
116 BitcoinSignature {
117 signature: model::Signature(sig.serialize_compact()),
118 sighash: EcdsaSighashType::All as u8,
119 }
120}
121
122pub fn call<T: SerBolt, R: DeBolt>(
123 dbid: u64,
124 peer_id: PubKey,
125 transport: &dyn Transport,
126 message: T,
127) -> Result<R, Error> {
128 assert_ne!(dbid, 0, "dbid 0 is reserved");
129 let message_ser = message.as_vec();
130 debug!("signer call {:?}", message);
131 let result_ser = transport.call(dbid, peer_id, message_ser)?;
132 let result = R::from_vec(result_ser)?;
133 debug!("signer result {:?}", result);
134 Ok(result)
135}
136
137pub fn node_call<T: SerBolt, R: DeBolt>(transport: &dyn Transport, message: T) -> Result<R, Error> {
138 debug!("signer call {:?}", message);
139 let message_ser = message.as_vec();
140 let result_ser = transport.node_call(message_ser)?;
141 let result = R::from_vec(result_ser)?;
142 debug!("signer result {:?}", result);
143 Ok(result)
144}
145
146fn to_htlcs(htlcs: &Vec<HTLCOutputInCommitment>, is_remote: bool) -> Array<Htlc> {
147 let htlcs = htlcs
148 .iter()
149 .map(|h| Htlc {
150 side: if h.offered != is_remote { Htlc::LOCAL } else { Htlc::REMOTE },
151 amount: h.amount_msat,
152 payment_hash: model::Sha256(h.payment_hash.0),
153 ctlv_expiry: h.cltv_expiry,
154 })
155 .collect();
156 Array(htlcs)
157}
158
159fn dest_wallet_path() -> ArrayBE<u32> {
160 let result = vec![1];
161 assert_eq!(result.len(), 1);
163 result.into()
164}
165
166impl SignerClient {
167 fn call<T: SerBolt, R: DeBolt>(&self, message: T) -> Result<R, Error> {
168 call(self.dbid, PubKey(self.peer_id), &*self.transport, message).map_err(|e| {
169 error!("transport error: {:?}", e);
170 e
171 })
172 }
173
174 fn new(
175 transport: Arc<dyn Transport>,
176 peer_id: [u8; 33],
177 dbid: u64,
178 channel_keys: ChannelPublicKeys,
179 ) -> Self {
180 SignerClient {
181 transport,
182 peer_id,
183 dbid,
184 channel_keys,
185 setup_state: Arc::new(Mutex::new(SetupState { done: false, deferred_validate: None })),
186 }
187 }
188}
189
190impl Writeable for SignerClient {
191 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), bitcoin::io::Error> {
192 self.peer_id.write(writer)?;
195 self.dbid.write(writer)?;
196 self.channel_keys.write(writer)?;
197 Ok(())
198 }
199}
200
201impl EcdsaChannelSigner for SignerClient {
202 fn sign_counterparty_commitment(
203 &self,
204 channel_parameters: &ChannelTransactionParameters,
205 commitment_tx: &CommitmentTransaction,
206 _preimages: Vec<PaymentPreimage>,
207 _preimages_ount: Vec<PaymentPreimage>,
208 _secp_ctx: &Secp256k1<All>,
209 ) -> Result<(Signature, Vec<Signature>), ()> {
210 self.ensure_channel_setup(channel_parameters)?;
211 let tx = commitment_tx.trust();
213 let htlcs = to_htlcs(tx.nondust_htlcs(), true);
214 let message = SignRemoteCommitmentTx2 {
215 remote_per_commitment_point: to_pubkey(tx.keys().per_commitment_point),
216 commitment_number: INITIAL_COMMITMENT_NUMBER - tx.commitment_number(),
217 feerate: tx.negotiated_feerate_per_kw(),
218 to_local_value_sat: tx.to_countersignatory_value_sat(),
219 to_remote_value_sat: tx.to_broadcaster_value_sat(),
220 htlcs,
221 };
222 let result: SignCommitmentTxWithHtlcsReply = self.call(message).map_err(|_| ())?;
223 let signature = Signature::from_compact(&result.signature.signature.0).map_err(|_| ())?;
224 let htlc_signatures = result
225 .htlc_signatures
226 .iter()
227 .map(|s| Signature::from_compact(&s.signature.0))
228 .collect::<Result<Vec<_>, _>>()
229 .map_err(|_| ())?;
230 Ok((signature, htlc_signatures))
231 }
232
233 fn sign_holder_commitment(
234 &self,
235 channel_parameters: &ChannelTransactionParameters,
236 commitment_tx: &HolderCommitmentTransaction,
237 _secp_ctx: &Secp256k1<All>,
238 ) -> Result<Signature, ()> {
239 self.ensure_channel_setup(channel_parameters)?;
240 let message = SignLocalCommitmentTx2 {
241 commitment_number: INITIAL_COMMITMENT_NUMBER - commitment_tx.commitment_number(),
242 };
243 let result: SignCommitmentTxReply = self.call(message).map_err(|_| ())?;
244 let signature = Signature::from_compact(&result.signature.signature.0).map_err(|_| ())?;
245 Ok(signature)
246 }
247
248 fn unsafe_sign_holder_commitment(
249 &self,
250 channel_parameters: &ChannelTransactionParameters,
251 commitment_tx: &HolderCommitmentTransaction,
252 secp_ctx: &Secp256k1<All>,
253 ) -> Result<Signature, ()> {
254 self.sign_holder_commitment(channel_parameters, commitment_tx, secp_ctx)
255 }
256
257 #[allow(unused)]
258 fn sign_justice_revoked_output(
259 &self,
260 _channel_parameters: &ChannelTransactionParameters,
261 justice_tx: &Transaction,
262 input: usize,
263 amount: u64,
264 per_commitment_key: &SecretKey,
265 _secp_ctx: &Secp256k1<All>,
266 ) -> Result<Signature, ()> {
267 todo!()
269 }
270
271 #[allow(unused)]
272 fn sign_justice_revoked_htlc(
273 &self,
274 _channel_parameters: &ChannelTransactionParameters,
275 justice_tx: &Transaction,
276 input: usize,
277 amount: u64,
278 per_commitment_key: &SecretKey,
279 htlc: &HTLCOutputInCommitment,
280 _secp_ctx: &Secp256k1<All>,
281 ) -> Result<Signature, ()> {
282 todo!()
284 }
285
286 fn sign_holder_htlc_transaction(
287 &self,
288 htlc_tx: &Transaction,
289 input: usize,
290 htlc_descriptor: &HTLCDescriptor,
291 _secp_ctx: &Secp256k1<All>,
292 ) -> Result<Signature, ()> {
293 let htlc = &htlc_descriptor.htlc;
294 let message = SignLocalHtlcTx2 {
295 per_commitment_number: htlc_descriptor.per_commitment_number,
296 offered: htlc.offered,
297 cltv_expiry: htlc.cltv_expiry,
298 tx: WithSize(htlc_tx.clone()),
299 input: input as u32,
300 payment_hash: model::Sha256(htlc.payment_hash.0),
301 htlc_amount_msat: htlc_descriptor.htlc.amount_msat,
302 };
303 let result: SignTxReply = self.call(message).map_err(|_| ())?;
304 Ok(Signature::from_compact(&result.signature.signature.0).unwrap())
305 }
306
307 #[allow(unused)]
308 fn sign_counterparty_htlc_transaction(
309 &self,
310 _channel_parameters: &ChannelTransactionParameters,
311 htlc_tx: &Transaction,
312 input: usize,
313 amount: u64,
314 per_commitment_point: &PublicKey,
315 htlc: &HTLCOutputInCommitment,
316 _secp_ctx: &Secp256k1<All>,
317 ) -> Result<Signature, ()> {
318 todo!()
320 }
321
322 fn sign_closing_transaction(
323 &self,
324 channel_parameters: &ChannelTransactionParameters,
325 tx: &ClosingTransaction,
326 _secp_ctx: &Secp256k1<All>,
327 ) -> Result<Signature, ()> {
328 self.ensure_channel_setup(channel_parameters)?;
329 let message = SignMutualCloseTx2 {
330 to_local_value_sat: tx.to_holder_value_sat(),
331 to_remote_value_sat: tx.to_counterparty_value_sat(),
332 local_script: tx.to_holder_script().to_bytes().into(),
333 remote_script: tx.to_counterparty_script().to_bytes().into(),
334 local_wallet_path_hint: dest_wallet_path(),
335 };
336 let result: SignTxReply = self.call(message).map_err(|_| ())?;
337 Ok(Signature::from_compact(&result.signature.signature.0).unwrap())
338 }
339
340 fn sign_holder_keyed_anchor_input(
341 &self,
342 _channel_parameters: &ChannelTransactionParameters,
343 _anchor_tx: &Transaction,
344 _input: usize,
345 _secp_ctx: &Secp256k1<All>,
346 ) -> Result<Signature, ()> {
347 todo!()
348 }
349
350 fn sign_channel_announcement_with_funding_key(
351 &self,
352 channel_parameters: &ChannelTransactionParameters,
353 msg: &UnsignedChannelAnnouncement,
354 _secp_ctx: &Secp256k1<All>,
355 ) -> Result<Signature, ()> {
356 self.ensure_channel_setup(channel_parameters)?;
357 let mut announcement = [0u8; 258].to_vec();
359 announcement.extend(msg.encode());
360 let message = SignChannelAnnouncement { announcement: announcement.into() };
361 let result: SignChannelAnnouncementReply = self.call(message).map_err(|_| ())?;
362 Ok(Signature::from_compact(&result.bitcoin_signature.0).unwrap())
363 }
364
365 fn sign_splice_shared_input(
366 &self,
367 _channel_parameters: &ChannelTransactionParameters,
368 _tx: &Transaction,
369 _input_index: usize,
370 _secp_ctx: &Secp256k1<All>,
371 ) -> Signature {
372 todo!("sign_splice_shared_input - #538")
373 }
374}
375
376impl ChannelSigner for SignerClient {
377 fn get_per_commitment_point(
378 &self,
379 idx: u64,
380 _secp_ctx: &Secp256k1<All>,
381 ) -> Result<PublicKey, ()> {
382 let message = GetPerCommitmentPoint2 { commitment_number: INITIAL_COMMITMENT_NUMBER - idx };
383 let result: GetPerCommitmentPoint2Reply =
384 self.call(message).expect("get_per_commitment_point");
385 Ok(PublicKey::from_slice(&result.point.0).expect("public key"))
386 }
387
388 fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey) -> Result<(), ()> {
389 let message = ValidateRevocation {
390 commitment_number: INITIAL_COMMITMENT_NUMBER - idx,
391 commitment_secret: DisclosedSecret(secret[..].try_into().unwrap()),
392 };
393 let _: ValidateRevocationReply = self.call(message).map_err(|_| ())?;
394 Ok(())
395 }
396
397 fn release_commitment_secret(&self, idx: u64) -> Result<[u8; 32], ()> {
398 let message =
400 GetPerCommitmentPoint { commitment_number: INITIAL_COMMITMENT_NUMBER - idx + 2 };
401 let result: GetPerCommitmentPointReply =
402 self.call(message).expect("get_per_commitment_point");
403 let secret = result.secret.expect("secret not released");
404 Ok(secret.0)
405 }
406
407 fn validate_holder_commitment(
408 &self,
409 holder_tx: &HolderCommitmentTransaction,
410 _outbound_htlc_preimages: Vec<PaymentPreimage>,
411 ) -> Result<(), ()> {
412 let tx = holder_tx.trust();
414 let htlcs = to_htlcs(tx.nondust_htlcs(), false);
415 let message = ValidateCommitmentTx2 {
416 commitment_number: INITIAL_COMMITMENT_NUMBER - tx.commitment_number(),
417 feerate: tx.negotiated_feerate_per_kw(),
418 to_local_value_sat: tx.to_broadcaster_value_sat(),
419 to_remote_value_sat: tx.to_countersignatory_value_sat(),
420 htlcs,
421 signature: to_bitcoin_sig(&holder_tx.counterparty_sig),
422 htlc_signatures: Array(
423 holder_tx.counterparty_htlc_sigs.iter().map(|s| to_bitcoin_sig(s)).collect(),
424 ),
425 };
426 {
432 let mut state = self.setup_state.lock().unwrap();
433 if !state.done {
434 if state.deferred_validate.is_some() {
439 debug_assert!(false, "validate_holder_commitment called twice before setup");
440 error!("validate_holder_commitment called twice before setup");
441 return Err(());
442 }
443 state.deferred_validate = Some(message);
444 return Ok(());
445 }
446 }
447 let _: ValidateCommitmentTxReply = self.call(message).map_err(|_| ())?;
448 Ok(())
449 }
450
451 fn pubkeys(&self, _secp_ctx: &Secp256k1<All>) -> ChannelPublicKeys {
452 self.channel_keys.clone()
453 }
454
455 fn new_funding_pubkey(
456 &self,
457 _splice_parent_funding_txid: bitcoin::Txid,
458 _secp_ctx: &Secp256k1<All>,
459 ) -> PublicKey {
460 todo!("new_funding_pubkey for splicing - #538")
464 }
465
466 fn channel_keys_id(&self) -> [u8; 32] {
467 ChannelId::new_from_oid(self.dbid).ldk_channel_keys_id()
468 }
469}
470
471impl SignerClient {
472 fn ensure_channel_setup(&self, p: &ChannelTransactionParameters) -> Result<(), ()> {
485 let mut state = self.setup_state.lock().unwrap();
486 if state.done {
487 return Ok(());
488 }
489 self.do_setup_channel(p)?;
490 if let Some(message) = state.deferred_validate.clone() {
493 let _: ValidateCommitmentTxReply = self.call(message).map_err(|_| ())?;
494 state.deferred_validate = None;
495 }
496 state.done = true;
497 Ok(())
498 }
499
500 fn do_setup_channel(&self, p: &ChannelTransactionParameters) -> Result<(), ()> {
501 let funding = p.funding_outpoint.ok_or(())?;
502 let cp = p.counterparty_parameters.as_ref().ok_or(())?;
503
504 let features = &p.channel_type_features;
505 let commitment_type = if features.supports_anchors_zero_fee_htlc_tx() {
506 CommitmentType::AnchorsZeroFeeHtlc
507 } else if features.supports_anchors_nonzero_fee_htlc_tx() {
508 CommitmentType::Anchors
511 } else {
512 CommitmentType::StaticRemoteKey
513 };
514
515 let ser_channel_type = commitment_type_to_channel_type(commitment_type);
516 let message = SetupChannel {
517 is_outbound: p.is_outbound_from_holder,
518 channel_value: p.channel_value_satoshis,
519 push_value: 0, funding_txid: funding.txid,
521 funding_txout: funding.index,
522 to_self_delay: p.holder_selected_contest_delay,
523 local_shutdown_script: Octets::EMPTY, local_shutdown_wallet_index: None,
525 remote_basepoints: Basepoints {
526 revocation: to_pubkey(cp.pubkeys.revocation_basepoint.0),
527 payment: to_pubkey(cp.pubkeys.payment_point),
528 htlc: to_pubkey(cp.pubkeys.htlc_basepoint.0),
529 delayed_payment: to_pubkey(cp.pubkeys.delayed_payment_basepoint.0),
530 },
531 remote_funding_pubkey: to_pubkey(cp.pubkeys.funding_pubkey),
532 remote_to_self_delay: cp.selected_contest_delay,
533 remote_shutdown_script: Octets::EMPTY, channel_type: ser_channel_type.into(),
535 };
536
537 let _: SetupChannelReply = self.call(message).map_err(|_| ())?;
538 Ok(())
539 }
540}
541
542pub struct KeysManagerClient {
543 transport: Arc<dyn Transport>,
544 next_dbid: AtomicU64,
545 key_material: ExpandedKey,
546 xpub: Xpub,
547 node_id: PublicKey,
548 peer_storage_key: lightning::sign::PeerStorageKey,
549 receive_auth_key: lightning::sign::ReceiveAuthKey,
550}
551
552impl KeysManagerClient {
553 pub fn new(
568 transport: Arc<dyn Transport>,
569 network: String,
570 key_derivation_style: Option<KeyDerivationStyle>,
571 dev_allowlist: Option<Array<WireString>>,
572 receive_auth_key: lightning::sign::ReceiveAuthKey,
573 ) -> Self {
574 let key_derivation_style = key_derivation_style.unwrap_or(KeyDerivationStyle::Native);
575
576 #[cfg(not(feature = "developer"))]
577 assert!(dev_allowlist.is_none(), "dev_allowlist is only available in developer mode");
578
579 #[cfg(feature = "developer")]
580 if let Some(allowlist) = dev_allowlist {
581 let preinit_message = HsmdDevPreinit {
582 derivation_style: key_derivation_style as u8,
583 network_name: WireString(network.clone().into_bytes()),
584 seed: None,
585 allowlist,
586 };
587 let _: HsmdDevPreinitReply =
588 node_call(&*transport, preinit_message).expect("HsmdDevPreinit should succeed");
589 }
590
591 let init_message = HsmdInit2 {
592 derivation_style: key_derivation_style as u8,
593 network_name: WireString(network.into_bytes()),
594 dev_seed: None,
595 dev_allowlist: Array::new(),
596 };
597 let result: HsmdInit2Reply = node_call(&*transport, init_message).expect("HsmdInit");
598 let xpub = Xpub::decode(&result.bip32.0).expect("xpub");
599 let node_id = PublicKey::from_slice(&result.node_id.0).expect("node id");
600 let peer_storage_key = lightning::sign::PeerStorageKey { inner: result.peer_storage_key.0 };
601
602 Self {
603 transport,
604 next_dbid: AtomicU64::new(1),
605 key_material: ExpandedKey::new(result.inbound_payment_key.0),
606 xpub,
607 node_id,
608 peer_storage_key,
609 receive_auth_key,
610 }
611 }
612
613 pub fn call<T: SerBolt, R: DeBolt>(&self, message: T) -> Result<R, Error> {
614 node_call(&*self.transport, message)
615 }
616
617 fn get_channel_basepoints(&self, dbid: u64, peer_id: [u8; 33]) -> ChannelPublicKeys {
618 let message = GetChannelBasepoints { node_id: PubKey(peer_id), dbid };
619 let result: GetChannelBasepointsReply = self.call(message).expect("pubkeys");
620 let channel_keys = ChannelPublicKeys {
621 funding_pubkey: result.funding.into(),
622 revocation_basepoint: result.basepoints.revocation.into(),
623 payment_point: result.basepoints.payment.into(),
624 delayed_payment_basepoint: result.basepoints.delayed_payment.into(),
625 htlc_basepoint: result.basepoints.htlc.into(),
626 };
627 channel_keys
628 }
629
630 pub fn sign_onchain_tx(
631 &self,
632 tx: &Transaction,
633 descriptors: &[&SpendableOutputDescriptor],
634 ) -> Vec<Vec<Vec<u8>>> {
635 assert_eq!(tx.input.len(), descriptors.len());
636
637 let mut psbt = Psbt::from_unsigned_tx(tx.clone()).expect("create PSBT");
638 for i in 0..psbt.inputs.len() {
639 psbt.inputs[i].witness_utxo = Self::descriptor_to_txout(descriptors[i]);
640 }
641
642 let streamed_psbt = StreamedPSBT::new(psbt).into();
643 let utxos = Array(descriptors.into_iter().map(|d| Self::descriptor_to_utxo(*d)).collect());
644
645 let message = SignWithdrawal { utxos, psbt: streamed_psbt };
646 let result: SignWithdrawalReply = self.call(message).expect("sign failed");
647 let psbt = result.psbt.0.inner;
648 psbt.inputs.into_iter().map(|i| i.final_script_witness.unwrap().to_vec()).collect()
649 }
650
651 fn descriptor_to_txout(d: &SpendableOutputDescriptor) -> Option<TxOut> {
652 match d {
653 SpendableOutputDescriptor::StaticOutput { output, .. } => Some(output.clone()),
654 SpendableOutputDescriptor::DelayedPaymentOutput(o) => Some(o.output.clone()),
655 SpendableOutputDescriptor::StaticPaymentOutput(o) => Some(o.output.clone()),
656 }
657 }
658
659 fn descriptor_to_utxo(d: &SpendableOutputDescriptor) -> Utxo {
660 let (outpoint, amount, keyindex, close_info) = match d {
661 SpendableOutputDescriptor::StaticOutput { output, outpoint, .. } =>
663 (outpoint.clone(), output.value, dest_wallet_path()[0], None), SpendableOutputDescriptor::DelayedPaymentOutput(o) => (
666 o.outpoint,
667 o.output.value,
668 0,
669 Some(CloseInfo {
670 channel_id: ChannelId::new(&o.channel_keys_id).oid(),
671 peer_id: PubKey([0; 33]),
672 commitment_point: Some(to_pubkey(o.per_commitment_point)),
673 is_anchors: false,
674 csv: o.to_self_delay as u32,
675 }),
676 ),
677 SpendableOutputDescriptor::StaticPaymentOutput(o) => (
679 o.outpoint,
680 o.output.value,
681 0,
682 Some(CloseInfo {
683 channel_id: ChannelId::new(&o.channel_keys_id).oid(),
684 peer_id: PubKey([0; 33]),
685 commitment_point: None,
686 is_anchors: false,
687 csv: 0,
688 }),
689 ),
690 };
691 let is_in_coinbase = false; Utxo {
693 txid: outpoint.txid,
694 outnum: outpoint.index as u32,
695 amount: amount.to_sat(),
696 keyindex,
697 is_p2sh: false,
698 script: Octets::EMPTY,
699 close_info,
700 is_in_coinbase,
701 }
702 }
703}
704
705impl EntropySource for KeysManagerClient {
706 fn get_secure_random_bytes(&self) -> [u8; 32] {
707 let result: GetSecureRandomBytesReply =
708 self.call(GetSecureRandomBytes {}).expect("signer must provide secure random bytes");
709
710 result.random_bytes.0
711 }
712}
713
714impl NodeSigner for KeysManagerClient {
715 fn get_expanded_key(&self) -> ExpandedKey {
716 self.key_material
717 }
718
719 fn get_peer_storage_key(&self) -> lightning::sign::PeerStorageKey {
720 self.peer_storage_key
721 }
722
723 fn get_receive_auth_key(&self) -> lightning::sign::ReceiveAuthKey {
724 self.receive_auth_key
725 }
726
727 fn sign_message(&self, msg: &[u8]) -> Result<String, ()> {
728 let reply: SignMessageReply =
729 self.call(SignMessage { message: msg.to_vec().into() }).map_err(|_| ())?;
730 Ok(lightning_signer::util::crypto_utils::encode_signed_message(&reply.signature.0))
733 }
734
735 fn get_node_id(&self, recipient: Recipient) -> Result<PublicKey, ()> {
736 match recipient {
737 Recipient::Node => {}
738 Recipient::PhantomNode => {
739 unimplemented!("phantom nodes not supported")
740 }
741 }
742 Ok(self.node_id)
743 }
744
745 fn ecdh(
746 &self,
747 recipient: Recipient,
748 other_key: &PublicKey,
749 tweak: Option<&Scalar>,
750 ) -> Result<SharedSecret, ()> {
751 match recipient {
752 Recipient::Node => {}
753 Recipient::PhantomNode => unimplemented!("PhantomNode"),
754 }
755
756 if tweak.is_some() {
757 unimplemented!("tweak is not supported");
758 }
759 let message = Ecdh { point: PubKey(other_key.serialize()) };
760 let result: EcdhReply = self.call(message).expect("ecdh");
761 Ok(SharedSecret::from_bytes(result.secret.0))
762 }
763
764 fn sign_invoice(
765 &self,
766 invoice: &RawBolt11Invoice,
767 recipient: Recipient,
768 ) -> Result<RecoverableSignature, ()> {
769 match recipient {
770 Recipient::Node => {}
771 Recipient::PhantomNode => {
772 unimplemented!("phantom nodes not supported")
773 }
774 }
775 let (hrp, invoice_data) = invoice.to_raw();
776 let hrp_bytes = hrp.into_bytes();
777
778 let message = SignInvoice {
779 u5bytes: Octets(invoice_data.iter().map(|u| u.to_u8()).collect()),
780 hrp: hrp_bytes.into(),
781 };
782 let result: SignInvoiceReply = self.call(message).expect("sign_invoice");
783 let rid = RecoveryId::from_i32(result.signature.0[64] as i32).expect("recovery ID");
784 let sig = &result.signature.0[0..64];
785 RecoverableSignature::from_compact(sig, rid).map_err(|_| ())
786 }
787
788 fn sign_bolt12_invoice(
789 &self,
790 invoice: &lightning::offers::invoice::UnsignedBolt12Invoice,
791 ) -> Result<bitcoin::secp256k1::schnorr::Signature, ()> {
792 let mut bytes = Vec::new();
793 invoice.write(&mut bytes).map_err(|_| ())?;
794
795 let message = SignBolt12Invoice { invoice_bytes: Octets(bytes) };
796 let result: SignBolt12InvoiceReply = self.call(message).expect("sign_bolt12_invoice");
797
798 bitcoin::secp256k1::schnorr::Signature::from_slice(&result.signature.0).map_err(|_| ())
799 }
800
801 fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
802 let message = SignGossipMessage { message: Octets(msg.encode()) };
803 let result: SignGossipMessageReply = self.call(message).expect("sign_gossip_message");
804 Ok(Signature::from_compact(&result.signature.0).expect("signature"))
805 }
806}
807
808impl SignerProvider for KeysManagerClient {
809 type EcdsaSigner = SignerClient;
810
811 fn generate_channel_keys_id(&self, _inbound: bool, _user_channel_id: u128) -> [u8; 32] {
812 let dbid = self.next_dbid.fetch_add(1, Ordering::AcqRel);
813 ChannelId::new_from_oid(dbid).ldk_channel_keys_id()
814 }
815
816 fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> Self::EcdsaSigner {
817 let peer_id = [0u8; 33];
820 let dbid = ChannelId::new(&channel_keys_id).oid();
821
822 let message = NewChannel { peer_id: PubKey(peer_id.clone()), dbid };
823 let _: NewChannelReply = self.call(message).expect("NewChannel");
824
825 let channel_keys = self.get_channel_basepoints(dbid, peer_id);
826
827 SignerClient::new(self.transport.clone(), peer_id, dbid, channel_keys)
828 }
829
830 fn get_destination_script(&self, _: [u8; 32]) -> Result<ScriptBuf, ()> {
831 let secp_ctx = Secp256k1::new();
832 let wallet_path = dest_wallet_path();
833 let mut key = self.xpub;
834 for i in wallet_path.iter() {
835 key = key.ckd_pub(&secp_ctx, ChildNumber::from_normal_idx(*i).unwrap()).unwrap();
836 }
837 let pubkey = key.public_key;
838 Ok(ScriptBuf::new_p2wpkh(&WPubkeyHash::hash(&pubkey.serialize())))
839 }
840
841 fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
842 Ok(ShutdownScript::try_from(self.get_destination_script([0; 32])?).expect("script"))
843 }
844}
845
846impl OutputSpender for KeysManagerClient {
847 fn spend_spendable_outputs(
848 &self,
849 descriptors: &[&SpendableOutputDescriptor],
850 outputs: Vec<TxOut>,
851 change_destination_script: ScriptBuf,
852 feerate_sat_per_1000_weight: u32,
853 locktime: Option<LockTime>,
854 _secp_ctx: &Secp256k1<All>,
855 ) -> Result<Transaction, ()> {
856 let mut tx = create_spending_transaction(
857 descriptors,
858 outputs,
859 change_destination_script,
860 feerate_sat_per_1000_weight,
861 )
862 .unwrap();
863 tx.lock_time = locktime.unwrap_or(LockTime::ZERO);
864 let witnesses = self.sign_onchain_tx(&tx, descriptors);
865 for (idx, w) in witnesses.into_iter().enumerate() {
866 tx.input[idx].witness = Witness::from_slice(&w);
867 }
868 Ok(tx)
869 }
870}
871
872impl InnerSign for SignerClient {
873 fn box_clone(&self) -> Box<dyn InnerSign> {
874 Box::new(self.clone())
875 }
876
877 fn as_any(&self) -> &dyn Any {
878 self
879 }
880
881 fn vwrite(&self, writer: &mut Vec<u8>) -> Result<(), bitcoin::io::Error> {
882 self.write(writer)
883 }
884}
885
886#[cfg(test)]
887mod tests {
888 use super::*;
889 use bitcoin::bip32::Xpub;
890 use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
891 use lightning::ln::inbound_payment::ExpandedKey;
892 use mockall::mock;
893 use std::sync::atomic::AtomicU64;
894 use std::sync::Arc;
895 use vls_protocol::model::{PubKey, Secret};
896 use vls_protocol::msgs::{self, GetSecureRandomBytesReply, Message, SerBolt};
897
898 mock! {
899 pub TestTransport {}
900 impl Transport for TestTransport {
901 fn node_call(&self, message: Vec<u8>) -> Result<Vec<u8>, Error>;
902 fn call(&self, dbid: u64, peer_id: PubKey, message: Vec<u8>) -> Result<Vec<u8>, Error>;
903 }
904 }
905
906 fn make_test_keys_manager_client(transport: Arc<MockTestTransport>) -> KeysManagerClient {
907 let secp_ctx = Secp256k1::new();
908 let sk = SecretKey::from_slice(&[1; 32]).unwrap();
909 let pk = PublicKey::from_secret_key(&secp_ctx, &sk);
910 let xpriv = bitcoin::bip32::Xpriv::new_master(bitcoin::Network::Testnet, &[1; 32]).unwrap();
911 let xpub = Xpub::from_priv(&secp_ctx, &xpriv);
912
913 KeysManagerClient {
914 transport,
915 next_dbid: AtomicU64::new(1),
916 key_material: ExpandedKey::new([1; 32]),
917 xpub,
918 node_id: pk,
919 peer_storage_key: lightning::sign::PeerStorageKey { inner: [2; 32] },
920 receive_auth_key: lightning::sign::ReceiveAuthKey([3; 32]),
921 }
922 }
923
924 #[test]
925 fn test_get_secure_random_bytes() {
926 let mut mock_transport = MockTestTransport::new();
927
928 mock_transport.expect_node_call().times(1).returning(|message| {
929 let msg = msgs::from_vec(message).unwrap();
930 assert!(matches!(msg, Message::GetSecureRandomBytes(_)));
931
932 Ok(GetSecureRandomBytesReply { random_bytes: Secret([42u8; 32]) }.as_vec())
933 });
934
935 let kmc = make_test_keys_manager_client(Arc::new(mock_transport));
936 let bytes = kmc.get_secure_random_bytes();
937
938 assert_eq!(bytes, [42u8; 32]);
939 }
940
941 #[test]
942 fn test_sign_bolt12_invoice() {
943 let mut mock_transport = MockTestTransport::new();
944
945 mock_transport.expect_node_call().times(1).returning(|message| {
946 let msg = msgs::from_vec(message).unwrap();
947 assert!(matches!(msg, Message::SignBolt12Invoice(_)));
948
949 let fake_sig = vls_protocol::model::Signature([0xABu8; 64]);
950 Ok(msgs::SignBolt12InvoiceReply { signature: fake_sig }.as_vec())
951 });
952
953 let kmc = make_test_keys_manager_client(Arc::new(mock_transport));
954
955 let fake_invoice_bytes = vec![0x01, 0x02, 0x03, 0x04];
956 let message = msgs::SignBolt12Invoice { invoice_bytes: Octets(fake_invoice_bytes) };
957 let msg_bytes = message.as_vec();
958
959 let response = kmc.transport.node_call(msg_bytes).unwrap();
960 let reply: Message = msgs::from_vec(response).unwrap();
961
962 match reply {
963 Message::SignBolt12InvoiceReply(r) => {
964 assert_eq!(r.signature.0, [0xABu8; 64]);
965 }
966 _ => panic!("expected SignBolt12InvoiceReply"),
967 }
968 }
969}