X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fkeysinterface.rs;h=da5a99ddbb76a92bd7aaeef65ab0b574b136bbf1;hb=4fcc3a396a3fd32549c897ebc9877b00e13f734a;hp=80f734edbde3e0def17dcd23ceb903d564d969e2;hpb=25c9a37e18b6e3e30a9ad0c8645fb8da34413199;p=rust-lightning diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 80f734edb..da5a99ddb 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -47,9 +47,9 @@ use ln::msgs::DecodeError; /// that txid/index, and any keys or other information required to sign. #[derive(Clone, Debug, PartialEq)] pub enum SpendableOutputDescriptor { - /// An output to a script which was provided via KeysInterface, thus you should already know - /// how to spend it. No keys are provided as rust-lightning was never given any keys - only the - /// script_pubkey as it appears in the output. + /// An output to a script which was provided via KeysInterface directly, either from + /// `get_destination_script()` or `get_shutdown_pubkey()`, thus you should already know how to + /// spend it. No secret keys are provided as rust-lightning was never given any key. /// These may include outputs from a transaction punishing our counterparty or claiming an HTLC /// on-chain using the payment preimage or after it has timed out. StaticOutput { @@ -98,11 +98,14 @@ pub enum SpendableOutputDescriptor { to_self_delay: u16, /// The output which is referenced by the given outpoint output: TxOut, - /// The channel keys state used to proceed to derivation of signing key. Must - /// be pass to KeysInterface::derive_channel_keys. - key_derivation_params: (u64, u64), /// The revocation_pubkey used to derive witnessScript - revocation_pubkey: PublicKey + revocation_pubkey: PublicKey, + /// Arbitrary identification information returned by a call to + /// `ChannelKeys::channel_keys_id()`. This may be useful in re-deriving keys used in + /// the channel to spend the output. + channel_keys_id: [u8; 32], + /// The value of the channel which this output originated from, possibly indirectly. + channel_value_satoshis: u64, }, /// An output to a P2WPKH, spendable exclusively by our payment key (ie the private key which /// corresponds to the public key in ChannelKeys::pubkeys().payment_point). @@ -116,9 +119,12 @@ pub enum SpendableOutputDescriptor { outpoint: OutPoint, /// The output which is reference by the given outpoint output: TxOut, - /// The channel keys state used to proceed to derivation of signing key. Must - /// be pass to KeysInterface::derive_channel_keys. - key_derivation_params: (u64, u64), + /// Arbitrary identification information returned by a call to + /// `ChannelKeys::channel_keys_id()`. This may be useful in re-deriving keys used in + /// the channel to spend the output. + channel_keys_id: [u8; 32], + /// The value of the channel which this transactions spends. + channel_value_satoshis: u64, } } @@ -130,22 +136,22 @@ impl Writeable for SpendableOutputDescriptor { outpoint.write(writer)?; output.write(writer)?; }, - &SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref key_derivation_params, ref revocation_pubkey } => { + &SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref revocation_pubkey, ref channel_keys_id, channel_value_satoshis } => { 1u8.write(writer)?; outpoint.write(writer)?; per_commitment_point.write(writer)?; to_self_delay.write(writer)?; output.write(writer)?; - key_derivation_params.0.write(writer)?; - key_derivation_params.1.write(writer)?; revocation_pubkey.write(writer)?; + channel_keys_id.write(writer)?; + channel_value_satoshis.write(writer)?; }, - &SpendableOutputDescriptor::StaticOutputCounterpartyPayment { ref outpoint, ref output, ref key_derivation_params } => { + &SpendableOutputDescriptor::StaticOutputCounterpartyPayment { ref outpoint, ref output, ref channel_keys_id, channel_value_satoshis } => { 2u8.write(writer)?; outpoint.write(writer)?; output.write(writer)?; - key_derivation_params.0.write(writer)?; - key_derivation_params.1.write(writer)?; + channel_keys_id.write(writer)?; + channel_value_satoshis.write(writer)?; }, } Ok(()) @@ -164,13 +170,15 @@ impl Readable for SpendableOutputDescriptor { per_commitment_point: Readable::read(reader)?, to_self_delay: Readable::read(reader)?, output: Readable::read(reader)?, - key_derivation_params: (Readable::read(reader)?, Readable::read(reader)?), revocation_pubkey: Readable::read(reader)?, + channel_keys_id: Readable::read(reader)?, + channel_value_satoshis: Readable::read(reader)?, }), 2u8 => Ok(SpendableOutputDescriptor::StaticOutputCounterpartyPayment { outpoint: Readable::read(reader)?, output: Readable::read(reader)?, - key_derivation_params: (Readable::read(reader)?, Readable::read(reader)?), + channel_keys_id: Readable::read(reader)?, + channel_value_satoshis: Readable::read(reader)?, }), _ => Err(DecodeError::InvalidValue), } @@ -221,10 +229,10 @@ pub trait ChannelKeys : Send+Clone + Writeable { fn release_commitment_secret(&self, idx: u64) -> [u8; 32]; /// Gets the holder's channel public keys and basepoints fn pubkeys(&self) -> &ChannelPublicKeys; - /// Gets arbitrary identifiers describing the set of keys which are provided back to you in - /// some SpendableOutputDescriptor types. These should be sufficient to identify this + /// Gets an arbitrary identifier describing the set of keys which are provided back to you in + /// some SpendableOutputDescriptor types. This should be sufficient to identify this /// ChannelKeys object uniquely and lookup or re-derive its keys. - fn key_derivation_params(&self) -> (u64, u64); + fn channel_keys_id(&self) -> [u8; 32]; /// Create a signature for a counterparty's commitment transaction and associated HTLC transactions. /// @@ -254,7 +262,7 @@ pub trait ChannelKeys : Send+Clone + Writeable { /// state. Thus, needs its own method as sign_holder_commitment may enforce that we only ever /// get called once. #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] - fn unsafe_sign_holder_commitment(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result; + fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()>; /// Create a signature for the given input in a transaction spending an HTLC or commitment /// transaction output when our counterparty broadcasts an old state. @@ -327,18 +335,31 @@ pub trait KeysInterface: Send + Sync { /// A type which implements ChannelKeys which will be returned by get_channel_keys. type ChanKeySigner : ChannelKeys; - /// Get node secret key (aka node_id or network_key) + /// Get node secret key (aka node_id or network_key). + /// + /// This method must return the same value each time it is called. fn get_node_secret(&self) -> SecretKey; - /// Get destination redeemScript to encumber static protocol exit points. + /// 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 + /// on-chain funds across channels as controlled to the same user. fn get_destination_script(&self) -> Script; - /// Get shutdown_pubkey to use as PublicKey at channel closure + /// Get a public key which we will send funds to (in the form of a P2WPKH output) when closing + /// a channel. + /// + /// 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_pubkey(&self) -> PublicKey; /// Get a new set of ChannelKeys for per-channel secrets. These MUST be unique even if you /// restarted with some stale data! + /// + /// This method must return a different value each time it is called. fn get_channel_keys(&self, inbound: bool, channel_value_satoshis: u64) -> Self::ChanKeySigner; /// 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. + /// + /// This method must return a different value each time it is called. fn get_secure_random_bytes(&self) -> [u8; 32]; /// Reads a `ChanKeySigner` for this `KeysInterface` from the given input stream. @@ -375,7 +396,7 @@ pub struct InMemoryChannelKeys { /// The total value of this channel channel_value_satoshis: u64, /// Key derivation parameters - key_derivation_params: (u64, u64), + channel_keys_id: [u8; 32], } impl InMemoryChannelKeys { @@ -389,7 +410,7 @@ impl InMemoryChannelKeys { htlc_base_key: SecretKey, commitment_seed: [u8; 32], channel_value_satoshis: u64, - key_derivation_params: (u64, u64)) -> InMemoryChannelKeys { + channel_keys_id: [u8; 32]) -> InMemoryChannelKeys { let holder_channel_pubkeys = InMemoryChannelKeys::make_holder_keys(secp_ctx, &funding_key, &revocation_base_key, &payment_key, &delayed_payment_base_key, @@ -404,7 +425,7 @@ impl InMemoryChannelKeys { channel_value_satoshis, holder_channel_pubkeys, channel_parameters: None, - key_derivation_params, + channel_keys_id, } } @@ -468,7 +489,7 @@ impl ChannelKeys for InMemoryChannelKeys { } fn pubkeys(&self) -> &ChannelPublicKeys { &self.holder_channel_pubkeys } - fn key_derivation_params(&self) -> (u64, u64) { self.key_derivation_params } + fn channel_keys_id(&self) -> [u8; 32] { self.channel_keys_id } fn sign_counterparty_commitment(&self, commitment_tx: &CommitmentTransaction, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()> { let trusted_tx = commitment_tx.trust(); @@ -499,18 +520,22 @@ impl ChannelKeys for InMemoryChannelKeys { fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()> { let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey); - let sig = commitment_tx.trust().built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx); - let channel_parameters = self.get_channel_parameters(); let trusted_tx = commitment_tx.trust(); + let sig = trusted_tx.built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx); + let channel_parameters = self.get_channel_parameters(); let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?; Ok((sig, htlc_sigs)) } #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] - fn unsafe_sign_holder_commitment(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result { + fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()> { let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey); - Ok(commitment_tx.trust().built_transaction().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx)) + let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey); + let trusted_tx = commitment_tx.trust(); + let sig = trusted_tx.built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx); + let channel_parameters = self.get_channel_parameters(); + let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?; + Ok((sig, htlc_sigs)) } fn sign_justice_transaction(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option, secp_ctx: &Secp256k1) -> Result { @@ -596,8 +621,7 @@ impl Writeable for InMemoryChannelKeys { self.commitment_seed.write(writer)?; self.channel_parameters.write(writer)?; self.channel_value_satoshis.write(writer)?; - self.key_derivation_params.0.write(writer)?; - self.key_derivation_params.1.write(writer)?; + self.channel_keys_id.write(writer)?; Ok(()) } @@ -618,8 +642,7 @@ impl Readable for InMemoryChannelKeys { InMemoryChannelKeys::make_holder_keys(&secp_ctx, &funding_key, &revocation_base_key, &payment_key, &delayed_payment_base_key, &htlc_base_key); - let params_1 = Readable::read(reader)?; - let params_2 = Readable::read(reader)?; + let keys_id = Readable::read(reader)?; Ok(InMemoryChannelKeys { funding_key, @@ -631,7 +654,7 @@ impl Readable for InMemoryChannelKeys { channel_value_satoshis, holder_channel_pubkeys, channel_parameters: counterparty_channel_data, - key_derivation_params: (params_1, params_2), + channel_keys_id: keys_id, }) } } @@ -727,19 +750,19 @@ impl KeysManager { /// Derive an old set of ChannelKeys for per-channel secrets based on a key derivation /// parameters. /// Key derivation parameters are accessible through a per-channel secrets - /// ChannelKeys::key_derivation_params and is provided inside DynamicOuputP2WSH in case of + /// ChannelKeys::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_1: u64, params_2: u64) -> InMemoryChannelKeys { - let chan_id = ((params_1 & 0xFFFF_FFFF_0000_0000) >> 32) as u32; + pub fn derive_channel_keys(&self, channel_value_satoshis: u64, params: &[u8; 32]) -> InMemoryChannelKeys { + let chan_id = byte_utils::slice_to_be64(¶ms[0..8]); + assert!(chan_id <= std::u32::MAX as u64); // Otherwise the params field wasn't created by us let mut unique_start = Sha256::engine(); - unique_start.input(&byte_utils::be64_to_array(params_2)); - unique_start.input(&byte_utils::be32_to_array(params_1 as u32)); + unique_start.input(params); unique_start.input(&self.seed); // 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).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).expect("key space exhausted")).expect("Your RNG is busted"); unique_start.input(&child_privkey.private_key.key[..]); let seed = Sha256::from_engine(unique_start).into_inner(); @@ -774,7 +797,7 @@ impl KeysManager { htlc_base_key, commitment_seed, channel_value_satoshis, - (params_1, params_2), + params.clone() ) } } @@ -796,8 +819,12 @@ impl KeysInterface for KeysManager { fn get_channel_keys(&self, _inbound: bool, channel_value_satoshis: u64) -> Self::ChanKeySigner { let child_ix = self.channel_child_index.fetch_add(1, Ordering::AcqRel); - let ix_and_nanos: u64 = (child_ix as u64) << 32 | (self.starting_time_nanos as u64); - self.derive_channel_keys(channel_value_satoshis, ix_and_nanos, self.starting_time_secs) + assert!(child_ix <= std::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) } fn get_secure_random_bytes(&self) -> [u8; 32] {