Skip to content

Commit a144837

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 f3173a4 commit a144837

File tree

7 files changed

+637
-669
lines changed

7 files changed

+637
-669
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
@@ -9311,7 +9311,7 @@ where
93119311

93129312
let nonce = Nonce::from_entropy_source(entropy);
93139313
let builder: InvoiceRequestBuilder<DerivedPayerSigningPubkey, secp256k1::All> = offer
9314-
.request_invoice_deriving_signing_pubkey(expanded_key, nonce, secp_ctx, payment_id)?
9314+
.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
93159315
.into();
93169316
let builder = builder.chain_hash(self.chain_hash)?;
93179317

lightning/src/ln/outbound_payment.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -2268,14 +2268,17 @@ mod tests {
22682268
use crate::ln::types::{PaymentHash, PaymentPreimage};
22692269
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
22702270
use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
2271+
use crate::ln::inbound_payment::ExpandedKey;
22712272
use crate::ln::msgs::{ErrorAction, LightningError};
22722273
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PendingOutboundPayment, Retry, RetryableSendFailure, StaleExpiration};
22732274
#[cfg(feature = "std")]
22742275
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
2276+
use crate::offers::nonce::Nonce;
22752277
use crate::offers::offer::OfferBuilder;
22762278
use crate::offers::test_utils::*;
22772279
use crate::routing::gossip::NetworkGraph;
22782280
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters};
2281+
use crate::sign::KeyMaterial;
22792282
use crate::sync::{Arc, Mutex, RwLock};
22802283
use crate::util::errors::APIError;
22812284
use crate::util::hash_tables::new_hash_map;
@@ -2620,6 +2623,8 @@ mod tests {
26202623
let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
26212624
let secp_ctx = Secp256k1::new();
26222625
let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
2626+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2627+
let nonce = Nonce([0; 16]);
26232628

26242629
let pending_events = Mutex::new(VecDeque::new());
26252630
let outbound_payments = OutboundPayments::new(new_hash_map());
@@ -2637,9 +2642,8 @@ mod tests {
26372642
let invoice = OfferBuilder::new(recipient_pubkey())
26382643
.amount_msats(1000)
26392644
.build().unwrap()
2640-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2641-
.build().unwrap()
2642-
.sign(payer_sign).unwrap()
2645+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2646+
.build_and_sign().unwrap()
26432647
.respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
26442648
.build().unwrap()
26452649
.sign(recipient_sign).unwrap();
@@ -2676,15 +2680,16 @@ mod tests {
26762680

26772681
let pending_events = Mutex::new(VecDeque::new());
26782682
let outbound_payments = OutboundPayments::new(new_hash_map());
2683+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2684+
let nonce = Nonce([0; 16]);
26792685
let payment_id = PaymentId([0; 32]);
26802686
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
26812687

26822688
let invoice = OfferBuilder::new(recipient_pubkey())
26832689
.amount_msats(1000)
26842690
.build().unwrap()
2685-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2686-
.build().unwrap()
2687-
.sign(payer_sign).unwrap()
2691+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2692+
.build_and_sign().unwrap()
26882693
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
26892694
.build().unwrap()
26902695
.sign(recipient_sign).unwrap();
@@ -2737,15 +2742,16 @@ mod tests {
27372742

27382743
let pending_events = Mutex::new(VecDeque::new());
27392744
let outbound_payments = OutboundPayments::new(new_hash_map());
2745+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2746+
let nonce = Nonce([0; 16]);
27402747
let payment_id = PaymentId([0; 32]);
27412748
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
27422749

27432750
let invoice = OfferBuilder::new(recipient_pubkey())
27442751
.amount_msats(1000)
27452752
.build().unwrap()
2746-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2747-
.build().unwrap()
2748-
.sign(payer_sign).unwrap()
2753+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2754+
.build_and_sign().unwrap()
27492755
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
27502756
.build().unwrap()
27512757
.sign(recipient_sign).unwrap();

0 commit comments

Comments
 (0)