Skip to content

Commit 86d5944

Browse files
authored
Merge pull request #1177 from valentinewallace/2021-11-derivable-payment-secret
Stop storing pending inbound payment data; instead make it derivable on receive
2 parents cec8ce0 + d41499a commit 86d5944

File tree

11 files changed

+525
-83
lines changed

11 files changed

+525
-83
lines changed

fuzz/src/chanmon_consistency.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use lightning::chain::{BestBlock, ChannelMonitorUpdateErr, chainmonitor, channel
3434
use lightning::chain::channelmonitor::{ChannelMonitor, MonitorEvent};
3535
use lightning::chain::transaction::OutPoint;
3636
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
37-
use lightning::chain::keysinterface::{KeysInterface, InMemorySigner};
37+
use lightning::chain::keysinterface::{KeyMaterial, KeysInterface, InMemorySigner};
3838
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
3939
use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs};
4040
use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
@@ -164,6 +164,10 @@ impl KeysInterface for KeyProvider {
164164
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()
165165
}
166166

167+
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
168+
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])
169+
}
170+
167171
fn get_destination_script(&self) -> Script {
168172
let secp_ctx = Secp256k1::signing_only();
169173
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();

fuzz/src/full_stack.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use lightning::chain::{BestBlock, Confirm, Listen};
3131
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
3232
use lightning::chain::chainmonitor;
3333
use lightning::chain::transaction::OutPoint;
34-
use lightning::chain::keysinterface::{InMemorySigner, KeysInterface};
34+
use lightning::chain::keysinterface::{InMemorySigner, KeyMaterial, KeysInterface};
3535
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
3636
use lightning::ln::channelmanager::{ChainParameters, ChannelManager};
3737
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,IgnoringMessageHandler};
@@ -56,6 +56,7 @@ use bitcoin::secp256k1::Secp256k1;
5656

5757
use std::cell::RefCell;
5858
use std::collections::{HashMap, hash_map};
59+
use std::convert::TryInto;
5960
use std::cmp;
6061
use std::sync::{Arc, Mutex};
6162
use std::sync::atomic::{AtomicU64,AtomicUsize,Ordering};
@@ -257,6 +258,7 @@ impl<'a> Drop for MoneyLossDetector<'a> {
257258

258259
struct KeyProvider {
259260
node_secret: SecretKey,
261+
inbound_payment_key: KeyMaterial,
260262
counter: AtomicU64,
261263
}
262264
impl KeysInterface for KeyProvider {
@@ -266,6 +268,10 @@ impl KeysInterface for KeyProvider {
266268
self.node_secret.clone()
267269
}
268270

271+
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
272+
self.inbound_payment_key.clone()
273+
}
274+
269275
fn get_destination_script(&self) -> Script {
270276
let secp_ctx = Secp256k1::signing_only();
271277
let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
@@ -365,11 +371,13 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
365371
Err(_) => return,
366372
};
367373

374+
let inbound_payment_key = [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, 42];
375+
368376
let broadcast = Arc::new(TestBroadcaster{ txn_broadcasted: Mutex::new(Vec::new()) });
369377
let monitor = Arc::new(chainmonitor::ChainMonitor::new(None, broadcast.clone(), Arc::clone(&logger), fee_est.clone(),
370378
Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) })));
371379

372-
let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), counter: AtomicU64::new(0) });
380+
let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), inbound_payment_key: KeyMaterial(inbound_payment_key.try_into().unwrap()), counter: AtomicU64::new(0) });
373381
let mut config = UserConfig::default();
374382
config.channel_options.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
375383
config.channel_options.announced_channel = get_slice!(1)[0] != 0;

lightning-invoice/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,9 @@ pub enum CreationError {
14131413

14141414
/// The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
14151415
ExpiryTimeOutOfBounds,
1416+
1417+
/// The supplied millisatoshi amount was greater than the total bitcoin supply.
1418+
InvalidAmount,
14161419
}
14171420

14181421
impl Display for CreationError {
@@ -1422,6 +1425,7 @@ impl Display for CreationError {
14221425
CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
14231426
CreationError::TimestampOutOfBounds => f.write_str("The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`"),
14241427
CreationError::ExpiryTimeOutOfBounds => f.write_str("The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`"),
1428+
CreationError::InvalidAmount => f.write_str("The supplied millisatoshi amount was greater than the total bitcoin supply"),
14251429
}
14261430
}
14271431
}

lightning-invoice/src/utils.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Convenient utilities to create an invoice.
22
3-
use {Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError, RawInvoice};
3+
use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError, RawInvoice};
44
use payment::{Payer, Router};
55

66
use bech32::ToBase32;
@@ -60,10 +60,11 @@ where
6060
}]));
6161
}
6262

63+
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
64+
// supply.
6365
let (payment_hash, payment_secret) = channelmanager.create_inbound_payment(
64-
amt_msat,
65-
DEFAULT_EXPIRY_TIME.try_into().unwrap(),
66-
);
66+
amt_msat, DEFAULT_EXPIRY_TIME.try_into().unwrap())
67+
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
6768
let our_node_pubkey = channelmanager.get_our_node_id();
6869
let mut invoice = InvoiceBuilder::new(network)
6970
.description(description)

lightning/src/chain/keysinterface.rs

+20
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ use core::sync::atomic::{AtomicUsize, Ordering};
4343
use io::{self, Error};
4444
use ln::msgs::{DecodeError, MAX_VALUE_MSAT};
4545

46+
/// Used as initial key material, to be expanded into multiple secret keys (but not to be used
47+
/// directly). This is used within LDK to encrypt/decrypt inbound payment data.
48+
/// (C-not exported) as we just use [u8; 32] directly
49+
#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
50+
pub struct KeyMaterial(pub [u8; 32]);
51+
4652
/// Information about a spendable output to a P2WSH script. See
4753
/// SpendableOutputDescriptor::DelayedPaymentOutput for more details on how to spend this.
4854
#[derive(Clone, Debug, PartialEq)]
@@ -397,6 +403,11 @@ pub trait KeysInterface {
397403
/// this trait to parse the invoice and make sure they're signing what they expect, rather than
398404
/// blindly signing the hash.
399405
fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()>;
406+
407+
/// Get secret key material as bytes for use in encrypting and decrypting inbound payment data.
408+
///
409+
/// This method must return the same value each time it is called.
410+
fn get_inbound_payment_key_material(&self) -> KeyMaterial;
400411
}
401412

402413
#[derive(Clone)]
@@ -766,6 +777,7 @@ impl Readable for InMemorySigner {
766777
pub struct KeysManager {
767778
secp_ctx: Secp256k1<secp256k1::All>,
768779
node_secret: SecretKey,
780+
inbound_payment_key: KeyMaterial,
769781
destination_script: Script,
770782
shutdown_pubkey: PublicKey,
771783
channel_master_key: ExtendedPrivKey,
@@ -821,6 +833,9 @@ impl KeysManager {
821833
};
822834
let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3).unwrap()).expect("Your RNG is busted");
823835
let rand_bytes_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4).unwrap()).expect("Your RNG is busted");
836+
let inbound_payment_key: SecretKey = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5).unwrap()).expect("Your RNG is busted").private_key.key;
837+
let mut inbound_pmt_key_bytes = [0; 32];
838+
inbound_pmt_key_bytes.copy_from_slice(&inbound_payment_key[..]);
824839

825840
let mut rand_bytes_unique_start = Sha256::engine();
826841
rand_bytes_unique_start.input(&byte_utils::be64_to_array(starting_time_secs));
@@ -830,6 +845,7 @@ impl KeysManager {
830845
let mut res = KeysManager {
831846
secp_ctx,
832847
node_secret,
848+
inbound_payment_key: KeyMaterial(inbound_pmt_key_bytes),
833849

834850
destination_script,
835851
shutdown_pubkey,
@@ -1038,6 +1054,10 @@ impl KeysInterface for KeysManager {
10381054
self.node_secret.clone()
10391055
}
10401056

1057+
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
1058+
self.inbound_payment_key.clone()
1059+
}
1060+
10411061
fn get_destination_script(&self) -> Script {
10421062
self.destination_script.clone()
10431063
}

lightning/src/ln/channel.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -5816,7 +5816,7 @@ mod tests {
58165816
use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT};
58175817
use chain::BestBlock;
58185818
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
5819-
use chain::keysinterface::{InMemorySigner, KeysInterface, BaseSign};
5819+
use chain::keysinterface::{InMemorySigner, KeyMaterial, KeysInterface, BaseSign};
58205820
use chain::transaction::OutPoint;
58215821
use util::config::UserConfig;
58225822
use util::enforcing_trait_impls::EnforcingSigner;
@@ -5857,6 +5857,7 @@ mod tests {
58575857
type Signer = InMemorySigner;
58585858

58595859
fn get_node_secret(&self) -> SecretKey { panic!(); }
5860+
fn get_inbound_payment_key_material(&self) -> KeyMaterial { panic!(); }
58605861
fn get_destination_script(&self) -> Script {
58615862
let secp_ctx = Secp256k1::signing_only();
58625863
let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();

0 commit comments

Comments
 (0)