X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fkeysinterface.rs;h=7063a38c4af33b862c810f710c5a3ee19abc3e1c;hb=acf9292d585fe558a33a2192e2e5e025f0c1edb2;hp=76781376f4ba1ea587fe12d7cecfec58ea373384;hpb=f7211fbf7907508a9ff2744ed56e60ed736e931d;p=rust-lightning diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 76781376..7063a38c 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -34,14 +34,14 @@ 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}; +use crate::util::ser::{Writeable, Writer, Readable}; #[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::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; use crate::ln::script::ShutdownScript; use crate::prelude::*; @@ -137,7 +137,7 @@ impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, { /// [`SpendableOutputs`]: crate::util::events::Event::SpendableOutputs #[derive(Clone, Debug, PartialEq, Eq)] pub enum SpendableOutputDescriptor { - /// An output to a script which was provided via [`KeysInterface`] directly, either from + /// An output to a script which was provided via [`SignerProvider`] directly, either from /// [`get_destination_script`] or [`get_shutdown_scriptpubkey`], thus you should already /// know how to spend it. No secret keys are provided as LDK was never given any key. /// These may include outputs from a transaction punishing our counterparty or claiming an HTLC @@ -383,17 +383,18 @@ pub trait BaseSign { 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. + /// Signs a channel announcement message with our funding key proving it comes from one of the + /// channel participants. /// - /// The first returned signature should be from our node secret key, the second from our - /// funding key. + /// Channel announcements also require a signature from each node's network key. Our node + /// signature is computed through [`NodeSigner::sign_gossip_message`]. /// /// Note that if this fails or is rejected, the channel will not be publicly announced and /// our counterparty may (though likely will not) close the channel on us for violating the /// protocol. - fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) - -> Result<(Signature, Signature), ()>; + fn sign_channel_announcement_with_funding_key( + &self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1 + ) -> Result; /// Set the counterparty static channel data, including basepoints, /// `counterparty_selected`/`holder_selected_contest_delay` and funding outpoint. /// @@ -438,16 +439,6 @@ pub trait EntropySource { /// A trait that can handle cryptographic operations at the scope level of a node. pub trait NodeSigner { - /// Get node secret key based on the provided [`Recipient`]. - /// - /// 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 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 @@ -462,36 +453,44 @@ pub trait NodeSigner { /// [phantom node payments]: PhantomKeysManager fn get_inbound_payment_key_material(&self) -> KeyMaterial; - /// Get node id based on the provided [`Recipient`]. This public key corresponds to the secret in - /// [`get_node_secret`]. + /// Get node id based on the provided [`Recipient`]. /// /// 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`]: Self::get_node_secret fn get_node_id(&self, recipient: Recipient) -> Result; - /// Gets the ECDH shared secret of our [`node secret`] and `other_key`, multiplying by `tweak` if + /// 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. + /// Note that if this fails while attempting to forward an HTLC, LDK will panic. The error + /// should be resolved to allow LDK to resume forwarding HTLCs. /// - /// [`node secret`]: Self::get_node_secret + /// Errors if the [`Recipient`] variant is not supported by the implementation. fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result; /// Sign an invoice. + /// /// By parameterizing by the raw invoice bytes instead of the hash, we allow implementors of /// 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. + /// + /// The `hrp_bytes` are ASCII bytes, while the `invoice_data` is base32. /// /// 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], recipient: Recipient) -> Result; + + /// Sign a gossip message. + /// + /// Note that if this fails, LDK may panic and the message will not be broadcast to the network + /// or a possible channel counterparty. If LDK panics, the error should be resolved to allow the + /// message to be broadcast, as otherwise it may prevent one from receiving funds over the + /// corresponding channel. + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result; } /// A trait that can return signer instances for individual channels. @@ -515,7 +514,7 @@ pub trait SignerProvider { /// [`BaseSign::channel_keys_id`]. fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer; - /// Reads a [`Signer`] for this [`KeysInterface`] from the given input stream. + /// Reads a [`Signer`] for this [`SignerProvider`] from the given input stream. /// This is only called during deserialization of other objects which contain /// [`Sign`]-implementing objects (i.e., [`ChannelMonitor`]s and [`ChannelManager`]s). /// The bytes are exactly those which `::write()` writes, and @@ -543,9 +542,6 @@ pub trait SignerProvider { fn get_shutdown_scriptpubkey(&self) -> ShutdownScript; } -/// A trait to describe an object which can get user secrets and key material. -pub trait KeysInterface: EntropySource + NodeSigner + SignerProvider {} - #[derive(Clone)] /// A simple implementation of [`Sign`] that just keeps the private keys in memory. /// @@ -567,8 +563,6 @@ pub struct InMemorySigner { pub commitment_seed: [u8; 32], /// Holder public keys and basepoints. pub(crate) holder_channel_pubkeys: ChannelPublicKeys, - /// Private key of our node secret, used for signing channel announcements. - node_secret: SecretKey, /// Counterparty public keys and counterparty/holder `selected_contest_delay`, populated on channel acceptance. channel_parameters: Option, /// The total value of this channel. @@ -581,7 +575,6 @@ impl InMemorySigner { /// Creates a new [`InMemorySigner`]. pub fn new( secp_ctx: &Secp256k1, - node_secret: SecretKey, funding_key: SecretKey, revocation_base_key: SecretKey, payment_key: SecretKey, @@ -602,7 +595,6 @@ impl InMemorySigner { delayed_payment_base_key, htlc_base_key, commitment_seed, - node_secret, channel_value_satoshis, holder_channel_pubkeys, channel_parameters: None, @@ -873,10 +865,11 @@ impl BaseSign for InMemorySigner { Ok(sign(secp_ctx, &hash_to_message!(&sighash[..]), &self.funding_key)) } - fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) - -> Result<(Signature, Signature), ()> { + fn sign_channel_announcement_with_funding_key( + &self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1 + ) -> Result { let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); - Ok((sign(secp_ctx, &msghash, &self.node_secret), sign(secp_ctx, &msghash, &self.funding_key))) + Ok(sign(secp_ctx, &msghash, &self.funding_key)) } fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { @@ -916,8 +909,8 @@ impl Writeable for InMemorySigner { } } -impl ReadableArgs for InMemorySigner { - fn read(reader: &mut R, node_secret: SecretKey) -> Result { +impl Readable for InMemorySigner { + fn read(reader: &mut R) -> Result { let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); let funding_key = Readable::read(reader)?; @@ -942,7 +935,6 @@ impl ReadableArgs for InMemorySigner { payment_key, delayed_payment_base_key, htlc_base_key, - node_secret, commitment_seed, channel_value_satoshis, holder_channel_pubkeys, @@ -952,8 +944,8 @@ impl ReadableArgs for InMemorySigner { } } -/// Simple [`KeysInterface`] implementation that takes a 32-byte seed for use as a BIP 32 extended -/// key and derives keys from that. +/// Simple implementation of [`EntropySource`], [`NodeSigner`], and [`SignerProvider`] that takes a +/// 32-byte seed for use as a BIP 32 extended key and derives keys from that. /// /// Your `node_id` is seed/0'. /// Unilateral closes may use seed/1'. @@ -1070,7 +1062,9 @@ impl KeysManager { // We only seriously intend to rely on the channel_master_key for true secure // 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"); + let child_privkey = self.channel_master_key.ckd_priv(&self.secp_ctx, + ChildNumber::from_hardened_idx((chan_id as u32) % (1 << 31)).expect("key space exhausted") + ).expect("Your RNG is busted"); unique_start.input(&child_privkey.private_key[..]); let seed = Sha256::from_engine(unique_start).into_inner(); @@ -1098,7 +1092,6 @@ impl KeysManager { InMemorySigner::new( &self.secp_ctx, - self.node_secret, funding_key, revocation_base_key, payment_key, @@ -1255,13 +1248,6 @@ impl EntropySource for KeysManager { } impl NodeSigner for KeysManager { - 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()), @@ -1270,7 +1256,10 @@ impl NodeSigner for KeysManager { } fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { - let mut node_secret = self.get_node_secret(recipient)?; + let mut node_secret = match recipient { + Recipient::Node => Ok(self.node_secret.clone()), + Recipient::PhantomNode => Err(()) + }?; if let Some(tweak) = tweak { node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; } @@ -1284,10 +1273,15 @@ impl NodeSigner for KeysManager { 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)) + Recipient::Node => Ok(&self.node_secret), + Recipient::PhantomNode => Err(()) + }?; + Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), secret)) + } + + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result { + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); + Ok(sign(&self.secp_ctx, &msg_hash, &self.node_secret)) } } @@ -1296,7 +1290,12 @@ impl SignerProvider for KeysManager { 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); + // `child_idx` is the only thing guaranteed to make each channel unique without a restart + // (though `user_channel_id` should help, depending on user behavior). If it manages to + // roll over, we may generate duplicate keys for two different channels, which could result + // in loss of funds. Because we only support 32-bit+ systems, assert that our `AtomicUsize` + // doesn't reach `u32::MAX`. + assert!(child_idx < core::u32::MAX as usize, "2^32 channels opened without restart"); let mut id = [0; 32]; 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()); @@ -1310,7 +1309,7 @@ impl SignerProvider for KeysManager { } fn read_chan_signer(&self, reader: &[u8]) -> Result { - InMemorySigner::read(&mut io::Cursor::new(reader), self.node_secret.clone()) + InMemorySigner::read(&mut io::Cursor::new(reader)) } fn get_destination_script(&self) -> Script { @@ -1322,8 +1321,6 @@ impl SignerProvider for KeysManager { } } -impl KeysInterface for KeysManager {} - /// Similar to [`KeysManager`], but allows the node using this struct to receive phantom node /// payments. /// @@ -1359,13 +1356,6 @@ impl EntropySource for PhantomKeysManager { } impl NodeSigner for PhantomKeysManager { - 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), @@ -1374,7 +1364,10 @@ impl NodeSigner for PhantomKeysManager { } fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { - let mut node_secret = self.get_node_secret(recipient)?; + let mut node_secret = match recipient { + Recipient::Node => self.inner.node_secret.clone(), + Recipient::PhantomNode => self.phantom_secret.clone(), + }; if let Some(tweak) = tweak { node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; } @@ -1387,8 +1380,15 @@ impl NodeSigner for PhantomKeysManager { fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); - let secret = self.get_node_secret(recipient)?; - Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret)) + let secret = match recipient { + Recipient::Node => &self.inner.node_secret, + Recipient::PhantomNode => &self.phantom_secret, + }; + Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), secret)) + } + + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result { + self.inner.sign_gossip_message(msg) } } @@ -1416,8 +1416,6 @@ impl SignerProvider for PhantomKeysManager { } } -impl KeysInterface for PhantomKeysManager {} - 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]