X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fkeysinterface.rs;h=f2d198bbfa101d97d129c251381a637a76aaf348;hb=4a0010d7393bb32305bdb3d859735b7b563462eb;hp=9f81976906cf7fa3b31961869ed4132435513d18;hpb=53eb0d7aa7e7ee2c247a509d259fbdc7cf840426;p=rust-lightning diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 9f819769..f2d198bb 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -31,10 +31,11 @@ use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::RecoverableSignature; use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; -use crate::util::{byte_utils, transaction_utils}; +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}; @@ -43,6 +44,7 @@ use crate::ln::msgs::UnsignedChannelAnnouncement; use crate::ln::script::ShutdownScript; use crate::prelude::*; +use core::convert::TryInto; use core::sync::atomic::{AtomicUsize, Ordering}; use crate::io::{self, Error}; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; @@ -161,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 @@ -324,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. /// @@ -368,24 +383,22 @@ 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. /// -/// 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 { +/// There will always be two instances of a signer per channel, one occupied by the +/// [`ChannelManager`] and another by the channel's [`ChannelMonitor`]. +/// +/// [`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 @@ -402,7 +415,7 @@ pub enum Recipient { /// 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 based on the provided [`Recipient`]. @@ -445,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. @@ -463,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. @@ -571,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() } @@ -655,8 +680,7 @@ impl InMemorySigner { if spend_tx.input[input_idx].previous_output != descriptor.outpoint.into_bitcoin_outpoint() { 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!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]); @@ -672,7 +696,6 @@ impl InMemorySigner { witness.push(witness_script.clone().into_bytes()); Ok(witness) } - } impl BaseSign for InMemorySigner { @@ -710,7 +733,7 @@ impl BaseSign for InMemorySigner { let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys); 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).map_err(|_| ())?; + 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)); } @@ -743,11 +766,11 @@ 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 = sighash::SighashCache::new(justice_tx); @@ -756,12 +779,12 @@ impl BaseSign for InMemorySigner { } 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 = sighash::SighashCache::new(justice_tx); @@ -769,20 +792,33 @@ impl BaseSign for InMemorySigner { 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 = sighash::SighashCache::new(htlc_tx); - let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); - return Ok(sign(secp_ctx, &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 { @@ -807,8 +843,12 @@ impl BaseSign for InMemorySigner { 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()); } @@ -955,8 +995,8 @@ impl KeysManager { 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 { @@ -987,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); @@ -1209,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] { @@ -1309,8 +1349,12 @@ impl KeysInterface for PhantomKeysManager { self.inner.get_shutdown_scriptpubkey() } - fn get_channel_signer(&self, inbound: bool, channel_value_satoshis: u64) -> Self::Signer { - self.inner.get_channel_signer(inbound, channel_value_satoshis) + 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] {