Provide remote channel public keys to signer
authorDevrandom <c1.devrandom@niftybox.net>
Fri, 17 Jan 2020 00:51:15 +0000 (16:51 -0800)
committerMatt Corallo <git@bluematt.me>
Mon, 20 Jan 2020 01:40:49 +0000 (20:40 -0500)
.gitignore
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
lightning/src/chain/keysinterface.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/channel.rs
lightning/src/util/enforcing_trait_impls.rs

index c795d9b53373103e2a75b2acfdcb1c27facb24e7..19ed4bd115a78efd45966f8fe9c144e421ca1b06 100644 (file)
@@ -1,4 +1,5 @@
 /target/
+/hfuzz_target/
 /net-tokio/target/
 **/*.rs.bk
 Cargo.lock
index d4a33427ef4b9a1b0eee8483d8f8d5b5e669bf2b..382886492dbd0a88ef245de713253ddad8fb9c6d 100644 (file)
@@ -158,7 +158,7 @@ impl KeysInterface for KeyProvider {
                        delayed_payment_base_key:  SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, self.node_id]).unwrap(),
                        htlc_base_key:             SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, self.node_id]).unwrap(),
                        commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_id],
-                       remote_funding_pubkey: None,
+                       remote_channel_pubkeys: None,
                })
        }
 
index 7e6135b5c658aeba7ee179af755c4ef80234677f..a98c29bc8e52b87952c2ab96e7c4d1d430ed9c1c 100644 (file)
@@ -257,7 +257,7 @@ impl KeysInterface for KeyProvider {
                                delayed_payment_base_key:  SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, ctr]).unwrap(),
                                htlc_base_key:             SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, ctr]).unwrap(),
                                commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ctr],
-                               remote_funding_pubkey: None,
+                               remote_channel_pubkeys: None,
                        }
                } else {
                        InMemoryChannelKeys {
@@ -267,7 +267,7 @@ impl KeysInterface for KeyProvider {
                                delayed_payment_base_key:  SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, ctr]).unwrap(),
                                htlc_base_key:             SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, ctr]).unwrap(),
                                commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, ctr],
-                               remote_funding_pubkey: None,
+                               remote_channel_pubkeys: None,
                        }
                })
        }
index c001646263fdf0d7ae4e1f1c079ed02ab3b40135..689a16603743e228ffff64dfba9ea710474fdc43 100644 (file)
@@ -24,7 +24,7 @@ use util::logger::Logger;
 use util::ser::Writeable;
 
 use ln::chan_utils;
-use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, make_funding_redeemscript};
+use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys};
 use ln::msgs;
 
 use std::sync::Arc;
@@ -142,7 +142,7 @@ pub trait ChannelKeys : Send {
        /// TODO: Document the things someone using this interface should enforce before signing.
        /// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
        /// making the callee generate it via some util function we expose)!
-       fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
+       fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
 
        /// Create a signature for a (proposed) closing transaction.
        ///
@@ -158,11 +158,11 @@ pub trait ChannelKeys : Send {
        /// protocol.
        fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
 
-       /// Set the remote funding key.  This is done immediately on incoming channels
+       /// Set the remote channel basepoints.  This is done immediately on incoming channels
        /// and as soon as the channel is accepted on outgoing channels.
        ///
        /// Will be called before any signatures are applied.
-       fn set_remote_funding_pubkey(&mut self, key: &PublicKey);
+       fn set_remote_channel_pubkeys(&mut self, channel_points: &ChannelPublicKeys);
 }
 
 #[derive(Clone)]
@@ -181,7 +181,7 @@ pub struct InMemoryChannelKeys {
        /// Commitment seed
        pub commitment_seed: [u8; 32],
        /// Remote funding pubkey
-       pub remote_funding_pubkey: Option<PublicKey>,
+       pub remote_channel_pubkeys: Option<ChannelPublicKeys>,
 }
 
 impl ChannelKeys for InMemoryChannelKeys {
@@ -192,12 +192,12 @@ impl ChannelKeys for InMemoryChannelKeys {
        fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
        fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }
 
-       fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
+       fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
                if commitment_tx.input.len() != 1 { return Err(()); }
 
                let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
-               let remote_funding_pubkey = self.remote_funding_pubkey.as_ref().expect("must set remote funding key before signing");
-               let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, remote_funding_pubkey);
+               let remote_channel_pubkeys = self.remote_channel_pubkeys.as_ref().expect("must set remote channel pubkeys before signing");
+               let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &remote_channel_pubkeys.funding_pubkey);
 
                let commitment_sighash = hash_to_message!(&bip143::SighashComponents::new(&commitment_tx).sighash_all(&commitment_tx.input[0], &channel_funding_redeemscript, channel_value_satoshis)[..]);
                let commitment_sig = secp_ctx.sign(&commitment_sighash, &self.funding_key);
@@ -236,9 +236,9 @@ impl ChannelKeys for InMemoryChannelKeys {
                Ok(secp_ctx.sign(&msghash, &self.funding_key))
        }
 
-       fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
-               assert!(self.remote_funding_pubkey.is_none(), "Already set remote funding key");
-               self.remote_funding_pubkey = Some(*key);
+       fn set_remote_channel_pubkeys(&mut self, channel_pubkeys: &ChannelPublicKeys) {
+               assert!(self.remote_channel_pubkeys.is_none(), "Already set remote channel pubkeys");
+               self.remote_channel_pubkeys = Some(channel_pubkeys.clone());
        }
 }
 
@@ -249,7 +249,7 @@ impl_writeable!(InMemoryChannelKeys, 0, {
        delayed_payment_base_key,
        htlc_base_key,
        commitment_seed,
-       remote_funding_pubkey
+       remote_channel_pubkeys
 });
 
 /// Simple KeysInterface implementor that takes a 32-byte seed for use as a BIP 32 extended key
@@ -398,7 +398,7 @@ impl KeysInterface for KeysManager {
                        delayed_payment_base_key,
                        htlc_base_key,
                        commitment_seed,
-                       remote_funding_pubkey: None,
+                       remote_channel_pubkeys: None,
                }
        }
 
index 19a07aaa19c2ea2c30f5498aee3c32278f7cb0c2..5338c06c5b839fb099e0ac608cca8dfc7178f790 100644 (file)
@@ -118,6 +118,7 @@ pub(super) fn derive_public_revocation_key<T: secp256k1::Verification>(secp_ctx:
 
 /// The set of public keys which are used in the creation of one commitment transaction.
 /// These are derived from the channel base keys and per-commitment data.
+#[derive(PartialEq)]
 pub struct TxCreationKeys {
        /// The per-commitment public key which was used to derive the other keys.
        pub per_commitment_point: PublicKey,
@@ -134,8 +135,40 @@ pub struct TxCreationKeys {
        pub b_payment_key: PublicKey,
 }
 
+/// One counterparty's public keys which do not change over the life of a channel.
+#[derive(Clone)]
+pub struct ChannelPublicKeys {
+       /// The public key which is used to sign all commitment transactions, as it appears in the
+       /// on-chain channel lock-in 2-of-2 multisig output.
+       pub funding_pubkey: PublicKey,
+       /// The base point which is used (with derive_public_revocation_key) to derive per-commitment
+       /// revocation keys. The per-commitment revocation private key is then revealed by the owner of
+       /// a commitment transaction so that their counterparty can claim all available funds if they
+       /// broadcast an old state.
+       pub revocation_basepoint: PublicKey,
+       /// The base point which is used (with derive_public_key) to derive a per-commitment payment
+       /// public key which receives immediately-spendable non-HTLC-encumbered funds.
+       pub payment_basepoint: PublicKey,
+       /// The base point which is used (with derive_public_key) to derive a per-commitment payment
+       /// public key which receives non-HTLC-encumbered funds which are only available for spending
+       /// after some delay (or can be claimed via the revocation path).
+       pub delayed_payment_basepoint: PublicKey,
+       /// The base point which is used (with derive_public_key) to derive a per-commitment public key
+       /// which is used to encumber HTLC-in-flight outputs.
+       pub htlc_basepoint: PublicKey,
+}
+
+impl_writeable!(ChannelPublicKeys, 33*5, {
+       funding_pubkey,
+       revocation_basepoint,
+       payment_basepoint,
+       delayed_payment_basepoint,
+       htlc_basepoint
+});
+
+
 impl TxCreationKeys {
-       pub(super) fn new<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_payment_base: &PublicKey, b_htlc_base: &PublicKey) -> Result<TxCreationKeys, secp256k1::Error> {
+       pub(crate) fn new<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_payment_base: &PublicKey, b_htlc_base: &PublicKey) -> Result<TxCreationKeys, secp256k1::Error> {
                Ok(TxCreationKeys {
                        per_commitment_point: per_commitment_point.clone(),
                        revocation_key: derive_public_revocation_key(&secp_ctx, &per_commitment_point, &b_revocation_base)?,
index 3d8962b4fe6c2b35c9f82f9f3e2ea27c85dde9f3..a9a8876404bd410cd30821230ea6f786dee71cf9 100644 (file)
@@ -20,7 +20,7 @@ use ln::msgs;
 use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
 use ln::channelmonitor::ChannelMonitor;
 use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
-use ln::chan_utils::{LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript};
+use ln::chan_utils::{LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys};
 use ln::chan_utils;
 use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
 use chain::transaction::OutPoint;
@@ -546,7 +546,14 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
        /// Assumes chain_hash has already been checked and corresponds with what we expect!
        pub fn new_from_req(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface<ChanKeySigner = ChanSigner>>, their_node_id: PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel<ChanSigner>, ChannelError> {
                let mut chan_keys = keys_provider.get_channel_keys(true);
-               chan_keys.set_remote_funding_pubkey(&msg.funding_pubkey);
+               let channel_pubkeys = ChannelPublicKeys {
+                       funding_pubkey: msg.funding_pubkey,
+                       revocation_basepoint: msg.revocation_basepoint,
+                       payment_basepoint: msg.payment_basepoint,
+                       delayed_payment_basepoint: msg.delayed_payment_basepoint,
+                       htlc_basepoint: msg.htlc_basepoint
+               };
+               chan_keys.set_remote_channel_pubkeys(&channel_pubkeys);
                let mut local_config = (*config).channel_options.clone();
 
                if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
@@ -1401,7 +1408,14 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                self.channel_monitor.set_basic_channel_info(&msg.htlc_basepoint, &msg.delayed_payment_basepoint, msg.to_self_delay, funding_redeemscript, self.channel_value_satoshis, obscure_factor);
 
                self.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32;
-               self.local_keys.set_remote_funding_pubkey(&msg.funding_pubkey);
+               let channel_pubkeys = ChannelPublicKeys {
+                       funding_pubkey: msg.funding_pubkey,
+                       revocation_basepoint: msg.revocation_basepoint,
+                       payment_basepoint: msg.payment_basepoint,
+                       delayed_payment_basepoint: msg.delayed_payment_basepoint,
+                       htlc_basepoint: msg.htlc_basepoint
+               };
+               self.local_keys.set_remote_channel_pubkeys(&channel_pubkeys);
 
                Ok(())
        }
@@ -4127,7 +4141,7 @@ mod tests {
                        // These aren't set in the test vectors:
                        revocation_base_key: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
                        commitment_seed: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
-                       remote_funding_pubkey: None,
+                       remote_channel_pubkeys: None,
                };
                assert_eq!(PublicKey::from_secret_key(&secp_ctx, chan_keys.funding_key()).serialize()[..],
                                hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
index ee90fe7acf8ead65b3b7701f619d398db154f4fd..e5b5a3179665f874dfdbaaf628c9051a2dc1635e 100644 (file)
@@ -1,4 +1,4 @@
-use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys};
+use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys, ChannelPublicKeys};
 use ln::msgs;
 use chain::keysinterface::{ChannelKeys, InMemoryChannelKeys};
 
@@ -27,6 +27,27 @@ impl EnforcingChannelKeys {
                }
        }
 }
+
+impl EnforcingChannelKeys {
+       fn check_keys<T: secp256k1::Signing + secp256k1::Verification>(&self, secp_ctx: &Secp256k1<T>,
+                                                                      keys: &TxCreationKeys) {
+               let revocation_base = PublicKey::from_secret_key(secp_ctx, &self.inner.revocation_base_key);
+               let payment_base = PublicKey::from_secret_key(secp_ctx, &self.inner.payment_base_key);
+               let htlc_base = PublicKey::from_secret_key(secp_ctx, &self.inner.htlc_base_key);
+
+               let remote_points = self.inner.remote_channel_pubkeys.as_ref().unwrap();
+
+               let keys_expected = TxCreationKeys::new(secp_ctx,
+                                                       &keys.per_commitment_point,
+                                                       &remote_points.delayed_payment_basepoint,
+                                                       &remote_points.htlc_basepoint,
+                                                       &revocation_base,
+                                                       &payment_base,
+                                                       &htlc_base).unwrap();
+               if keys != &keys_expected { panic!("derived different per-tx keys") }
+       }
+}
+
 impl ChannelKeys for EnforcingChannelKeys {
        fn funding_key(&self) -> &SecretKey { self.inner.funding_key() }
        fn revocation_base_key(&self) -> &SecretKey { self.inner.revocation_base_key() }
@@ -35,8 +56,9 @@ impl ChannelKeys for EnforcingChannelKeys {
        fn htlc_base_key(&self) -> &SecretKey { self.inner.htlc_base_key() }
        fn commitment_seed(&self) -> &[u8; 32] { self.inner.commitment_seed() }
 
-       fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
-               if commitment_tx.input.len() != 1 { panic!(); }
+       fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, channel_value_satoshis: u64, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
+               if commitment_tx.input.len() != 1 { panic!("lightning commitment transactions have a single input"); }
+               self.check_keys(secp_ctx, keys);
                let obscured_commitment_transaction_number = (commitment_tx.lock_time & 0xffffff) as u64 | ((commitment_tx.input[0].sequence as u64 & 0xffffff) << 3*8);
 
                {
@@ -60,11 +82,12 @@ impl ChannelKeys for EnforcingChannelKeys {
                self.inner.sign_channel_announcement(msg, secp_ctx)
        }
 
-       fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
-               self.inner.set_remote_funding_pubkey(key)
+       fn set_remote_channel_pubkeys(&mut self, channel_pubkeys: &ChannelPublicKeys) {
+               self.inner.set_remote_channel_pubkeys(channel_pubkeys)
        }
 }
 
+
 impl_writeable!(EnforcingChannelKeys, 0, {
        inner,
        commitment_number_obscure_and_last