X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fkeysinterface.rs;h=f2d198bbfa101d97d129c251381a637a76aaf348;hb=4a0010d7393bb32305bdb3d859735b7b563462eb;hp=dffe060d91bb71a5f33e8c023de6cac94fb9826d;hpb=482a2b9250679abb3c9931497b2324799fbfa087;p=rust-lightning diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index dffe060d..f2d198bb 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -11,12 +11,12 @@ //! spendable on-chain outputs which the user owns and is responsible for using just as any other //! on-chain output which is theirs. -use bitcoin::blockdata::transaction::{Transaction, TxOut, TxIn, SigHashType}; +use bitcoin::blockdata::transaction::{Transaction, TxOut, TxIn, EcdsaSighashType}; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; use bitcoin::network::constants::Network; use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber}; -use bitcoin::util::bip143; +use bitcoin::util::sighash; use bitcoin::bech32::u5; use bitcoin::hashes::{Hash, HashEngine}; @@ -25,25 +25,30 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::WPubkeyHash; -use bitcoin::secp256k1::key::{SecretKey, PublicKey}; -use bitcoin::secp256k1::{Secp256k1, Signature, Signing}; -use bitcoin::secp256k1::recovery::RecoverableSignature; -use bitcoin::secp256k1; - -use util::{byte_utils, transaction_utils}; -use util::ser::{Writeable, Writer, Readable, ReadableArgs}; - -use chain::transaction::OutPoint; -use ln::{chan_utils, PaymentPreimage}; -use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction}; -use ln::msgs::UnsignedChannelAnnouncement; -use ln::script::ShutdownScript; - -use prelude::*; +use bitcoin::secp256k1::{SecretKey, PublicKey, Scalar}; +use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature, Signing}; +use bitcoin::secp256k1::ecdh::SharedSecret; +use bitcoin::secp256k1::ecdsa::RecoverableSignature; +use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; + +use crate::util::transaction_utils; +use crate::util::crypto::{hkdf_extract_expand_twice, sign}; +use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs}; +#[cfg(anchors)] +use crate::util::events::HTLCDescriptor; +use crate::chain::transaction::OutPoint; +use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; +use crate::ln::{chan_utils, PaymentPreimage}; +use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction}; +use crate::ln::msgs::UnsignedChannelAnnouncement; +use crate::ln::script::ShutdownScript; + +use crate::prelude::*; +use core::convert::TryInto; use core::sync::atomic::{AtomicUsize, Ordering}; -use io::{self, Error}; -use ln::msgs::{DecodeError, MAX_VALUE_MSAT}; -use util::invoice::construct_invoice_preimage; +use crate::io::{self, Error}; +use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; +use crate::util::invoice::construct_invoice_preimage; /// Used as initial key material, to be expanded into multiple secret keys (but not to be used /// directly). This is used within LDK to encrypt/decrypt inbound payment data. @@ -53,7 +58,7 @@ pub struct KeyMaterial(pub [u8; 32]); /// Information about a spendable output to a P2WSH script. See /// SpendableOutputDescriptor::DelayedPaymentOutput for more details on how to spend this. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct DelayedPaymentOutputDescriptor { /// The outpoint which is spendable pub outpoint: OutPoint, @@ -93,7 +98,7 @@ impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, { /// Information about a spendable output to our "payment key". See /// SpendableOutputDescriptor::StaticPaymentOutput for more details on how to spend this. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct StaticPaymentOutputDescriptor { /// The outpoint which is spendable pub outpoint: OutPoint, @@ -124,7 +129,7 @@ impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, { /// spend on-chain. The information needed to do this is provided in this enum, including the /// outpoint describing which txid and output index is available, the full output which exists at /// that txid/index, and any keys or other information required to sign. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum SpendableOutputDescriptor { /// An output to a script which was provided via KeysInterface directly, either from /// `get_destination_script()` or `get_shutdown_scriptpubkey()`, thus you should already know @@ -158,7 +163,7 @@ pub enum SpendableOutputDescriptor { /// /// To derive the revocation_pubkey provided here (which is used in the witness /// script generation), you must pass the counterparty revocation_basepoint (which appears in the - /// call to Sign::ready_channel) and the provided per_commitment point + /// call to Sign::provide_channel_parameters) and the provided per_commitment point /// to chan_utils::derive_public_revocation_key. /// /// The witness script which is hashed and included in the output script_pubkey may be @@ -321,6 +326,19 @@ pub trait BaseSign { /// (which is committed to in the BIP 143 signatures). fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result; + #[cfg(anchors)] + /// Computes the signature for a commitment transaction's HTLC output used as an input within + /// `htlc_tx`, which spends the commitment transaction, at index `input`. The signature returned + /// must be be computed using [`EcdsaSighashType::All`]. Note that this should only be used to + /// sign HTLC transactions from channels supporting anchor outputs after all additional + /// inputs/outputs have been added to the transaction. + /// + /// [`EcdsaSighashType::All`]: bitcoin::blockdata::transaction::EcdsaSighashType::All + fn sign_holder_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, + secp_ctx: &Secp256k1 + ) -> Result; + /// Create a signature for a claiming transaction for a HTLC output on a counterparty's commitment /// transaction, either offered or received. /// @@ -346,6 +364,12 @@ pub trait BaseSign { /// chosen to forgo their output as dust. fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1) -> Result; + /// Computes the signature for a commitment transaction's anchor output used as an + /// input within `anchor_tx`, which spends the commitment transaction, at index `input`. + fn sign_holder_anchor_input( + &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + ) -> Result; + /// Signs a channel announcement message with our funding key and our node secret key (aka /// node_id or network_key), proving it comes from one of the channel participants. /// @@ -359,35 +383,71 @@ pub trait BaseSign { -> Result<(Signature, Signature), ()>; /// Set the counterparty static channel data, including basepoints, - /// counterparty_selected/holder_selected_contest_delay and funding outpoint. - /// This is done as soon as the funding outpoint is known. Since these are static channel data, - /// they MUST NOT be allowed to change to different values once set. + /// counterparty_selected/holder_selected_contest_delay and funding outpoint. Since these are + /// static channel data, they MUST NOT be allowed to change to different values once set, as LDK + /// may call this method more than once. /// /// channel_parameters.is_populated() MUST be true. - /// - /// We bind holder_selected_contest_delay late here for API convenience. - /// - /// Will be called before any signatures are applied. - fn ready_channel(&mut self, channel_parameters: &ChannelTransactionParameters); + fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); } -/// A cloneable signer. +/// A writeable signer. +/// +/// There will always be two instances of a signer per channel, one occupied by the +/// [`ChannelManager`] and another by the channel's [`ChannelMonitor`]. /// -/// Although we require signers to be cloneable, it may be useful for developers to be able to use -/// signers in an un-sized way, for example as `dyn BaseSign`. Therefore we separate the Clone trait, -/// which implies Sized, into this derived trait. -pub trait Sign: BaseSign + Writeable + Clone { +/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager +/// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor +pub trait Sign: BaseSign + Writeable { +} + +/// Specifies the recipient of an invoice, to indicate to [`KeysInterface::sign_invoice`] what node +/// secret key should be used to sign the invoice. +pub enum Recipient { + /// The invoice should be signed with the local node secret key. + Node, + /// The invoice should be signed with the phantom node secret key. This secret key must be the + /// same for all nodes participating in the [phantom node payment]. + /// + /// [phantom node payment]: PhantomKeysManager + PhantomNode, } /// A trait to describe an object which can get user secrets and key material. pub trait KeysInterface { - /// A type which implements Sign which will be returned by get_channel_signer. + /// A type which implements Sign which will be returned by derive_channel_signer. type Signer : Sign; - /// Get node secret key (aka node_id or network_key). + /// Get node secret key based on the provided [`Recipient`]. /// - /// This method must return the same value each time it is called. - fn get_node_secret(&self) -> SecretKey; + /// The node_id/network_key is the public key that corresponds to this secret key. + /// + /// This method must return the same value each time it is called with a given `Recipient` + /// parameter. + /// + /// Errors if the `Recipient` variant is not supported by the implementation. + fn get_node_secret(&self, recipient: Recipient) -> Result; + /// Get node id based on the provided [`Recipient`]. This public key corresponds to the secret in + /// [`get_node_secret`]. + /// + /// This method must return the same value each time it is called with a given `Recipient` + /// parameter. + /// + /// Errors if the `Recipient` variant is not supported by the implementation. + /// + /// [`get_node_secret`]: KeysInterface::get_node_secret + fn get_node_id(&self, recipient: Recipient) -> Result { + let secp_ctx = Secp256k1::signing_only(); + Ok(PublicKey::from_secret_key(&secp_ctx, &self.get_node_secret(recipient)?)) + } + /// Gets the ECDH shared secret of our [`node secret`] and `other_key`, multiplying by `tweak` if + /// one is provided. Note that this tweak can be applied to `other_key` instead of our node + /// secret, though this is less efficient. + /// + /// Errors if the `Recipient` variant is not supported by the implementation. + /// + /// [`node secret`]: Self::get_node_secret + fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result; /// Get a script pubkey which we send funds to when claiming on-chain contestable outputs. /// /// This method should return a different value each time it is called, to avoid linking @@ -398,11 +458,20 @@ pub trait KeysInterface { /// This method should return a different value each time it is called, to avoid linking /// on-chain funds across channels as controlled to the same user. fn get_shutdown_scriptpubkey(&self) -> ShutdownScript; - /// Get a new set of Sign for per-channel secrets. These MUST be unique even if you - /// restarted with some stale data! + /// Generates a unique `channel_keys_id` that can be used to obtain a `Signer` through + /// [`KeysInterface::derive_channel_signer`]. The `user_channel_id` is provided to allow + /// implementations of `KeysInterface` to maintain a mapping between it and the generated + /// `channel_keys_id`. /// /// This method must return a different value each time it is called. - fn get_channel_signer(&self, inbound: bool, channel_value_satoshis: u64) -> Self::Signer; + fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32]; + /// Derives the private key material backing a `Signer`. + /// + /// To derive a new `Signer`, a fresh `channel_keys_id` should be obtained through + /// [`KeysInterface::generate_channel_keys_id`]. Otherwise, an existing `Signer` can be + /// re-derived from its `channel_keys_id`, which can be obtained through its trait method + /// [`BaseSign::channel_keys_id`]. + fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer; /// Gets a unique, cryptographically-secure, random 32 byte value. This is used for encrypting /// onion packets and for temporary channel IDs. There is no requirement that these be /// persisted anywhere, though they must be unique across restarts. @@ -416,6 +485,9 @@ pub trait KeysInterface { /// The bytes are exactly those which `::write()` writes, and /// contain no versioning scheme. You may wish to include your own version prefix and ensure /// you've read all of the provided bytes to ensure no corruption occurred. + /// + /// This method is slowly being phased out -- it will only be called when reading objects + /// written by LDK versions prior to 0.0.113. fn read_chan_signer(&self, reader: &[u8]) -> Result; /// Sign an invoice. @@ -423,11 +495,24 @@ pub trait KeysInterface { /// this trait to parse the invoice and make sure they're signing what they expect, rather than /// blindly signing the hash. /// The hrp is ascii bytes, while the invoice data is base32. - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result; + /// + /// The secret key used to sign the invoice is dependent on the [`Recipient`]. + /// + /// Errors if the `Recipient` variant is not supported by the implementation. + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], receipient: Recipient) -> Result; /// Get secret key material as bytes for use in encrypting and decrypting inbound payment data. /// + /// If the implementor of this trait supports [phantom node payments], then every node that is + /// intended to be included in the phantom invoice route hints must return the same value from + /// this method. + // This is because LDK avoids storing inbound payment data by encrypting payment data in the + // payment hash and/or payment secret, therefore for a payment to be receivable by multiple + // nodes, they must share the key that encrypts this payment data. + /// /// This method must return the same value each time it is called. + /// + /// [phantom node payments]: PhantomKeysManager fn get_inbound_payment_key_material(&self) -> KeyMaterial; } @@ -473,7 +558,8 @@ impl InMemorySigner { htlc_base_key: SecretKey, commitment_seed: [u8; 32], channel_value_satoshis: u64, - channel_keys_id: [u8; 32]) -> InMemorySigner { + channel_keys_id: [u8; 32], + ) -> InMemorySigner { let holder_channel_pubkeys = InMemorySigner::make_holder_keys(secp_ctx, &funding_key, &revocation_base_key, &payment_key, &delayed_payment_base_key, @@ -510,39 +596,39 @@ impl InMemorySigner { } /// Counterparty pubkeys. - /// Will panic if ready_channel wasn't called. + /// Will panic if provide_channel_parameters wasn't called. pub fn counterparty_pubkeys(&self) -> &ChannelPublicKeys { &self.get_channel_parameters().counterparty_parameters.as_ref().unwrap().pubkeys } /// The contest_delay value specified by our counterparty and applied on holder-broadcastable /// transactions, ie the amount of time that we have to wait to recover our funds if we /// broadcast a transaction. - /// Will panic if ready_channel wasn't called. + /// Will panic if provide_channel_parameters wasn't called. pub fn counterparty_selected_contest_delay(&self) -> u16 { self.get_channel_parameters().counterparty_parameters.as_ref().unwrap().selected_contest_delay } /// The contest_delay value specified by us and applied on transactions broadcastable /// by our counterparty, ie the amount of time that they have to wait to recover their funds /// if they broadcast a transaction. - /// Will panic if ready_channel wasn't called. + /// Will panic if provide_channel_parameters wasn't called. pub fn holder_selected_contest_delay(&self) -> u16 { self.get_channel_parameters().holder_selected_contest_delay } /// Whether the holder is the initiator - /// Will panic if ready_channel wasn't called. + /// Will panic if provide_channel_parameters wasn't called. pub fn is_outbound(&self) -> bool { self.get_channel_parameters().is_outbound_from_holder } /// Funding outpoint - /// Will panic if ready_channel wasn't called. + /// Will panic if provide_channel_parameters wasn't called. pub fn funding_outpoint(&self) -> &OutPoint { self.get_channel_parameters().funding_outpoint.as_ref().unwrap() } /// Obtain a ChannelTransactionParameters for this channel, to be used when verifying or /// building transactions. /// - /// Will panic if ready_channel wasn't called. + /// Will panic if provide_channel_parameters wasn't called. pub fn get_channel_parameters(&self) -> &ChannelTransactionParameters { self.channel_parameters.as_ref().unwrap() } /// Whether anchors should be used. - /// Will panic if ready_channel wasn't called. + /// Will panic if provide_channel_parameters wasn't called. pub fn opt_anchors(&self) -> bool { self.get_channel_parameters().opt_anchors.is_some() } @@ -563,16 +649,16 @@ impl InMemorySigner { if spend_tx.input[input_idx].previous_output != descriptor.outpoint.into_bitcoin_outpoint() { return Err(()); } let remotepubkey = self.pubkeys().payment_point; - let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Testnet).script_pubkey(); - let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]); - let remotesig = secp_ctx.sign(&sighash, &self.payment_key); - let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey(); + let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Testnet).script_pubkey(); + let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]); + let remotesig = sign(secp_ctx, &sighash, &self.payment_key); + let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey(); if payment_script != descriptor.output.script_pubkey { return Err(()); } let mut witness = Vec::with_capacity(2); witness.push(remotesig.serialize_der().to_vec()); - witness[0].push(SigHashType::All as u8); + witness[0].push(EcdsaSighashType::All as u8); witness.push(remotepubkey.serialize().to_vec()); Ok(witness) } @@ -592,21 +678,20 @@ impl InMemorySigner { if spend_tx.input.len() <= input_idx { return Err(()); } if !spend_tx.input[input_idx].script_sig.is_empty() { return Err(()); } if spend_tx.input[input_idx].previous_output != descriptor.outpoint.into_bitcoin_outpoint() { return Err(()); } - if spend_tx.input[input_idx].sequence != descriptor.to_self_delay as u32 { return Err(()); } + if spend_tx.input[input_idx].sequence.0 != descriptor.to_self_delay as u32 { return Err(()); } - let delayed_payment_key = chan_utils::derive_private_key(&secp_ctx, &descriptor.per_commitment_point, &self.delayed_payment_base_key) - .expect("We constructed the payment_base_key, so we can only fail here if the RNG is busted."); + let delayed_payment_key = chan_utils::derive_private_key(&secp_ctx, &descriptor.per_commitment_point, &self.delayed_payment_base_key); let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key); let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey); - let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]); - let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key); + let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]); + let local_delayedsig = sign(secp_ctx, &sighash, &delayed_payment_key); let payment_script = bitcoin::Address::p2wsh(&witness_script, Network::Bitcoin).script_pubkey(); if descriptor.output.script_pubkey != payment_script { return Err(()); } let mut witness = Vec::with_capacity(3); witness.push(local_delayedsig.serialize_der().to_vec()); - witness[0].push(SigHashType::All as u8); + witness[0].push(EcdsaSighashType::All as u8); witness.push(vec!()); //MINIMALIF witness.push(witness_script.clone().into_bytes()); Ok(witness) @@ -643,12 +728,13 @@ impl BaseSign for InMemorySigner { let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len()); for htlc in commitment_tx.htlcs() { - let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let channel_parameters = self.get_channel_parameters(); + let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, self.opt_anchors(), channel_parameters.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys); - let htlc_sighashtype = if self.opt_anchors() { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All }; - let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype)[..]); - let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key).map_err(|_| ())?; - htlc_sigs.push(secp_ctx.sign(&htlc_sighash, &holder_htlc_key)); + let htlc_sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; + let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]); + let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key); + htlc_sigs.push(sign(secp_ctx, &htlc_sighash, &holder_htlc_key)); } Ok((commitment_sig, htlc_sigs)) @@ -680,46 +766,59 @@ impl BaseSign for InMemorySigner { } fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1) -> Result { - let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key).map_err(|_| ())?; + let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key); let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint).map_err(|_| ())?; + let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); let witness_script = { - let counterparty_delayedpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().delayed_payment_basepoint).map_err(|_| ())?; + let counterparty_delayedpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().delayed_payment_basepoint); chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.holder_selected_contest_delay(), &counterparty_delayedpubkey) }; - let mut sighash_parts = bip143::SigHashCache::new(justice_tx); - let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &revocation_key)) + let mut sighash_parts = sighash::SighashCache::new(justice_tx); + let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); + return Ok(sign(secp_ctx, &sighash, &revocation_key)) } fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { - let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key).map_err(|_| ())?; + let revocation_key = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key); let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint).map_err(|_| ())?; + let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); let witness_script = { - let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint).map_err(|_| ())?; - let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint).map_err(|_| ())?; + let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint); + let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey) }; - let mut sighash_parts = bip143::SigHashCache::new(justice_tx); - let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &revocation_key)) + let mut sighash_parts = sighash::SighashCache::new(justice_tx); + let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); + return Ok(sign(secp_ctx, &sighash, &revocation_key)) + } + + #[cfg(anchors)] + fn sign_holder_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, + secp_ctx: &Secp256k1 + ) -> Result { + let per_commitment_point = self.get_per_commitment_point( + htlc_descriptor.per_commitment_number, &secp_ctx + ); + let witness_script = htlc_descriptor.witness_script(&per_commitment_point, secp_ctx); + let sighash = &sighash::SighashCache::new(&*htlc_tx).segwit_signature_hash( + input, &witness_script, htlc_descriptor.htlc.amount_msat / 1000, EcdsaSighashType::All + ).map_err(|_| ())?; + let our_htlc_private_key = chan_utils::derive_private_key( + &secp_ctx, &per_commitment_point, &self.htlc_base_key + ); + Ok(sign(&secp_ctx, &hash_to_message!(sighash), &our_htlc_private_key)) } fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { - if let Ok(htlc_key) = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key) { - let witness_script = if let Ok(revocation_pubkey) = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint) { - if let Ok(counterparty_htlcpubkey) = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint) { - if let Ok(htlcpubkey) = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint) { - chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey) - } else { return Err(()) } - } else { return Err(()) } - } else { return Err(()) }; - let mut sighash_parts = bip143::SigHashCache::new(htlc_tx); - let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &htlc_key)) - } - Err(()) + let htlc_key = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key); + let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); + let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint); + let htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey); + let mut sighash_parts = sighash::SighashCache::new(htlc_tx); + let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); + Ok(sign(secp_ctx, &sighash, &htlc_key)) } fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1) -> Result { @@ -728,14 +827,28 @@ impl BaseSign for InMemorySigner { Ok(closing_tx.trust().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx)) } + fn sign_holder_anchor_input( + &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + ) -> Result { + let witness_script = chan_utils::get_anchor_redeemscript(&self.holder_channel_pubkeys.funding_pubkey); + let sighash = sighash::SighashCache::new(&*anchor_tx).segwit_signature_hash( + input, &witness_script, ANCHOR_OUTPUT_VALUE_SATOSHI, EcdsaSighashType::All, + ).unwrap(); + Ok(sign(secp_ctx, &hash_to_message!(&sighash[..]), &self.funding_key)) + } + fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) -> Result<(Signature, Signature), ()> { let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); - Ok((secp_ctx.sign(&msghash, &self.node_secret), secp_ctx.sign(&msghash, &self.funding_key))) + Ok((sign(secp_ctx, &msghash, &self.node_secret), sign(secp_ctx, &msghash, &self.funding_key))) } - fn ready_channel(&mut self, channel_parameters: &ChannelTransactionParameters) { - assert!(self.channel_parameters.is_none(), "Acceptance already noted"); + fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { + assert!(self.channel_parameters.is_none() || self.channel_parameters.as_ref().unwrap() == channel_parameters); + if self.channel_parameters.is_some() { + // The channel parameters were already set and they match, return early. + return; + } assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); self.channel_parameters = Some(channel_parameters.clone()); } @@ -810,9 +923,16 @@ impl ReadableArgs for InMemorySigner { /// ChannelMonitor closes may use seed/1' /// Cooperative closes may use seed/2' /// The two close keys may be needed to claim on-chain funds! +/// +/// This struct cannot be used for nodes that wish to support receiving phantom payments; +/// [`PhantomKeysManager`] must be used instead. +/// +/// Note that switching between this struct and [`PhantomKeysManager`] will invalidate any +/// previously issued invoices and attempts to pay previous invoices will fail. pub struct KeysManager { secp_ctx: Secp256k1, node_secret: SecretKey, + node_id: PublicKey, inbound_payment_key: KeyMaterial, destination_script: Script, shutdown_pubkey: PublicKey, @@ -853,10 +973,11 @@ impl KeysManager { // Note that when we aren't serializing the key, network doesn't matter match ExtendedPrivKey::new_master(Network::Testnet, seed) { Ok(master_key) => { - let node_secret = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(0).unwrap()).expect("Your RNG is busted").private_key.key; + let node_secret = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(0).unwrap()).expect("Your RNG is busted").private_key; + let node_id = PublicKey::from_secret_key(&secp_ctx, &node_secret); let destination_script = match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(1).unwrap()) { Ok(destination_key) => { - let wpubkey_hash = WPubkeyHash::hash(&ExtendedPubKey::from_private(&secp_ctx, &destination_key).public_key.to_bytes()); + let wpubkey_hash = WPubkeyHash::hash(&ExtendedPubKey::from_priv(&secp_ctx, &destination_key).to_pub().to_bytes()); Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice(&wpubkey_hash.into_inner()) .into_script() @@ -864,23 +985,24 @@ impl KeysManager { Err(_) => panic!("Your RNG is busted"), }; let shutdown_pubkey = match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(2).unwrap()) { - Ok(shutdown_key) => ExtendedPubKey::from_private(&secp_ctx, &shutdown_key).public_key.key, + Ok(shutdown_key) => ExtendedPubKey::from_priv(&secp_ctx, &shutdown_key).public_key, Err(_) => panic!("Your RNG is busted"), }; let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3).unwrap()).expect("Your RNG is busted"); let rand_bytes_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4).unwrap()).expect("Your RNG is busted"); - let inbound_payment_key: SecretKey = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5).unwrap()).expect("Your RNG is busted").private_key.key; + let inbound_payment_key: SecretKey = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5).unwrap()).expect("Your RNG is busted").private_key; let mut inbound_pmt_key_bytes = [0; 32]; inbound_pmt_key_bytes.copy_from_slice(&inbound_payment_key[..]); let mut rand_bytes_unique_start = Sha256::engine(); - rand_bytes_unique_start.input(&byte_utils::be64_to_array(starting_time_secs)); - rand_bytes_unique_start.input(&byte_utils::be32_to_array(starting_time_nanos)); + rand_bytes_unique_start.input(&starting_time_secs.to_be_bytes()); + rand_bytes_unique_start.input(&starting_time_nanos.to_be_bytes()); rand_bytes_unique_start.input(seed); let mut res = KeysManager { secp_ctx, node_secret, + node_id, inbound_payment_key: KeyMaterial(inbound_pmt_key_bytes), destination_script, @@ -905,13 +1027,8 @@ impl KeysManager { } } /// Derive an old Sign containing per-channel secrets based on a key derivation parameters. - /// - /// Key derivation parameters are accessible through a per-channel secrets - /// Sign::channel_keys_id and is provided inside DynamicOuputP2WSH in case of - /// onchain output detection for which a corresponding delayed_payment_key must be derived. pub fn derive_channel_keys(&self, channel_value_satoshis: u64, params: &[u8; 32]) -> InMemorySigner { - let chan_id = byte_utils::slice_to_be64(¶ms[0..8]); - assert!(chan_id <= core::u32::MAX as u64); // Otherwise the params field wasn't created by us + let chan_id = u64::from_be_bytes(params[0..8].try_into().unwrap()); let mut unique_start = Sha256::engine(); unique_start.input(params); unique_start.input(&self.seed); @@ -920,7 +1037,7 @@ impl KeysManager { // entropy, everything else just ensures uniqueness. We rely on the unique_start (ie // starting_time provided in the constructor) to be unique. let child_privkey = self.channel_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(chan_id as u32).expect("key space exhausted")).expect("Your RNG is busted"); - unique_start.input(&child_privkey.private_key.key[..]); + unique_start.input(&child_privkey.private_key[..]); let seed = Sha256::from_engine(unique_start).into_inner(); @@ -955,7 +1072,7 @@ impl KeysManager { htlc_base_key, commitment_seed, channel_value_satoshis, - params.clone() + params.clone(), ) } @@ -964,7 +1081,7 @@ impl KeysManager { /// transaction will have a feerate, at least, of the given value. /// /// Returns `Err(())` if the output value is greater than the input value minus required fee, - /// if a descriptor was duplicated, or if an output descriptor script_pubkey + /// if a descriptor was duplicated, or if an output descriptor `script_pubkey` /// does not match the one we can spend. /// /// We do not enforce that outputs meet the dust limit or that any output scripts are standard. @@ -982,8 +1099,8 @@ impl KeysManager { input.push(TxIn { previous_output: descriptor.outpoint.into_bitcoin_outpoint(), script_sig: Script::new(), - sequence: 0, - witness: Vec::new(), + sequence: Sequence::ZERO, + witness: Witness::new(), }); witness_weight += StaticPaymentOutputDescriptor::MAX_WITNESS_LENGTH; input_value += descriptor.output.value; @@ -993,8 +1110,8 @@ impl KeysManager { input.push(TxIn { previous_output: descriptor.outpoint.into_bitcoin_outpoint(), script_sig: Script::new(), - sequence: descriptor.to_self_delay as u32, - witness: Vec::new(), + sequence: Sequence(descriptor.to_self_delay as u32), + witness: Witness::new(), }); witness_weight += DelayedPaymentOutputDescriptor::MAX_WITNESS_LENGTH; input_value += descriptor.output.value; @@ -1004,8 +1121,8 @@ impl KeysManager { input.push(TxIn { previous_output: outpoint.into_bitcoin_outpoint(), script_sig: Script::new(), - sequence: 0, - witness: Vec::new(), + sequence: Sequence::ZERO, + witness: Witness::new(), }); witness_weight += 1 + 73 + 34; input_value += output.value; @@ -1016,7 +1133,7 @@ impl KeysManager { } let mut spend_tx = Transaction { version: 2, - lock_time: 0, + lock_time: PackedLockTime(0), input, output: outputs, }; @@ -1033,7 +1150,7 @@ impl KeysManager { self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id), descriptor.channel_keys_id)); } - spend_tx.input[input_idx].witness = keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?; + spend_tx.input[input_idx].witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?); }, SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => { if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id { @@ -1041,7 +1158,7 @@ impl KeysManager { self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id), descriptor.channel_keys_id)); } - spend_tx.input[input_idx].witness = keys_cache.as_ref().unwrap().0.sign_dynamic_p2wsh_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?; + spend_tx.input[input_idx].witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_dynamic_p2wsh_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?); }, SpendableOutputDescriptor::StaticOutput { ref output, .. } => { let derivation_idx = if output.script_pubkey == self.destination_script { @@ -1061,29 +1178,30 @@ impl KeysManager { Err(_) => panic!("Your rng is busted"), } }; - let pubkey = ExtendedPubKey::from_private(&secp_ctx, &secret).public_key; + let pubkey = ExtendedPubKey::from_priv(&secp_ctx, &secret).to_pub(); if derivation_idx == 2 { - assert_eq!(pubkey.key, self.shutdown_pubkey); + assert_eq!(pubkey.inner, self.shutdown_pubkey); } let witness_script = bitcoin::Address::p2pkh(&pubkey, Network::Testnet).script_pubkey(); let payment_script = bitcoin::Address::p2wpkh(&pubkey, Network::Testnet).expect("uncompressed key found").script_pubkey(); if payment_script != output.script_pubkey { return Err(()); }; - let sighash = hash_to_message!(&bip143::SigHashCache::new(&spend_tx).signature_hash(input_idx, &witness_script, output.value, SigHashType::All)[..]); - let sig = secp_ctx.sign(&sighash, &secret.private_key.key); - spend_tx.input[input_idx].witness.push(sig.serialize_der().to_vec()); - spend_tx.input[input_idx].witness[0].push(SigHashType::All as u8); - spend_tx.input[input_idx].witness.push(pubkey.key.serialize().to_vec()); + let sighash = hash_to_message!(&sighash::SighashCache::new(&spend_tx).segwit_signature_hash(input_idx, &witness_script, output.value, EcdsaSighashType::All).unwrap()[..]); + let sig = sign(secp_ctx, &sighash, &secret.private_key); + let mut sig_ser = sig.serialize_der().to_vec(); + sig_ser.push(EcdsaSighashType::All as u8); + spend_tx.input[input_idx].witness.push(sig_ser); + spend_tx.input[input_idx].witness.push(pubkey.inner.serialize().to_vec()); }, } input_idx += 1; } - debug_assert!(expected_max_weight >= spend_tx.get_weight()); + debug_assert!(expected_max_weight >= spend_tx.weight()); // Note that witnesses with a signature vary somewhat in size, so allow // `expected_max_weight` to overshoot by up to 3 bytes per input. - debug_assert!(expected_max_weight <= spend_tx.get_weight() + descriptors.len() * 3); + debug_assert!(expected_max_weight <= spend_tx.weight() + descriptors.len() * 3); Ok(spend_tx) } @@ -1092,8 +1210,26 @@ impl KeysManager { impl KeysInterface for KeysManager { type Signer = InMemorySigner; - fn get_node_secret(&self) -> SecretKey { - self.node_secret.clone() + fn get_node_secret(&self, recipient: Recipient) -> Result { + match recipient { + Recipient::Node => Ok(self.node_secret.clone()), + Recipient::PhantomNode => Err(()) + } + } + + fn get_node_id(&self, recipient: Recipient) -> Result { + match recipient { + Recipient::Node => Ok(self.node_id.clone()), + Recipient::PhantomNode => Err(()) + } + } + + fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { + let mut node_secret = self.get_node_secret(recipient)?; + if let Some(tweak) = tweak { + node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; + } + Ok(SharedSecret::new(other_key, &node_secret)) } fn get_inbound_payment_key_material(&self) -> KeyMaterial { @@ -1108,14 +1244,19 @@ impl KeysInterface for KeysManager { ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone()) } - fn get_channel_signer(&self, _inbound: bool, channel_value_satoshis: u64) -> Self::Signer { - let child_ix = self.channel_child_index.fetch_add(1, Ordering::AcqRel); - assert!(child_ix <= core::u32::MAX as usize); + fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { + let child_idx = self.channel_child_index.fetch_add(1, Ordering::AcqRel); + assert!(child_idx <= core::u32::MAX as usize); let mut id = [0; 32]; - id[0..8].copy_from_slice(&byte_utils::be64_to_array(child_ix as u64)); - id[8..16].copy_from_slice(&byte_utils::be64_to_array(self.starting_time_nanos as u64)); - id[16..24].copy_from_slice(&byte_utils::be64_to_array(self.starting_time_secs)); - self.derive_channel_keys(channel_value_satoshis, &id) + id[0..4].copy_from_slice(&(child_idx as u32).to_be_bytes()); + id[4..8].copy_from_slice(&self.starting_time_nanos.to_be_bytes()); + id[8..16].copy_from_slice(&self.starting_time_secs.to_be_bytes()); + id[16..32].copy_from_slice(&user_channel_id.to_be_bytes()); + id + } + + fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer { + self.derive_channel_keys(channel_value_satoshis, &channel_keys_id) } fn get_secure_random_bytes(&self) -> [u8; 32] { @@ -1123,19 +1264,146 @@ impl KeysInterface for KeysManager { let child_ix = self.rand_bytes_child_index.fetch_add(1, Ordering::AcqRel); let child_privkey = self.rand_bytes_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted"); - sha.input(&child_privkey.private_key.key[..]); + sha.input(&child_privkey.private_key[..]); sha.input(b"Unique Secure Random Bytes Salt"); Sha256::from_engine(sha).into_inner() } fn read_chan_signer(&self, reader: &[u8]) -> Result { - InMemorySigner::read(&mut io::Cursor::new(reader), self.get_node_secret()) + InMemorySigner::read(&mut io::Cursor::new(reader), self.node_secret.clone()) + } + + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { + let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); + let secret = match recipient { + Recipient::Node => self.get_node_secret(Recipient::Node)?, + Recipient::PhantomNode => return Err(()), + }; + Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret)) + } +} + +/// Similar to [`KeysManager`], but allows the node using this struct to receive phantom node +/// payments. +/// +/// A phantom node payment is a payment made to a phantom invoice, which is an invoice that can be +/// paid to one of multiple nodes. This works because we encode the invoice route hints such that +/// LDK will recognize an incoming payment as destined for a phantom node, and collect the payment +/// itself without ever needing to forward to this fake node. +/// +/// Phantom node payments are useful for load balancing between multiple LDK nodes. They also +/// provide some fault tolerance, because payers will automatically retry paying other provided +/// nodes in the case that one node goes down. +/// +/// Note that multi-path payments are not supported in phantom invoices for security reasons. +// In the hypothetical case that we did support MPP phantom payments, there would be no way for +// nodes to know when the full payment has been received (and the preimage can be released) without +// significantly compromising on our safety guarantees. I.e., if we expose the ability for the user +// to tell LDK when the preimage can be released, we open ourselves to attacks where the preimage +// is released too early. +// +/// Switching between this struct and [`KeysManager`] will invalidate any previously issued +/// invoices and attempts to pay previous invoices will fail. +pub struct PhantomKeysManager { + inner: KeysManager, + inbound_payment_key: KeyMaterial, + phantom_secret: SecretKey, + phantom_node_id: PublicKey, +} + +impl KeysInterface for PhantomKeysManager { + type Signer = InMemorySigner; + + fn get_node_secret(&self, recipient: Recipient) -> Result { + match recipient { + Recipient::Node => self.inner.get_node_secret(Recipient::Node), + Recipient::PhantomNode => Ok(self.phantom_secret.clone()), + } + } + + fn get_node_id(&self, recipient: Recipient) -> Result { + match recipient { + Recipient::Node => self.inner.get_node_id(Recipient::Node), + Recipient::PhantomNode => Ok(self.phantom_node_id.clone()), + } + } + + fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { + let mut node_secret = self.get_node_secret(recipient)?; + if let Some(tweak) = tweak { + node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; + } + Ok(SharedSecret::new(other_key, &node_secret)) + } + + fn get_inbound_payment_key_material(&self) -> KeyMaterial { + self.inbound_payment_key.clone() + } + + fn get_destination_script(&self) -> Script { + self.inner.get_destination_script() + } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + self.inner.get_shutdown_scriptpubkey() + } + + fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { + self.inner.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) + } + + fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer { + self.inner.derive_channel_signer(channel_value_satoshis, channel_keys_id) + } + + fn get_secure_random_bytes(&self) -> [u8; 32] { + self.inner.get_secure_random_bytes() + } + + fn read_chan_signer(&self, reader: &[u8]) -> Result { + self.inner.read_chan_signer(reader) } - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result { + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); - Ok(self.secp_ctx.sign_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &self.get_node_secret())) + let secret = self.get_node_secret(recipient)?; + Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret)) + } +} + +impl PhantomKeysManager { + /// Constructs a `PhantomKeysManager` given a 32-byte seed and an additional `cross_node_seed` + /// that is shared across all nodes that intend to participate in [phantom node payments] together. + /// + /// See [`KeysManager::new`] for more information on `seed`, `starting_time_secs`, and + /// `starting_time_nanos`. + /// + /// `cross_node_seed` must be the same across all phantom payment-receiving nodes and also the + /// same across restarts, or else inbound payments may fail. + /// + /// [phantom node payments]: PhantomKeysManager + pub fn new(seed: &[u8; 32], starting_time_secs: u64, starting_time_nanos: u32, cross_node_seed: &[u8; 32]) -> Self { + let inner = KeysManager::new(seed, starting_time_secs, starting_time_nanos); + let (inbound_key, phantom_key) = hkdf_extract_expand_twice(b"LDK Inbound and Phantom Payment Key Expansion", cross_node_seed); + let phantom_secret = SecretKey::from_slice(&phantom_key).unwrap(); + let phantom_node_id = PublicKey::from_secret_key(&inner.secp_ctx, &phantom_secret); + Self { + inner, + inbound_payment_key: KeyMaterial(inbound_key), + phantom_secret, + phantom_node_id, + } + } + + /// See [`KeysManager::spend_spendable_outputs`] for documentation on this method. + pub fn spend_spendable_outputs(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: Script, feerate_sat_per_1000_weight: u32, secp_ctx: &Secp256k1) -> Result { + self.inner.spend_spendable_outputs(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, secp_ctx) + } + + /// See [`KeysManager::derive_channel_keys`] for documentation on this method. + pub fn derive_channel_keys(&self, channel_value_satoshis: u64, params: &[u8; 32]) -> InMemorySigner { + self.inner.derive_channel_keys(channel_value_satoshis, params) } }