Skip to content

Commit 418ec04

Browse files
committed
Disallow user-provided payer_signing_pubkey
When creating an InvoiceRequests, users may choose to either use a transient signing pubkey generated by LDK or provide a static one. Disallow the latter as it allows users to reuse the same pubkey, which results in poor sender privacy.
1 parent d1bcf30 commit 418ec04

File tree

7 files changed

+633
-660
lines changed

7 files changed

+633
-660
lines changed

fuzz/src/offer_deser.rs

+25-18
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
// licenses.
99

1010
use crate::utils::test_logger;
11-
use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey};
11+
use bitcoin::secp256k1::Secp256k1;
1212
use core::convert::TryFrom;
13-
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
13+
use lightning::ln::channelmanager::PaymentId;
14+
use lightning::ln::inbound_payment::ExpandedKey;
15+
use lightning::offers::invoice_request::InvoiceRequest;
16+
use lightning::offers::nonce::Nonce;
1417
use lightning::offers::offer::{Amount, Offer, Quantity};
1518
use lightning::offers::parse::Bolt12SemanticError;
19+
use lightning::sign::{EntropySource, KeyMaterial};
1620
use lightning::util::ser::Writeable;
1721

1822
#[inline]
@@ -22,27 +26,30 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
2226
offer.write(&mut bytes).unwrap();
2327
assert_eq!(data, bytes);
2428

25-
let secp_ctx = Secp256k1::new();
26-
let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
27-
let pubkey = PublicKey::from(keys);
2829
let mut buffer = Vec::new();
2930

30-
if let Ok(invoice_request) = build_response(&offer, pubkey) {
31-
invoice_request
32-
.sign(|message: &UnsignedInvoiceRequest| {
33-
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
34-
})
35-
.unwrap()
36-
.write(&mut buffer)
37-
.unwrap();
31+
if let Ok(invoice_request) = build_request(&offer) {
32+
invoice_request.write(&mut buffer).unwrap();
3833
}
3934
}
4035
}
4136

42-
fn build_response(
43-
offer: &Offer, pubkey: PublicKey,
44-
) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
45-
let mut builder = offer.request_invoice(vec![42; 64], pubkey)?;
37+
struct FixedEntropy;
38+
39+
impl EntropySource for FixedEntropy {
40+
fn get_secure_random_bytes(&self) -> [u8; 32] {
41+
[42; 32]
42+
}
43+
}
44+
45+
fn build_request(offer: &Offer) -> Result<InvoiceRequest, Bolt12SemanticError> {
46+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
47+
let entropy = FixedEntropy {};
48+
let nonce = Nonce::from_entropy_source(&entropy);
49+
let secp_ctx = Secp256k1::new();
50+
let payment_id = PaymentId([1; 32]);
51+
52+
let mut builder = offer.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)?;
4653

4754
builder = match offer.amount() {
4855
None => builder.amount_msats(1000).unwrap(),
@@ -56,7 +63,7 @@ fn build_response(
5663
Quantity::One => builder,
5764
};
5865

59-
builder.build()
66+
builder.build_and_sign()
6067
}
6168

6269
pub fn offer_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {

lightning/src/ln/channelmanager.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9066,7 +9066,7 @@ where
90669066

90679067
let nonce = Nonce::from_entropy_source(entropy);
90689068
let builder: InvoiceRequestBuilder<DerivedPayerSigningPubkey, secp256k1::All> = offer
9069-
.request_invoice_deriving_signing_pubkey(expanded_key, nonce, secp_ctx, payment_id)?
9069+
.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
90709070
.into();
90719071
let builder = builder.chain_hash(self.chain_hash)?;
90729072

lightning/src/ln/outbound_payment.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -1949,14 +1949,17 @@ mod tests {
19491949
use crate::ln::types::PaymentHash;
19501950
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
19511951
use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
1952+
use crate::ln::inbound_payment::ExpandedKey;
19521953
use crate::ln::msgs::{ErrorAction, LightningError};
19531954
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure, StaleExpiration};
19541955
#[cfg(feature = "std")]
19551956
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
1957+
use crate::offers::nonce::Nonce;
19561958
use crate::offers::offer::OfferBuilder;
19571959
use crate::offers::test_utils::*;
19581960
use crate::routing::gossip::NetworkGraph;
19591961
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters};
1962+
use crate::sign::KeyMaterial;
19601963
use crate::sync::{Arc, Mutex, RwLock};
19611964
use crate::util::errors::APIError;
19621965
use crate::util::test_utils;
@@ -2300,6 +2303,8 @@ mod tests {
23002303
let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
23012304
let secp_ctx = Secp256k1::new();
23022305
let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
2306+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2307+
let nonce = Nonce([0; 16]);
23032308

23042309
let pending_events = Mutex::new(VecDeque::new());
23052310
let outbound_payments = OutboundPayments::new();
@@ -2317,9 +2322,8 @@ mod tests {
23172322
let invoice = OfferBuilder::new(recipient_pubkey())
23182323
.amount_msats(1000)
23192324
.build().unwrap()
2320-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2321-
.build().unwrap()
2322-
.sign(payer_sign).unwrap()
2325+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2326+
.build_and_sign().unwrap()
23232327
.respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
23242328
.build().unwrap()
23252329
.sign(recipient_sign).unwrap();
@@ -2356,15 +2360,16 @@ mod tests {
23562360

23572361
let pending_events = Mutex::new(VecDeque::new());
23582362
let outbound_payments = OutboundPayments::new();
2363+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2364+
let nonce = Nonce([0; 16]);
23592365
let payment_id = PaymentId([0; 32]);
23602366
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
23612367

23622368
let invoice = OfferBuilder::new(recipient_pubkey())
23632369
.amount_msats(1000)
23642370
.build().unwrap()
2365-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2366-
.build().unwrap()
2367-
.sign(payer_sign).unwrap()
2371+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2372+
.build_and_sign().unwrap()
23682373
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
23692374
.build().unwrap()
23702375
.sign(recipient_sign).unwrap();
@@ -2417,15 +2422,16 @@ mod tests {
24172422

24182423
let pending_events = Mutex::new(VecDeque::new());
24192424
let outbound_payments = OutboundPayments::new();
2425+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2426+
let nonce = Nonce([0; 16]);
24202427
let payment_id = PaymentId([0; 32]);
24212428
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
24222429

24232430
let invoice = OfferBuilder::new(recipient_pubkey())
24242431
.amount_msats(1000)
24252432
.build().unwrap()
2426-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2427-
.build().unwrap()
2428-
.sign(payer_sign).unwrap()
2433+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2434+
.build_and_sign().unwrap()
24292435
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
24302436
.build().unwrap()
24312437
.sign(recipient_sign).unwrap();

0 commit comments

Comments
 (0)