Skip to content

Commit 0ef873e

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 bd1f319 commit 0ef873e

File tree

7 files changed

+633
-660
lines changed

7 files changed

+633
-660
lines changed

fuzz/src/offer_deser.rs

Lines changed: 25 additions & 18 deletions
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9003,7 +9003,7 @@ where
90039003

90049004
let nonce = Nonce::from_entropy_source(entropy);
90059005
let builder: InvoiceRequestBuilder<DerivedPayerSigningPubkey, secp256k1::All> = offer
9006-
.request_invoice_deriving_signing_pubkey(expanded_key, nonce, secp_ctx, payment_id)?
9006+
.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
90079007
.into();
90089008
let builder = builder.chain_hash(self.chain_hash)?;
90099009

lightning/src/ln/outbound_payment.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,14 +1952,17 @@ mod tests {
19521952
use crate::ln::types::PaymentHash;
19531953
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
19541954
use crate::ln::features::{ChannelFeatures, NodeFeatures};
1955+
use crate::ln::inbound_payment::ExpandedKey;
19551956
use crate::ln::msgs::{ErrorAction, LightningError};
19561957
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure, StaleExpiration};
19571958
#[cfg(feature = "std")]
19581959
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
1960+
use crate::offers::nonce::Nonce;
19591961
use crate::offers::offer::OfferBuilder;
19601962
use crate::offers::test_utils::*;
19611963
use crate::routing::gossip::NetworkGraph;
19621964
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters};
1965+
use crate::sign::KeyMaterial;
19631966
use crate::sync::{Arc, Mutex, RwLock};
19641967
use crate::util::errors::APIError;
19651968
use crate::util::test_utils;
@@ -2293,6 +2296,8 @@ mod tests {
22932296
let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
22942297
let secp_ctx = Secp256k1::new();
22952298
let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
2299+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2300+
let nonce = Nonce([0; 16]);
22962301

22972302
let pending_events = Mutex::new(VecDeque::new());
22982303
let outbound_payments = OutboundPayments::new();
@@ -2310,9 +2315,8 @@ mod tests {
23102315
let invoice = OfferBuilder::new(recipient_pubkey())
23112316
.amount_msats(1000)
23122317
.build().unwrap()
2313-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2314-
.build().unwrap()
2315-
.sign(payer_sign).unwrap()
2318+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2319+
.build_and_sign().unwrap()
23162320
.respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
23172321
.build().unwrap()
23182322
.sign(recipient_sign).unwrap();
@@ -2349,15 +2353,16 @@ mod tests {
23492353

23502354
let pending_events = Mutex::new(VecDeque::new());
23512355
let outbound_payments = OutboundPayments::new();
2356+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2357+
let nonce = Nonce([0; 16]);
23522358
let payment_id = PaymentId([0; 32]);
23532359
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
23542360

23552361
let invoice = OfferBuilder::new(recipient_pubkey())
23562362
.amount_msats(1000)
23572363
.build().unwrap()
2358-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2359-
.build().unwrap()
2360-
.sign(payer_sign).unwrap()
2364+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2365+
.build_and_sign().unwrap()
23612366
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
23622367
.build().unwrap()
23632368
.sign(recipient_sign).unwrap();
@@ -2410,15 +2415,16 @@ mod tests {
24102415

24112416
let pending_events = Mutex::new(VecDeque::new());
24122417
let outbound_payments = OutboundPayments::new();
2418+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2419+
let nonce = Nonce([0; 16]);
24132420
let payment_id = PaymentId([0; 32]);
24142421
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
24152422

24162423
let invoice = OfferBuilder::new(recipient_pubkey())
24172424
.amount_msats(1000)
24182425
.build().unwrap()
2419-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2420-
.build().unwrap()
2421-
.sign(payer_sign).unwrap()
2426+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2427+
.build_and_sign().unwrap()
24222428
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
24232429
.build().unwrap()
24242430
.sign(recipient_sign).unwrap();

0 commit comments

Comments
 (0)