Skip to main content

vls_protocol_client/
lib.rs

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    /// Perform a call for the node API
88    fn node_call(&self, message: Vec<u8>) -> Result<Vec<u8>, Error>;
89    /// Perform a call for the channel API
90    fn call(&self, dbid: u64, peer_id: PubKey, message: Vec<u8>) -> Result<Vec<u8>, Error>;
91}
92
93/// Tracks lazy SetupChannel state. LDK 0.2 removed `provide_channel_parameters`
94/// from `ChannelSigner`, so we send `SetupChannel` to the signer on the first
95/// signing call instead. On the inbound side, `validate_holder_commitment` is
96/// called before any signing op, so we defer it here and replay after setup.
97struct 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    // elsewhere we assume that the path has a single component
162    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        // LDK 0.2 dropped `read_chan_signer` from `SignerProvider`, so this
193        // never round-trips. The impl is required for trait bounds only.
194        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        // TODO preimage handling
212        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        // onchain
268        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        // onchain
283        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        // onchain
319        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        // Prepend a fake prefix to match CLN behavior
358        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        // Getting the point at idx + 2 releases the secret at idx
399        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        // TODO preimage handling
413        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        // On the inbound side, this is called before SetupChannel; defer and
427        // replay after setup completes. Holding the lock through the check +
428        // insert keeps it atomic with the setup-completion in
429        // `ensure_channel_setup`, so we never insert into a slot that has
430        // already been drained.
431        {
432            let mut state = self.setup_state.lock().unwrap();
433            if !state.done {
434                // Only one validation can be deferred: overwriting would silently drop a holder
435                // commitment the signer never saw. Unreachable in practice (the first signing op
436                // completes setup before a second `commitment_signed`), so fail the call rather
437                // than lose it — LDK closes the channel instead of proceeding unvalidated.
438                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        // Splicing needs a fresh funding pubkey; returning the original would be silently
461        // wrong. Splicing is unsupported (#538) and rejected before any signer call, so this
462        // is unreachable — panic rather than hand back an incorrect key if that ever changes.
463        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    /// Ensure channel parameters have been sent to the signer. Called lazily
473    /// on the first signing operation. Holds the setup lock across both the
474    /// `SetupChannel` round-trip and the deferred replay so that other
475    /// callers block until the signer is ready, preventing them from
476    /// sending sign requests against an unset-up channel.
477    /// Errors are returned rather than panicking: the deferred `validate_holder_commitment`
478    /// replay is driven by counterparty-supplied data, so the signer can legitimately reject it
479    /// (e.g. a malformed or policy-violating commitment from the peer). Propagating lets the
480    /// calling signing op fail — and LDK close the channel — instead of crashing the node.
481    ///
482    /// On failure `done` stays false and the deferred message is retained, so a later signing op
483    /// retries both the setup and the replay.
484    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        // Clone rather than `take` so a failed replay leaves the message in place: `done` stays
491        // false and a later signing op retries it, instead of dropping it on the floor.
492        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            // simple_validator::validate_setup_channel will
509            // stop non zero anchors fee with `policy-channel-safe-type`
510            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, // TODO
520            funding_txid: funding.txid,
521            funding_txout: funding.index,
522            to_self_delay: p.holder_selected_contest_delay,
523            local_shutdown_script: Octets::EMPTY, // TODO
524            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, // TODO
534            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    /// Create a new VLS client with the given transport.
554    ///
555    /// `receive_auth_key` is the LDK 0.2 blinded-path MAC key. Its only
556    /// requirement is to be consistent across invocations, so the caller is
557    /// responsible for generating it (e.g. on first run) and persisting it
558    /// in its own state — see `NodeSigner::get_receive_auth_key` in LDK.
559    /// The signer does not provide it, since any caller with persistence
560    /// can.
561    ///
562    /// `peer_storage_key` and the inbound-payment `ExpandedKey` seed are in
563    /// contrast obtained from the signer's `HsmdInit2Reply`: LDK requires them
564    /// to be stable across restarts (state-loss recovery, and receivable
565    /// invoices respectively) and the signer is the only place that holds the
566    /// seed they derive from.
567    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            // Mutual close - we are spending a non-delayed output to us on the shutdown key
662            SpendableOutputDescriptor::StaticOutput { output, outpoint, .. } =>
663                (outpoint.clone(), output.value, dest_wallet_path()[0], None), // FIXME this makes some assumptions
664            // We force-closed - we are spending a delayed output to us
665            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            // Remote force-closed - we are spending an non-delayed output to us
678            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; // FIXME - set this for real
692        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        // The signer returns a 64-byte compact signature followed by the raw recovery id; encode
731        // it as the lnd / core-lightning zbase32 string LDK expects.
732        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        // We don't use the peer_id, because it's not easy to get at this point within the LDK framework.
818        // The dbid is unique, so that's enough for our purposes.
819        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}