From: Arik Sosman Date: Thu, 8 Dec 2022 23:40:54 +0000 (-0800) Subject: Split out KeysInterface into EntropySource, NodeSigner, and SignerProvider. X-Git-Tag: v0.0.114-beta~80^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=9d7bb73b599a7a9d8468a2f0c54d28f0ce6cf5;p=rust-lightning Split out KeysInterface into EntropySource, NodeSigner, and SignerProvider. --- diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 605a8c29c..1e8e57d24 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -36,7 +36,7 @@ use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, chainmonitor, chan use lightning::chain::channelmonitor::{ChannelMonitor, MonitorEvent}; use lightning::chain::transaction::OutPoint; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; -use lightning::chain::keysinterface::{KeyMaterial, KeysInterface, InMemorySigner, Recipient}; +use lightning::chain::keysinterface::{KeyMaterial, KeysInterface, InMemorySigner, Recipient, EntropySource, NodeSigner, SignerProvider}; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::ln::channelmanager::{self, ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs, PaymentId}; use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE; @@ -160,13 +160,26 @@ struct KeyProvider { rand_bytes_id: atomic::AtomicU32, enforcement_states: Mutex>>>, } -impl KeysInterface for KeyProvider { - type Signer = EnforcingSigner; +impl EntropySource for KeyProvider { + fn get_secure_random_bytes(&self) -> [u8; 32] { + let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed); + let mut res = [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, self.node_id]; + res[30-4..30].copy_from_slice(&id.to_le_bytes()); + res + } +} + +impl NodeSigner for KeyProvider { fn get_node_secret(&self, _recipient: Recipient) -> Result { Ok(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, 1, self.node_id]).unwrap()) } + 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)?)) + } + 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 { @@ -179,19 +192,13 @@ impl KeysInterface for KeyProvider { KeyMaterial([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, 1, self.node_id]) } - fn get_destination_script(&self) -> Script { - let secp_ctx = Secp256k1::signing_only(); - let channel_monitor_claim_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, 2, self.node_id]).unwrap(); - let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { + unreachable!() } +} - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - let secp_ctx = Secp256k1::signing_only(); - let secret_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, 3, self.node_id]).unwrap(); - let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); - ShutdownScript::new_p2wpkh(&pubkey_hash) - } +impl SignerProvider for KeyProvider { + type Signer = EnforcingSigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed) as u8; @@ -217,13 +224,6 @@ impl KeysInterface for KeyProvider { EnforcingSigner::new_with_revoked(keys, revoked_commitment, false) } - fn get_secure_random_bytes(&self) -> [u8; 32] { - let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed); - let mut res = [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, self.node_id]; - res[30-4..30].copy_from_slice(&id.to_le_bytes()); - res - } - fn read_chan_signer(&self, buffer: &[u8]) -> Result { let mut reader = std::io::Cursor::new(buffer); @@ -237,11 +237,23 @@ impl KeysInterface for KeyProvider { }) } - fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { - unreachable!() + fn get_destination_script(&self) -> Script { + let secp_ctx = Secp256k1::signing_only(); + let channel_monitor_claim_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, 2, self.node_id]).unwrap(); + let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); + Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() + } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + let secp_ctx = Secp256k1::signing_only(); + let secret_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, 3, self.node_id]).unwrap(); + let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); + ShutdownScript::new_p2wpkh(&pubkey_hash) } } +impl KeysInterface for KeyProvider {} + impl KeyProvider { fn make_enforcement_state_cell(&self, commitment_seed: [u8; 32]) -> Arc> { let mut revoked_commitments = self.enforcement_states.lock().unwrap(); diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 637432823..a6b86c921 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -33,7 +33,7 @@ use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen}; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::chain::chainmonitor; use lightning::chain::transaction::OutPoint; -use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface}; +use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface, EntropySource, NodeSigner, SignerProvider}; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentId}; use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,IgnoringMessageHandler}; @@ -265,13 +265,25 @@ struct KeyProvider { counter: AtomicU64, signer_state: RefCell>)>> } -impl KeysInterface for KeyProvider { - type Signer = EnforcingSigner; +impl EntropySource for KeyProvider { + fn get_secure_random_bytes(&self) -> [u8; 32] { + let ctr = self.counter.fetch_add(1, Ordering::Relaxed); + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + (ctr >> 8*7) as u8, (ctr >> 8*6) as u8, (ctr >> 8*5) as u8, (ctr >> 8*4) as u8, (ctr >> 8*3) as u8, (ctr >> 8*2) as u8, (ctr >> 8*1) as u8, 14, (ctr >> 8*0) as u8] + } +} + +impl NodeSigner for KeyProvider { fn get_node_secret(&self, _recipient: Recipient) -> Result { Ok(self.node_secret.clone()) } + 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)?)) + } + 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 { @@ -284,19 +296,13 @@ impl KeysInterface for KeyProvider { self.inbound_payment_key.clone() } - fn get_destination_script(&self) -> Script { - let secp_ctx = Secp256k1::signing_only(); - let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); - let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { + unreachable!() } +} - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - let secp_ctx = Secp256k1::signing_only(); - let secret_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, 0, 1]).unwrap(); - let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); - ShutdownScript::new_p2wpkh(&pubkey_hash) - } +impl SignerProvider for KeyProvider { + type Signer = EnforcingSigner; fn generate_channel_keys_id(&self, inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8; @@ -337,12 +343,6 @@ impl KeysInterface for KeyProvider { }, state, false) } - fn get_secure_random_bytes(&self) -> [u8; 32] { - let ctr = self.counter.fetch_add(1, Ordering::Relaxed); - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - (ctr >> 8*7) as u8, (ctr >> 8*6) as u8, (ctr >> 8*5) as u8, (ctr >> 8*4) as u8, (ctr >> 8*3) as u8, (ctr >> 8*2) as u8, (ctr >> 8*1) as u8, 14, (ctr >> 8*0) as u8] - } - fn read_chan_signer(&self, mut data: &[u8]) -> Result { let inner: InMemorySigner = ReadableArgs::read(&mut data, self.node_secret.clone())?; let state = Arc::new(Mutex::new(EnforcementState::new())); @@ -354,11 +354,23 @@ impl KeysInterface for KeyProvider { )) } - fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { - unreachable!() + fn get_destination_script(&self) -> Script { + let secp_ctx = Secp256k1::signing_only(); + let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); + let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); + Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() + } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + let secp_ctx = Secp256k1::signing_only(); + let secret_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, 0, 1]).unwrap(); + let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); + ShutdownScript::new_p2wpkh(&pubkey_hash) } } +impl KeysInterface for KeyProvider {} + #[inline] pub fn do_test(data: &[u8], logger: &Arc) { let input = Arc::new(InputData { diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index b1f8fc336..4841f1c30 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -1,11 +1,11 @@ // Imports that need to be added manually use bitcoin::bech32::u5; use bitcoin::blockdata::script::Script; -use bitcoin::secp256k1::{PublicKey, Scalar, SecretKey}; +use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey}; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::RecoverableSignature; -use lightning::chain::keysinterface::{Recipient, KeyMaterial, KeysInterface}; +use lightning::chain::keysinterface::{Recipient, KeyMaterial, KeysInterface, EntropySource, NodeSigner, SignerProvider}; use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler}; use lightning::ln::script::ShutdownScript; use lightning::util::enforcing_trait_impls::EnforcingSigner; @@ -90,13 +90,25 @@ struct KeyProvider { node_secret: SecretKey, counter: AtomicU64, } -impl KeysInterface for KeyProvider { - type Signer = EnforcingSigner; +impl EntropySource for KeyProvider { + fn get_secure_random_bytes(&self) -> [u8; 32] { + let ctr = self.counter.fetch_add(1, Ordering::Relaxed); + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + (ctr >> 8*7) as u8, (ctr >> 8*6) as u8, (ctr >> 8*5) as u8, (ctr >> 8*4) as u8, (ctr >> 8*3) as u8, (ctr >> 8*2) as u8, (ctr >> 8*1) as u8, 14, (ctr >> 8*0) as u8] + } +} + +impl NodeSigner for KeyProvider { fn get_node_secret(&self, _recipient: Recipient) -> Result { Ok(self.node_secret.clone()) } + 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)?)) + } + 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 { @@ -107,9 +119,13 @@ impl KeysInterface for KeyProvider { fn get_inbound_payment_key_material(&self) -> KeyMaterial { unreachable!() } - fn get_destination_script(&self) -> Script { unreachable!() } + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { + unreachable!() + } +} - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { unreachable!() } +impl SignerProvider for KeyProvider { + type Signer = EnforcingSigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { unreachable!() } @@ -117,19 +133,15 @@ impl KeysInterface for KeyProvider { unreachable!() } - fn get_secure_random_bytes(&self) -> [u8; 32] { - let ctr = self.counter.fetch_add(1, Ordering::Relaxed); - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - (ctr >> 8*7) as u8, (ctr >> 8*6) as u8, (ctr >> 8*5) as u8, (ctr >> 8*4) as u8, (ctr >> 8*3) as u8, (ctr >> 8*2) as u8, (ctr >> 8*1) as u8, 14, (ctr >> 8*0) as u8] - } - fn read_chan_signer(&self, _data: &[u8]) -> Result { unreachable!() } - fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { - unreachable!() - } + fn get_destination_script(&self) -> Script { unreachable!() } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { unreachable!() } } +impl KeysInterface for KeyProvider {} + #[cfg(test)] mod tests { use lightning::util::logger::{Logger, Record}; diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 1c7209219..a197d1e80 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -17,7 +17,7 @@ extern crate lightning_rapid_gossip_sync; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use lightning::chain::chainmonitor::{ChainMonitor, Persist}; -use lightning::chain::keysinterface::KeysInterface; +use lightning::chain::keysinterface::{KeysInterface, SignerProvider}; use lightning::ln::channelmanager::ChannelManager; use lightning::ln::msgs::{ChannelMessageHandler, OnionMessageHandler, RoutingMessageHandler}; use lightning::ln::peer_handler::{CustomMessageHandler, PeerManager, SocketDescriptor}; @@ -352,7 +352,7 @@ pub async fn process_events_async< EventHandlerFuture: core::future::Future, EventHandler: Fn(Event) -> EventHandlerFuture, PS: 'static + Deref + Send, - M: 'static + Deref::Signer, CF, T, F, L, P>> + Send + Sync, + M: 'static + Deref::Signer, CF, T, F, L, P>> + Send + Sync, CM: 'static + Deref> + Send + Sync, PGS: 'static + Deref> + Send + Sync, RGS: 'static + Deref> + Send, @@ -370,12 +370,12 @@ pub async fn process_events_async< where CA::Target: 'static + chain::Access, CF::Target: 'static + chain::Filter, - CW::Target: 'static + chain::Watch<::Signer>, + CW::Target: 'static + chain::Watch<::Signer>, T::Target: 'static + BroadcasterInterface, K::Target: 'static + KeysInterface, F::Target: 'static + FeeEstimator, L::Target: 'static + Logger, - P::Target: 'static + Persist<::Signer>, + P::Target: 'static + Persist<::Signer>, CMH::Target: 'static + ChannelMessageHandler, OMH::Target: 'static + OnionMessageHandler, RMH::Target: 'static + RoutingMessageHandler, @@ -469,7 +469,7 @@ impl BackgroundProcessor { RMH: 'static + Deref + Send + Sync, EH: 'static + EventHandler + Send, PS: 'static + Deref + Send, - M: 'static + Deref::Signer, CF, T, F, L, P>> + Send + Sync, + M: 'static + Deref::Signer, CF, T, F, L, P>> + Send + Sync, CM: 'static + Deref> + Send + Sync, PGS: 'static + Deref> + Send + Sync, RGS: 'static + Deref> + Send, @@ -484,12 +484,12 @@ impl BackgroundProcessor { where CA::Target: 'static + chain::Access, CF::Target: 'static + chain::Filter, - CW::Target: 'static + chain::Watch<::Signer>, + CW::Target: 'static + chain::Watch<::Signer>, T::Target: 'static + BroadcasterInterface, K::Target: 'static + KeysInterface, F::Target: 'static + FeeEstimator, L::Target: 'static + Logger, - P::Target: 'static + Persist<::Signer>, + P::Target: 'static + Persist<::Signer>, CMH::Target: 'static + ChannelMessageHandler, OMH::Target: 'static + OnionMessageHandler, RMH::Target: 'static + RoutingMessageHandler, @@ -570,7 +570,7 @@ mod tests { use bitcoin::network::constants::Network; use lightning::chain::{BestBlock, Confirm, chainmonitor}; use lightning::chain::channelmonitor::ANTI_REORG_DELAY; - use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeysInterface, KeysManager}; + use lightning::chain::keysinterface::{InMemorySigner, Recipient, EntropySource, KeysInterface, KeysManager, NodeSigner}; use lightning::chain::transaction::OutPoint; use lightning::get_event_msg; use lightning::ln::channelmanager::{self, BREAKDOWN_TIMEOUT, ChainParameters, ChannelManager, SimpleArcChannelManager}; diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs index 1a077f095..c2fe5e4ae 100644 --- a/lightning-invoice/src/utils.rs +++ b/lightning-invoice/src/utils.rs @@ -8,7 +8,7 @@ use bech32::ToBase32; use bitcoin_hashes::Hash; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; -use lightning::chain::keysinterface::{Recipient, KeysInterface}; +use lightning::chain::keysinterface::{Recipient, KeysInterface, NodeSigner, SignerProvider}; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY}; #[cfg(feature = "std")] @@ -237,7 +237,7 @@ pub fn create_invoice_from_channelmanager, description: String, invoice_expiry_delta_secs: u32 ) -> Result> where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -268,7 +268,7 @@ pub fn create_invoice_from_channelmanager_with_description_hash Result> where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -295,7 +295,7 @@ pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_sin duration_since_epoch: Duration, invoice_expiry_delta_secs: u32 ) -> Result> where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -317,7 +317,7 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch Result> where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -338,7 +338,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch Result> where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -363,7 +363,7 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_ invoice_expiry_delta_secs: u32, payment_hash: PaymentHash ) -> Result> where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -387,7 +387,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has invoice_expiry_delta_secs: u32, payment_hash: PaymentHash, payment_secret: PaymentSecret ) -> Result> where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -567,7 +567,7 @@ fn filter_channels( impl Payer for ChannelManager where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -613,7 +613,7 @@ mod test { use crate::{Currency, Description, InvoiceDescription}; use bitcoin_hashes::{Hash, sha256}; use bitcoin_hashes::sha256::Hash as Sha256; - use lightning::chain::keysinterface::PhantomKeysManager; + use lightning::chain::keysinterface::{EntropySource, PhantomKeysManager}; use lightning::ln::{PaymentPreimage, PaymentHash}; use lightning::ln::channelmanager::{self, PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY, PaymentId}; use lightning::ln::functional_test_utils::*; diff --git a/lightning-persister/src/lib.rs b/lightning-persister/src/lib.rs index a949584a6..2653b251c 100644 --- a/lightning-persister/src/lib.rs +++ b/lightning-persister/src/lib.rs @@ -20,7 +20,7 @@ extern crate libc; use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::hashes::hex::FromHex; use lightning::chain::channelmonitor::ChannelMonitor; -use lightning::chain::keysinterface::KeysInterface; +use lightning::chain::keysinterface::{KeysInterface, SignerProvider}; use lightning::util::ser::{ReadableArgs, Writeable}; use lightning::util::persist::KVStorePersister; use std::fs; @@ -61,7 +61,7 @@ impl FilesystemPersister { /// Read `ChannelMonitor`s from disk. pub fn read_channelmonitors ( &self, keys_manager: K - ) -> Result::Signer>)>, std::io::Error> + ) -> Result::Signer>)>, std::io::Error> where K::Target: KeysInterface + Sized, { let mut path = PathBuf::from(&self.path_to_channel_data); @@ -105,7 +105,7 @@ impl FilesystemPersister { let contents = fs::read(&file.path())?; let mut buffer = Cursor::new(&contents); - match <(BlockHash, ChannelMonitor<::Signer>)>::read(&mut buffer, &*keys_manager) { + match <(BlockHash, ChannelMonitor<::Signer>)>::read(&mut buffer, &*keys_manager) { Ok((blockhash, channel_monitor)) => { if channel_monitor.get_funding_txo().0.txid != txid.unwrap() || channel_monitor.get_funding_txo().0.index != index.unwrap() { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "ChannelMonitor was stored in the wrong file")); diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index dc46880d1..76781376f 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -143,8 +143,8 @@ pub enum SpendableOutputDescriptor { /// 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. /// - /// [`get_shutdown_scriptpubkey`]: KeysInterface::get_shutdown_scriptpubkey - /// [`get_destination_script`]: KeysInterface::get_shutdown_scriptpubkey + /// [`get_shutdown_scriptpubkey`]: SignerProvider::get_shutdown_scriptpubkey + /// [`get_destination_script`]: SignerProvider::get_shutdown_scriptpubkey StaticOutput { /// The outpoint which is spendable. outpoint: OutPoint, @@ -399,7 +399,7 @@ pub trait BaseSign { /// /// This data is static, and will never change for a channel once set. For a given [`BaseSign`] /// instance, LDK will call this method exactly once - either immediately after construction - /// (not including if done via [`KeysInterface::read_chan_signer`]) or when the funding + /// (not including if done via [`SignerProvider::read_chan_signer`]) or when the funding /// information has been generated. /// /// channel_parameters.is_populated() MUST be true. @@ -417,7 +417,7 @@ pub trait Sign: BaseSign + Writeable {} /// Specifies the recipient of an invoice. /// -/// This indicates to [`KeysInterface::sign_invoice`] what node secret key should be used to sign +/// This indicates to [`NodeSigner::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. @@ -429,10 +429,15 @@ pub enum Recipient { 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 [`Self::derive_channel_signer`]. - type Signer : Sign; +/// A trait that describes a source of entropy. +pub trait EntropySource { + /// Gets a unique, cryptographically-secure, random 32-byte value. This method must return a + /// different value each time it is called. + fn get_secure_random_bytes(&self) -> [u8; 32]; +} + +/// 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. @@ -442,6 +447,21 @@ pub trait KeysInterface { /// /// 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 + /// 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; + /// Get node id based on the provided [`Recipient`]. This public key corresponds to the secret in /// [`get_node_secret`]. /// @@ -451,10 +471,8 @@ pub trait KeysInterface { /// 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 { - let secp_ctx = Secp256k1::signing_only(); - Ok(PublicKey::from_secret_key(&secp_ctx, &self.get_node_secret(recipient)?)) - } + fn get_node_id(&self, recipient: Recipient) -> Result; + /// 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. @@ -463,36 +481,40 @@ pub trait KeysInterface { /// /// [`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. + + /// 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. /// - /// 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 a script pubkey which we will send funds to when closing a channel. + /// The secret key used to sign the invoice is dependent on the [`Recipient`]. /// - /// 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; + /// Errors if the [`Recipient`] variant is not supported by the implementation. + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result; +} + +/// A trait that can return signer instances for individual channels. +pub trait SignerProvider { + /// A type which implements [`Sign`] which will be returned by [`Self::derive_channel_signer`]. + type Signer : Sign; + /// Generates a unique `channel_keys_id` that can be used to obtain a [`Self::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 + /// [`SignerProvider::derive_channel_signer`]. The `user_channel_id` is provided to allow + /// implementations of [`SignerProvider`] to maintain a mapping between itself and the generated /// `channel_keys_id`. /// /// This method must return a different value each time it is called. 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 + /// [`SignerProvider::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. - /// - /// This method must return a different value each time it is called. - fn get_secure_random_bytes(&self) -> [u8; 32]; + /// Reads a [`Signer`] for this [`KeysInterface`] 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). @@ -507,31 +529,23 @@ pub trait KeysInterface { /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager fn read_chan_signer(&self, reader: &[u8]) -> 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-encoded. - /// - /// 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. + + /// Get a script pubkey which we send funds to when claiming on-chain contestable outputs. /// - /// This method must return the same value each time it is called. + /// 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 a script pubkey which we will send funds to when closing a channel. /// - /// [phantom node payments]: PhantomKeysManager - fn get_inbound_payment_key_material(&self) -> KeyMaterial; + /// 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; } +/// 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. /// @@ -1227,9 +1241,20 @@ impl KeysManager { } } -impl KeysInterface for KeysManager { - type Signer = InMemorySigner; +impl EntropySource for KeysManager { + fn get_secure_random_bytes(&self) -> [u8; 32] { + let mut sha = self.rand_bytes_unique_start.clone(); + + 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[..]); + + sha.input(b"Unique Secure Random Bytes Salt"); + Sha256::from_engine(sha).into_inner() + } +} +impl NodeSigner for KeysManager { fn get_node_secret(&self, recipient: Recipient) -> Result { match recipient { Recipient::Node => Ok(self.node_secret.clone()), @@ -1256,13 +1281,18 @@ impl KeysInterface for KeysManager { self.inbound_payment_key.clone() } - fn get_destination_script(&self) -> Script { - self.destination_script.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)) } +} - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone()) - } +impl SignerProvider for KeysManager { + type Signer = InMemorySigner; 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); @@ -1279,31 +1309,21 @@ impl KeysInterface for KeysManager { self.derive_channel_keys(channel_value_satoshis, &channel_keys_id) } - fn get_secure_random_bytes(&self) -> [u8; 32] { - let mut sha = self.rand_bytes_unique_start.clone(); - - 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[..]); - - 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.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)) + fn get_destination_script(&self) -> Script { + self.destination_script.clone() + } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone()) } } +impl KeysInterface for KeysManager {} + /// Similar to [`KeysManager`], but allows the node using this struct to receive phantom node /// payments. /// @@ -1332,9 +1352,13 @@ pub struct PhantomKeysManager { phantom_node_id: PublicKey, } -impl KeysInterface for PhantomKeysManager { - type Signer = InMemorySigner; +impl EntropySource for PhantomKeysManager { + fn get_secure_random_bytes(&self) -> [u8; 32] { + self.inner.get_secure_random_bytes() + } +} +impl NodeSigner for PhantomKeysManager { fn get_node_secret(&self, recipient: Recipient) -> Result { match recipient { Recipient::Node => self.inner.get_node_secret(Recipient::Node), @@ -1361,13 +1385,15 @@ impl KeysInterface for PhantomKeysManager { self.inbound_payment_key.clone() } - fn get_destination_script(&self) -> Script { - self.inner.get_destination_script() + 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)) } +} - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - self.inner.get_shutdown_scriptpubkey() - } +impl SignerProvider for PhantomKeysManager { + type Signer = InMemorySigner; 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) @@ -1377,21 +1403,21 @@ impl KeysInterface for PhantomKeysManager { 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], 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)) + fn get_destination_script(&self) -> Script { + self.inner.get_destination_script() + } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + self.inner.get_shutdown_scriptpubkey() } } +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] diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 408f1cd7e..bbf0be788 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -1635,7 +1635,7 @@ mod tests { use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment}; use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1}; use crate::util::test_utils; - use crate::chain::keysinterface::{KeysInterface, BaseSign}; + use crate::chain::keysinterface::{KeysInterface, BaseSign, SignerProvider}; use bitcoin::{Network, Txid}; use bitcoin::hashes::Hash; use crate::ln::PaymentHash; diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 67e894a9d..76dc15065 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -35,7 +35,7 @@ use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator}; use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS}; use crate::chain::transaction::{OutPoint, TransactionData}; -use crate::chain::keysinterface::{Sign, KeysInterface, BaseSign}; +use crate::chain::keysinterface::{Sign, EntropySource, KeysInterface, BaseSign, SignerProvider}; use crate::util::events::ClosureReason; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter}; use crate::util::logger::Logger; @@ -740,7 +740,7 @@ pub(super) struct Channel { channel_ready_event_emitted: bool, /// The unique identifier used to re-derive the private key material for the channel through - /// [`KeysInterface::derive_channel_signer`]. + /// [`SignerProvider::derive_channel_signer`]. channel_keys_id: [u8; 32], } @@ -2223,7 +2223,7 @@ impl Channel { pub fn funding_created( &mut self, msg: &msgs::FundingCreated, best_block: BestBlock, keys_source: &K, logger: &L - ) -> Result<(msgs::FundingSigned, ChannelMonitor<::Signer>, Option), ChannelError> + ) -> Result<(msgs::FundingSigned, ChannelMonitor<::Signer>, Option), ChannelError> where K::Target: KeysInterface, L::Target: Logger @@ -2311,7 +2311,7 @@ impl Channel { /// If this call is successful, broadcast the funding transaction (and not before!) pub fn funding_signed( &mut self, msg: &msgs::FundingSigned, best_block: BestBlock, keys_source: &K, logger: &L - ) -> Result<(ChannelMonitor<::Signer>, Transaction, Option), ChannelError> + ) -> Result<(ChannelMonitor<::Signer>, Transaction, Option), ChannelError> where K::Target: KeysInterface, L::Target: Logger @@ -6329,7 +6329,7 @@ impl Writeable for Channel { } const MAX_ALLOC_SIZE: usize = 64*1024; -impl<'a, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<::Signer> +impl<'a, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<::Signer> where K::Target: KeysInterface { fn read(reader: &mut R, args: (&'a K, u32)) -> Result { let (keys_source, serialized_height) = args; @@ -6802,7 +6802,7 @@ mod tests { use crate::ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight}; use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, LowerBoundedFeeEstimator, ConfirmationTarget}; - use crate::chain::keysinterface::{BaseSign, InMemorySigner, Recipient, KeyMaterial, KeysInterface}; + use crate::chain::keysinterface::{BaseSign, InMemorySigner, Recipient, KeyMaterial, KeysInterface, EntropySource, NodeSigner, SignerProvider}; use crate::chain::transaction::OutPoint; use crate::util::config::UserConfig; use crate::util::enforcing_trait_impls::EnforcingSigner; @@ -6851,12 +6851,39 @@ mod tests { struct Keys { signer: InMemorySigner, } - impl KeysInterface for Keys { - type Signer = InMemorySigner; + impl EntropySource for Keys { + fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] } + } + + impl NodeSigner for Keys { fn get_node_secret(&self, _recipient: Recipient) -> Result { panic!(); } + + 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)?)) + } + fn ecdh(&self, _recipient: Recipient, _other_key: &PublicKey, _tweak: Option<&Scalar>) -> Result { panic!(); } + fn get_inbound_payment_key_material(&self) -> KeyMaterial { panic!(); } + + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { panic!(); } + } + + impl SignerProvider for Keys { + type Signer = InMemorySigner; + + fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { + self.signer.channel_keys_id() + } + + fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::Signer { + self.signer.clone() + } + + fn read_chan_signer(&self, _data: &[u8]) -> Result { panic!(); } + fn get_destination_script(&self) -> Script { let secp_ctx = Secp256k1::signing_only(); let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); @@ -6869,18 +6896,10 @@ mod tests { let channel_close_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); ShutdownScript::new_p2wpkh_from_pubkey(PublicKey::from_secret_key(&secp_ctx, &channel_close_key)) } - - fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { - self.signer.channel_keys_id() - } - fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::Signer { - self.signer.clone() - } - fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] } - fn read_chan_signer(&self, _data: &[u8]) -> Result { panic!(); } - fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { panic!(); } } + impl KeysInterface for Keys {} + #[cfg(not(feature = "grind_signatures"))] fn public_from_secret_hex(secp_ctx: &Secp256k1, hex: &str) -> PublicKey { PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(hex).unwrap()[..]).unwrap()) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index b8372ad9b..2bc3eac43 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -52,7 +52,7 @@ use crate::ln::onion_utils; use crate::ln::onion_utils::HTLCFailReason; use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT}; use crate::ln::wire::Encode; -use crate::chain::keysinterface::{Sign, KeysInterface, KeysManager, Recipient}; +use crate::chain::keysinterface::{EntropySource, KeysInterface, KeysManager, NodeSigner, Recipient, Sign, SignerProvider}; use crate::util::config::{UserConfig, ChannelConfig}; use crate::util::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination}; use crate::util::events; @@ -732,7 +732,7 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage // | |__`pending_background_events` // pub struct ChannelManager - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -753,9 +753,9 @@ pub struct ChannelManager /// See `ChannelManager` struct-level documentation for lock order requirements. #[cfg(any(test, feature = "_test_utils"))] - pub(super) channel_state: Mutex::Signer>>, + pub(super) channel_state: Mutex::Signer>>, #[cfg(not(any(test, feature = "_test_utils")))] - channel_state: Mutex::Signer>>, + channel_state: Mutex::Signer>>, /// Storage for PaymentSecrets and any requirements on future inbound payments before we will /// expose them to users via a PaymentClaimable event. HTLCs which do not meet the requirements @@ -1571,7 +1571,7 @@ macro_rules! emit_channel_ready_event { } impl ChannelManager - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -1739,7 +1739,7 @@ impl ChannelManager::Signer>)) -> bool>(&self, f: Fn) -> Vec { + fn list_channels_with_filter::Signer>)) -> bool>(&self, f: Fn) -> Vec { let mut res = Vec::new(); { let channel_state = self.channel_state.lock().unwrap(); @@ -1823,7 +1823,7 @@ impl ChannelManager::Signer>, closure_reason: ClosureReason) { + fn issue_channel_close_events(&self, channel: &Channel<::Signer>, closure_reason: ClosureReason) { let mut pending_events_lock = self.pending_events.lock().unwrap(); match channel.unbroadcasted_funding() { Some(transaction) => { @@ -2380,7 +2380,7 @@ impl ChannelManager::Signer>) -> Result { + fn get_channel_update_for_broadcast(&self, chan: &Channel<::Signer>) -> Result { if !chan.should_announce() { return Err(LightningError { err: "Cannot broadcast a channel_update for a private channel".to_owned(), @@ -2399,7 +2399,7 @@ impl ChannelManager::Signer>) -> Result { + fn get_channel_update_for_unicast(&self, chan: &Channel<::Signer>) -> Result { log_trace!(self.logger, "Attempting to generate channel update for channel {}", log_bytes!(chan.channel_id())); let short_channel_id = match chan.get_short_channel_id().or(chan.latest_inbound_scid_alias()) { None => return Err(LightningError{err: "Channel not yet established".to_owned(), action: msgs::ErrorAction::IgnoreError}), @@ -2408,7 +2408,7 @@ impl ChannelManager::Signer>) -> Result { + fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<::Signer>) -> Result { log_trace!(self.logger, "Generating channel update for channel {}", log_bytes!(chan.channel_id())); let were_node_one = PublicKey::from_secret_key(&self.secp_ctx, &self.our_network_key).serialize()[..] < chan.get_counterparty_node_id().serialize()[..]; @@ -2894,7 +2894,7 @@ impl ChannelManager::Signer>, &Transaction) -> Result>( + fn funding_transaction_generated_intern::Signer>, &Transaction) -> Result>( &self, temporary_channel_id: &[u8; 32], _counterparty_node_id: &PublicKey, funding_transaction: Transaction, find_funding_output: FundingOutput ) -> Result<(), APIError> { let (chan, msg) = { @@ -3623,7 +3623,7 @@ impl ChannelManager::Signer>, new_feerate: u32) -> NotifyOption { + fn update_channel_fee(&self, chan_id: &[u8; 32], chan: &mut Channel<::Signer>, new_feerate: u32) -> NotifyOption { if !chan.is_outbound() { return NotifyOption::SkipPersist; } // If the feerate has decreased by less than half, don't bother if new_feerate <= chan.get_feerate() && new_feerate * 2 > chan.get_feerate() { @@ -3850,7 +3850,7 @@ impl ChannelManager::Signer>) -> (u16, Vec) { + fn get_htlc_inbound_temp_fail_err_and_data(&self, desired_err_code: u16, chan: &Channel<::Signer>) -> (u16, Vec) { // We can't be sure what SCID was used when relaying inbound towards us, so we have to // guess somewhat. If its a public channel, we figure best to just use the real SCID (as // we're not leaking that we have a channel with the counterparty), otherwise we try to use @@ -3870,7 +3870,7 @@ impl ChannelManager::Signer>) -> (u16, Vec) { + fn get_htlc_temp_fail_err_and_data(&self, desired_err_code: u16, scid: u64, chan: &Channel<::Signer>) -> (u16, Vec) { debug_assert_eq!(desired_err_code & 0x1000, 0x1000); if let Ok(upd) = self.get_channel_update_for_onion(scid, chan) { let mut enc = VecWriter(Vec::with_capacity(upd.serialized_length() + 6)); @@ -4206,7 +4206,7 @@ impl ChannelManager) -> Option>(&self, - mut channel_state_lock: MutexGuard::Signer>>, + mut channel_state_lock: MutexGuard::Signer>>, prev_hop: HTLCPreviousHopData, payment_preimage: PaymentPreimage, completion_action: ComplFunc) -> Result<(), (PublicKey, MsgHandleErrInternal)> { //TODO: Delay the claimed_funds relaying just like we do outbound relay! @@ -4326,7 +4326,7 @@ impl ChannelManager::Signer>>, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option, from_onchain: bool, next_channel_id: [u8; 32]) { + fn claim_funds_internal(&self, channel_state_lock: MutexGuard::Signer>>, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option, from_onchain: bool, next_channel_id: [u8; 32]) { match source { HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => { mem::drop(channel_state_lock); @@ -4425,7 +4425,7 @@ impl ChannelManager, - channel: &mut Channel<::Signer>, raa: Option, + channel: &mut Channel<::Signer>, raa: Option, commitment_update: Option, order: RAACommitmentOrder, pending_forwards: Vec<(PendingHTLCInfo, u64)>, funding_broadcastable: Option, channel_ready: Option, announcement_sigs: Option) @@ -4968,7 +4968,7 @@ impl ChannelManager::Signer>, pending_forward_info: PendingHTLCStatus, error_code: u16| { + let create_pending_htlc_status = |chan: &Channel<::Signer>, pending_forward_info: PendingHTLCStatus, error_code: u16| { // If the update_add is completely bogus, the call will Err and we will close, // but if we've sent a shutdown and they haven't acknowledged it yet, we just // want to reject the new HTLC and fail it backwards instead of forwarding. @@ -5865,7 +5865,7 @@ impl ChannelManager MessageSendEventsProvider for ChannelManager - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -5905,7 +5905,7 @@ impl MessageSendEventsProvider impl EventsProvider for ChannelManager where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -5941,7 +5941,7 @@ where impl chain::Listen for ChannelManager where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -5978,7 +5978,7 @@ where impl chain::Confirm for ChannelManager where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -6065,7 +6065,7 @@ where impl ChannelManager where - M::Target: chain::Watch<::Signer>, + M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -6074,7 +6074,7 @@ where /// Calls a function which handles an on-chain event (blocks dis/connected, transactions /// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by /// the function. - fn do_chain_event::Signer>) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>, Option), ClosureReason>> + fn do_chain_event::Signer>) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>, Option), ClosureReason>> (&self, height_opt: Option, f: FN) { // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called // during initialization prior to the chain_monitor being fully configured in some cases. @@ -6265,7 +6265,7 @@ where impl ChannelMessageHandler for ChannelManager - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -6975,7 +6975,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, ); impl Writeable for ChannelManager - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -7172,7 +7172,7 @@ impl Writeable for ChannelMana /// /// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor pub struct ChannelManagerReadArgs<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -7217,12 +7217,12 @@ pub struct ChannelManagerReadArgs<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: /// this struct. /// /// (C-not exported) because we have no HashMap bindings - pub channel_monitors: HashMap::Signer>>, + pub channel_monitors: HashMap::Signer>>, } impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManagerReadArgs<'a, M, T, K, F, L> - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -7232,7 +7232,7 @@ impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> /// HashMap for you. This is primarily useful for C bindings where it is not practical to /// populate a HashMap directly from C. pub fn new(keys_manager: K, fee_estimator: F, chain_monitor: M, tx_broadcaster: T, logger: L, default_config: UserConfig, - mut channel_monitors: Vec<&'a mut ChannelMonitor<::Signer>>) -> Self { + mut channel_monitors: Vec<&'a mut ChannelMonitor<::Signer>>) -> Self { Self { keys_manager, fee_estimator, chain_monitor, tx_broadcaster, logger, default_config, channel_monitors: channel_monitors.drain(..).map(|monitor| { (monitor.get_funding_txo().0, monitor) }).collect() @@ -7244,7 +7244,7 @@ impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> // SipmleArcChannelManager type: impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ReadableArgs> for (BlockHash, Arc>) - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -7258,7 +7258,7 @@ impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ReadableArgs> for (BlockHash, ChannelManager) - where M::Target: chain::Watch<::Signer>, + where M::Target: chain::Watch<::Signer>, T::Target: BroadcasterInterface, K::Target: KeysInterface, F::Target: FeeEstimator, @@ -7280,7 +7280,7 @@ impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> let mut short_to_chan_info = HashMap::with_capacity(cmp::min(channel_count as usize, 128)); let mut channel_closures = Vec::new(); for _ in 0..channel_count { - let mut channel: Channel<::Signer> = Channel::read(reader, (&args.keys_manager, best_block_height))?; + let mut channel: Channel<::Signer> = Channel::read(reader, (&args.keys_manager, best_block_height))?; let funding_txo = channel.get_funding_txo().ok_or(DecodeError::InvalidValue)?; funding_txo_set.insert(funding_txo.clone()); if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) { @@ -7788,7 +7788,7 @@ mod tests { use crate::util::errors::APIError; use crate::util::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; use crate::util::test_utils; - use crate::chain::keysinterface::KeysInterface; + use crate::chain::keysinterface::{EntropySource, KeysInterface}; #[test] fn test_notify_limits() { @@ -8354,7 +8354,7 @@ mod tests { pub mod bench { use crate::chain::Listen; use crate::chain::chainmonitor::{ChainMonitor, Persist}; - use crate::chain::keysinterface::{KeysManager, KeysInterface, InMemorySigner}; + use crate::chain::keysinterface::{EntropySource, KeysManager, KeysInterface, InMemorySigner}; use crate::ln::channelmanager::{self, BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentId}; use crate::ln::functional_test_utils::*; use crate::ln::msgs::{ChannelMessageHandler, Init}; diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index bdf40f466..63b6e7867 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -10,7 +10,7 @@ //! A bunch of useful utilities for building networks of nodes and exchanging messages between //! nodes for functional tests. -use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, keysinterface::KeysInterface}; +use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, keysinterface::EntropySource}; use crate::chain::channelmonitor::ChannelMonitor; use crate::chain::transaction::OutPoint; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; @@ -1352,7 +1352,7 @@ macro_rules! get_payment_preimage_hash { #[macro_export] macro_rules! get_route { ($send_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{ - use $crate::chain::keysinterface::KeysInterface; + use $crate::chain::keysinterface::EntropySource; let scorer = $crate::util::test_utils::TestScorer::with_penalty(0); let keys_manager = $crate::util::test_utils::TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 28719f2d6..f18f28a13 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -17,7 +17,7 @@ use crate::chain::chaininterface::LowerBoundedFeeEstimator; use crate::chain::channelmonitor; use crate::chain::channelmonitor::{CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY}; use crate::chain::transaction::OutPoint; -use crate::chain::keysinterface::{BaseSign, KeysInterface}; +use crate::chain::keysinterface::{BaseSign, EntropySource, KeysInterface}; use crate::ln::{PaymentPreimage, PaymentSecret, PaymentHash}; use crate::ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT}; use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA}; diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index 731b68ce4..ba1b1fe57 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -14,7 +14,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::cmp::fixed_time_eq; use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; -use crate::chain::keysinterface::{KeyMaterial, KeysInterface}; +use crate::chain::keysinterface::{KeyMaterial, KeysInterface, EntropySource}; use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::msgs; use crate::ln::msgs::MAX_VALUE_MSAT; @@ -35,9 +35,9 @@ const AMT_MSAT_LEN: usize = 8; const METHOD_TYPE_OFFSET: usize = 5; /// A set of keys that were HKDF-expanded from an initial call to -/// [`KeysInterface::get_inbound_payment_key_material`]. +/// [`NodeSigner::get_inbound_payment_key_material`]. /// -/// [`KeysInterface::get_inbound_payment_key_material`]: crate::chain::keysinterface::KeysInterface::get_inbound_payment_key_material +/// [`NodeSigner::get_inbound_payment_key_material`]: crate::chain::keysinterface::NodeSigner::get_inbound_payment_key_material pub struct ExpandedKey { /// The key used to encrypt the bytes containing the payment metadata (i.e. the amount and /// expiry, included for payment verification on decryption). @@ -84,13 +84,14 @@ impl Method { /// `ChannelManager` is required. Useful for generating invoices for [phantom node payments] without /// a `ChannelManager`. /// -/// `keys` is generated by calling [`KeysInterface::get_inbound_payment_key_material`] and then +/// `keys` is generated by calling [`NodeSigner::get_inbound_payment_key_material`] and then /// calling [`ExpandedKey::new`] with its result. It is recommended to cache this value and not /// regenerate it for each new inbound payment. /// /// `current_time` is a Unix timestamp representing the current time. /// /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager +/// [`NodeSigner::get_inbound_payment_key_material`]: crate::chain::keysinterface::NodeSigner::get_inbound_payment_key_material pub fn create(keys: &ExpandedKey, min_value_msat: Option, invoice_expiry_delta_secs: u32, keys_manager: &K, current_time: u64) -> Result<(PaymentHash, PaymentSecret), ()> where K::Target: KeysInterface { @@ -176,7 +177,7 @@ fn construct_payment_secret(iv_bytes: &[u8; IV_LEN], metadata_bytes: &[u8; METAD /// /// The metadata is constructed as: /// payment method (3 bits) || payment amount (8 bytes - 3 bits) || expiry (8 bytes) -/// and encrypted using a key derived from [`KeysInterface::get_inbound_payment_key_material`]. +/// and encrypted using a key derived from [`NodeSigner::get_inbound_payment_key_material`]. /// /// Then on payment receipt, we verify in this method that the payment preimage and payment secret /// match what was constructed. @@ -197,7 +198,7 @@ fn construct_payment_secret(iv_bytes: &[u8; IV_LEN], metadata_bytes: &[u8; METAD /// /// See [`ExpandedKey`] docs for more info on the individual keys used. /// -/// [`KeysInterface::get_inbound_payment_key_material`]: crate::chain::keysinterface::KeysInterface::get_inbound_payment_key_material +/// [`NodeSigner::get_inbound_payment_key_material`]: crate::chain::keysinterface::NodeSigner::get_inbound_payment_key_material /// [`create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment /// [`create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash pub(super) fn verify(payment_hash: PaymentHash, payment_data: &msgs::FinalOnionHopData, highest_seen_timestamp: u64, keys: &ExpandedKey, logger: &L) -> Result, ()> diff --git a/lightning/src/ln/onion_route_tests.rs b/lightning/src/ln/onion_route_tests.rs index ca2fd7658..4f90202fd 100644 --- a/lightning/src/ln/onion_route_tests.rs +++ b/lightning/src/ln/onion_route_tests.rs @@ -12,7 +12,7 @@ //! returned errors decode to the correct thing. use crate::chain::channelmonitor::{CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS}; -use crate::chain::keysinterface::{KeysInterface, Recipient}; +use crate::chain::keysinterface::{EntropySource, KeysInterface, NodeSigner, Recipient}; use crate::ln::{PaymentHash, PaymentSecret}; use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS; use crate::ln::channelmanager::{self, HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingAddHTLCInfo, PendingHTLCInfo, PendingHTLCRouting, PaymentId}; diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index ff65bac4b..faac5e531 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -14,7 +14,7 @@ use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch}; use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS}; use crate::chain::transaction::OutPoint; -use crate::chain::keysinterface::KeysInterface; +use crate::chain::keysinterface::{EntropySource, KeysInterface}; use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS; use crate::ln::channelmanager::{self, BREAKDOWN_TIMEOUT, ChannelManager, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS}; use crate::ln::msgs; diff --git a/lightning/src/ln/priv_short_conf_tests.rs b/lightning/src/ln/priv_short_conf_tests.rs index f2166246d..4d1849049 100644 --- a/lightning/src/ln/priv_short_conf_tests.rs +++ b/lightning/src/ln/priv_short_conf_tests.rs @@ -12,7 +12,7 @@ //! LSP). use crate::chain::ChannelMonitorUpdateStatus; -use crate::chain::keysinterface::{Recipient, KeysInterface}; +use crate::chain::keysinterface::{Recipient, KeysInterface, NodeSigner}; use crate::ln::channelmanager::{self, ChannelManager, MIN_CLTV_EXPIRY_DELTA, PaymentId}; use crate::routing::gossip::RoutingFees; use crate::routing::router::{PaymentParameters, RouteHint, RouteHintHop}; diff --git a/lightning/src/ln/reload_tests.rs b/lightning/src/ln/reload_tests.rs index 6c04cbe0c..ff0b857ff 100644 --- a/lightning/src/ln/reload_tests.rs +++ b/lightning/src/ln/reload_tests.rs @@ -12,7 +12,7 @@ use crate::chain::{ChannelMonitorUpdateStatus, Watch}; use crate::chain::chaininterface::LowerBoundedFeeEstimator; use crate::chain::channelmonitor::ChannelMonitor; -use crate::chain::keysinterface::KeysInterface; +use crate::chain::keysinterface::{EntropySource, KeysInterface}; use crate::chain::transaction::OutPoint; use crate::ln::channelmanager::{self, ChannelManager, ChannelManagerReadArgs, PaymentId}; use crate::ln::msgs; diff --git a/lightning/src/ln/shutdown_tests.rs b/lightning/src/ln/shutdown_tests.rs index 48b452cdd..6a0d7c61f 100644 --- a/lightning/src/ln/shutdown_tests.rs +++ b/lightning/src/ln/shutdown_tests.rs @@ -9,7 +9,7 @@ //! Tests of our shutdown and closing_signed negotiation logic. -use crate::chain::keysinterface::KeysInterface; +use crate::chain::keysinterface::{EntropySource, KeysInterface, SignerProvider}; use crate::chain::transaction::OutPoint; use crate::ln::channelmanager::{self, PaymentSendFailure, PaymentId}; use crate::routing::router::{PaymentParameters, get_route}; diff --git a/lightning/src/onion_message/blinded_path.rs b/lightning/src/onion_message/blinded_path.rs index 31a23bc17..49949bc0d 100644 --- a/lightning/src/onion_message/blinded_path.rs +++ b/lightning/src/onion_message/blinded_path.rs @@ -13,7 +13,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey}; -use crate::chain::keysinterface::{KeysInterface, Recipient}; +use crate::chain::keysinterface::{KeysInterface, NodeSigner, Recipient}; use super::packet::ControlTlvs; use super::utils; use crate::ln::msgs::DecodeError; diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index f65a50ee1..7fc225cbc 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -9,7 +9,7 @@ //! Onion message testing and test utilities live here. -use crate::chain::keysinterface::{KeysInterface, Recipient}; +use crate::chain::keysinterface::{KeysInterface, NodeSigner, Recipient}; use crate::ln::features::InitFeatures; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; use super::{BlindedPath, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError}; diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 269b5f8cb..d9d6070ae 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -15,7 +15,7 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey}; -use crate::chain::keysinterface::{KeysInterface, KeysManager, Recipient}; +use crate::chain::keysinterface::{EntropySource, KeysInterface, KeysManager, NodeSigner, Recipient}; use crate::ln::features::{InitFeatures, NodeFeatures}; use crate::ln::msgs::{self, OnionMessageHandler}; use crate::ln::onion_utils; @@ -160,7 +160,7 @@ pub enum SendError { GetNodeIdFailed, /// We attempted to send to a blinded path where we are the introduction node, and failed to /// advance the blinded path to make the second hop the new introduction node. Either - /// [`KeysInterface::ecdh`] failed, we failed to tweak the current blinding point to get the + /// [`NodeSigner::ecdh`] failed, we failed to tweak the current blinding point to get the /// new blinding point, or we were attempting to send to ourselves. BlindedPathAdvanceFailed, } diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 09cee2a2e..c1ef01bff 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -2138,7 +2138,7 @@ mod tests { use crate::routing::scoring::{ChannelUsage, Score, ProbabilisticScorer, ProbabilisticScoringParameters}; use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel}; use crate::chain::transaction::OutPoint; - use crate::chain::keysinterface::KeysInterface; + use crate::chain::keysinterface::{EntropySource, KeysInterface}; use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use crate::ln::msgs::{ErrorAction, LightningError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; use crate::ln::channelmanager; @@ -5652,7 +5652,7 @@ mod benches { use bitcoin::hashes::Hash; use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use crate::chain::transaction::OutPoint; - use crate::chain::keysinterface::{KeysManager,KeysInterface}; + use crate::chain::keysinterface::{EntropySource, KeysManager,KeysInterface}; use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails}; use crate::ln::features::InvoiceFeatures; use crate::routing::gossip::NetworkGraph; diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs index c9c76f4e9..5b1bb6729 100644 --- a/lightning/src/util/config.rs +++ b/lightning/src/util/config.rs @@ -120,11 +120,11 @@ pub struct ChannelHandshakeConfig { /// any attacker who is able to take control of a channel can just as easily send the funds via /// lightning payments, so we never require that our counterparties support this option. /// - /// The upfront key committed is provided from [`KeysInterface::get_shutdown_scriptpubkey`]. + /// The upfront key committed is provided from [`SignerProvider::get_shutdown_scriptpubkey`]. /// /// Default value: true. /// - /// [`KeysInterface::get_shutdown_scriptpubkey`]: crate::chain::keysinterface::KeysInterface::get_shutdown_scriptpubkey + /// [`SignerProvider::get_shutdown_scriptpubkey`]: crate::chain::keysinterface::SignerProvider::get_shutdown_scriptpubkey pub commit_upfront_shutdown_pubkey: bool, /// The Proportion of the channel value to configure as counterparty's channel reserve, diff --git a/lightning/src/util/errors.rs b/lightning/src/util/errors.rs index 17e55a979..b7d562e54 100644 --- a/lightning/src/util/errors.rs +++ b/lightning/src/util/errors.rs @@ -55,13 +55,13 @@ pub enum APIError { /// [`chain::Watch::update_channel`]: crate::chain::Watch::update_channel /// [`ChannelMonitorUpdateStatus::InProgress`]: crate::chain::ChannelMonitorUpdateStatus::InProgress MonitorUpdateInProgress, - /// [`KeysInterface::get_shutdown_scriptpubkey`] returned a shutdown scriptpubkey incompatible + /// [`SignerProvider::get_shutdown_scriptpubkey`] returned a shutdown scriptpubkey incompatible /// with the channel counterparty as negotiated in [`InitFeatures`]. /// /// Using a SegWit v0 script should resolve this issue. If you cannot, you won't be able to open /// a channel or cooperatively close one with this peer (and will have to force-close instead). /// - /// [`KeysInterface::get_shutdown_scriptpubkey`]: crate::chain::keysinterface::KeysInterface::get_shutdown_scriptpubkey + /// [`SignerProvider::get_shutdown_scriptpubkey`]: crate::chain::keysinterface::SignerProvider::get_shutdown_scriptpubkey /// [`InitFeatures`]: crate::ln::features::InitFeatures IncompatibleShutdownScript { /// The incompatible shutdown script. diff --git a/lightning/src/util/persist.rs b/lightning/src/util/persist.rs index 31e532394..0a8990f53 100644 --- a/lightning/src/util/persist.rs +++ b/lightning/src/util/persist.rs @@ -16,7 +16,7 @@ use crate::routing::scoring::WriteableScore; use crate::chain; use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use crate::chain::chainmonitor::{Persist, MonitorUpdateId}; -use crate::chain::keysinterface::{Sign, KeysInterface}; +use crate::chain::keysinterface::{Sign, KeysInterface, SignerProvider}; use crate::chain::transaction::OutPoint; use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate}; use crate::ln::channelmanager::ChannelManager; @@ -34,7 +34,7 @@ pub trait KVStorePersister { /// Trait that handles persisting a [`ChannelManager`], [`NetworkGraph`], and [`WriteableScore`] to disk. pub trait Persister<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref, S: WriteableScore<'a>> - where M::Target: 'static + chain::Watch<::Signer>, + where M::Target: 'static + chain::Watch<::Signer>, T::Target: 'static + BroadcasterInterface, K::Target: 'static + KeysInterface, F::Target: 'static + FeeEstimator, @@ -51,7 +51,7 @@ pub trait Persister<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref, S: Wri } impl<'a, A: KVStorePersister, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref, S: WriteableScore<'a>> Persister<'a, M, T, K, F, L, S> for A - where M::Target: 'static + chain::Watch<::Signer>, + where M::Target: 'static + chain::Watch<::Signer>, T::Target: 'static + BroadcasterInterface, K::Target: 'static + KeysInterface, F::Target: 'static + FeeEstimator, diff --git a/lightning/src/util/scid_utils.rs b/lightning/src/util/scid_utils.rs index 1d951b8f9..3db98553a 100644 --- a/lightning/src/util/scid_utils.rs +++ b/lightning/src/util/scid_utils.rs @@ -68,7 +68,7 @@ pub fn scid_from_parts(block: u64, tx_index: u64, vout_index: u64) -> Result); @@ -72,17 +72,27 @@ impl chaininterface::FeeEstimator for TestFeeEstimator { } pub struct OnlyReadsKeysInterface {} -impl keysinterface::KeysInterface for OnlyReadsKeysInterface { - type Signer = EnforcingSigner; +impl EntropySource for OnlyReadsKeysInterface { + fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }} + +impl NodeSigner for OnlyReadsKeysInterface { fn get_node_secret(&self, _recipient: Recipient) -> Result { unreachable!(); } + 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)?)) + } fn ecdh(&self, _recipient: Recipient, _other_key: &PublicKey, _tweak: Option<&Scalar>) -> Result { unreachable!(); } fn get_inbound_payment_key_material(&self) -> KeyMaterial { unreachable!(); } - fn get_destination_script(&self) -> Script { unreachable!(); } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { unreachable!(); } + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { unreachable!(); } +} + +impl SignerProvider for OnlyReadsKeysInterface { + type Signer = EnforcingSigner; + fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { unreachable!(); } + fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::Signer { unreachable!(); } - fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] } fn read_chan_signer(&self, mut reader: &[u8]) -> Result { let dummy_sk = SecretKey::from_slice(&[42; 32]).unwrap(); @@ -95,7 +105,12 @@ impl keysinterface::KeysInterface for OnlyReadsKeysInterface { false )) } - fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { unreachable!(); } + + fn get_destination_script(&self) -> Script { unreachable!(); } + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { unreachable!(); } +} + +impl keysinterface::KeysInterface for OnlyReadsKeysInterface { } pub struct TestChainMonitor<'a> { @@ -603,32 +618,40 @@ pub struct TestKeysInterface { expectations: Mutex>>, } -impl keysinterface::KeysInterface for TestKeysInterface { - type Signer = EnforcingSigner; +impl EntropySource for TestKeysInterface { + fn get_secure_random_bytes(&self) -> [u8; 32] { + let override_random_bytes = self.override_random_bytes.lock().unwrap(); + if let Some(bytes) = &*override_random_bytes { + return *bytes; + } + self.backing.get_secure_random_bytes() + } +} +impl NodeSigner for TestKeysInterface { fn get_node_secret(&self, recipient: Recipient) -> Result { self.backing.get_node_secret(recipient) } + fn get_node_id(&self, recipient: Recipient) -> Result { self.backing.get_node_id(recipient) } + fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { self.backing.ecdh(recipient, other_key, tweak) } + fn get_inbound_payment_key_material(&self) -> keysinterface::KeyMaterial { self.backing.get_inbound_payment_key_material() } - fn get_destination_script(&self) -> Script { self.backing.get_destination_script() } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - match &mut *self.expectations.lock().unwrap() { - None => self.backing.get_shutdown_scriptpubkey(), - Some(expectations) => match expectations.pop_front() { - None => panic!("Unexpected get_shutdown_scriptpubkey"), - Some(expectation) => expectation.returns, - }, - } + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { + self.backing.sign_invoice(hrp_bytes, invoice_data, recipient) } +} + +impl SignerProvider for TestKeysInterface { + type Signer = EnforcingSigner; fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { self.backing.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) @@ -640,14 +663,6 @@ impl keysinterface::KeysInterface for TestKeysInterface { EnforcingSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check) } - fn get_secure_random_bytes(&self) -> [u8; 32] { - let override_random_bytes = self.override_random_bytes.lock().unwrap(); - if let Some(bytes) = &*override_random_bytes { - return *bytes; - } - self.backing.get_secure_random_bytes() - } - fn read_chan_signer(&self, buffer: &[u8]) -> Result { let mut reader = io::Cursor::new(buffer); @@ -661,11 +676,21 @@ impl keysinterface::KeysInterface for TestKeysInterface { )) } - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { - self.backing.sign_invoice(hrp_bytes, invoice_data, recipient) + fn get_destination_script(&self) -> Script { self.backing.get_destination_script() } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + match &mut *self.expectations.lock().unwrap() { + None => self.backing.get_shutdown_scriptpubkey(), + Some(expectations) => match expectations.pop_front() { + None => panic!("Unexpected get_shutdown_scriptpubkey"), + Some(expectation) => expectation.returns, + }, + } } } +impl keysinterface::KeysInterface for TestKeysInterface {} + impl TestKeysInterface { pub fn new(seed: &[u8; 32], network: Network) -> Self { let now = Duration::from_secs(genesis_block(network).header.time as u64); @@ -678,7 +703,7 @@ impl TestKeysInterface { } } - /// Sets an expectation that [`keysinterface::KeysInterface::get_shutdown_scriptpubkey`] is + /// Sets an expectation that [`keysinterface::SignerProvider::get_shutdown_scriptpubkey`] is /// called. pub fn expect(&self, expectation: OnGetShutdownScriptpubkey) -> &Self { self.expectations.lock().unwrap() @@ -726,7 +751,7 @@ impl Drop for TestKeysInterface { } } -/// An expectation that [`keysinterface::KeysInterface::get_shutdown_scriptpubkey`] was called and +/// An expectation that [`keysinterface::SignerProvider::get_shutdown_scriptpubkey`] was called and /// returns a [`ShutdownScript`]. pub struct OnGetShutdownScriptpubkey { /// A shutdown script used to close a channel.