Skip to content

Commit c61e16d

Browse files
committed
Elide nonce from payer metadata
InvoiceRequest and Refund have payer_metadata which consists of an encrypted payment id and a nonce used to derive its signing keys and authenticate any corresponding invoices. Now that the blinded paths include this data in their OffersContext, remove the nonce as it is now redundant. Keep the encrypted payment id as some data is need in the payer metadata according to the spec. This saves space and prevents de-anonymization attacks as along as the nonce isn't revealed.
1 parent abc9be8 commit c61e16d

File tree

5 files changed

+35
-39
lines changed

5 files changed

+35
-39
lines changed

lightning/src/ln/channelmanager.rs

+27-22
Original file line numberDiff line numberDiff line change
@@ -4106,15 +4106,35 @@ where
41064106
/// whether or not the payment was successful.
41074107
///
41084108
/// [timer tick]: Self::timer_tick_occurred
4109-
pub fn send_payment_for_bolt12_invoice(&self, invoice: &Bolt12Invoice) -> Result<(), Bolt12PaymentError> {
4110-
let secp_ctx = &self.secp_ctx;
4111-
let expanded_key = &self.inbound_payment_key;
4112-
match invoice.verify(expanded_key, secp_ctx) {
4109+
pub fn send_payment_for_bolt12_invoice(
4110+
&self, invoice: &Bolt12Invoice, context: &OffersContext,
4111+
) -> Result<(), Bolt12PaymentError> {
4112+
match self.verify_bolt12_invoice(invoice, context) {
41134113
Ok(payment_id) => self.send_payment_for_verified_bolt12_invoice(invoice, payment_id),
41144114
Err(()) => Err(Bolt12PaymentError::UnexpectedInvoice),
41154115
}
41164116
}
41174117

4118+
fn verify_bolt12_invoice(
4119+
&self, invoice: &Bolt12Invoice, context: &OffersContext,
4120+
) -> Result<PaymentId, ()> {
4121+
let secp_ctx = &self.secp_ctx;
4122+
let expanded_key = &self.inbound_payment_key;
4123+
4124+
match context {
4125+
OffersContext::Unknown {} if invoice.is_for_refund_without_paths() => {
4126+
invoice.verify(expanded_key, secp_ctx)
4127+
},
4128+
OffersContext::OutboundPayment { payment_id, nonce } => {
4129+
invoice
4130+
.verify_using_payer_data(*payment_id, *nonce, expanded_key, secp_ctx)
4131+
.then(|| *payment_id)
4132+
.ok_or(())
4133+
},
4134+
_ => Err(()),
4135+
}
4136+
}
4137+
41184138
fn send_payment_for_verified_bolt12_invoice(&self, invoice: &Bolt12Invoice, payment_id: PaymentId) -> Result<(), Bolt12PaymentError> {
41194139
let best_block_height = self.best_block.read().unwrap().height;
41204140
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
@@ -10623,30 +10643,15 @@ where
1062310643
}
1062410644
},
1062510645
OffersMessage::Invoice(invoice) => {
10626-
let payer_data = match context {
10627-
OffersContext::Unknown {} if invoice.is_for_refund_without_paths() => None,
10628-
OffersContext::OutboundPayment { payment_id, nonce } => Some((payment_id, nonce)),
10629-
_ => return ResponseInstruction::NoResponse,
10646+
let payment_id = match self.verify_bolt12_invoice(&invoice, &context) {
10647+
Ok(payment_id) => payment_id,
10648+
Err(()) => return ResponseInstruction::NoResponse,
1063010649
};
1063110650

1063210651
let logger = WithContext::from(
1063310652
&self.logger, None, None, Some(invoice.payment_hash()),
1063410653
);
1063510654

10636-
let (invoice, payment_id) = match payer_data {
10637-
Some((payment_id, nonce)) => {
10638-
if invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx) {
10639-
(invoice, payment_id)
10640-
} else {
10641-
return ResponseInstruction::NoResponse;
10642-
}
10643-
},
10644-
None => match invoice.verify(expanded_key, secp_ctx) {
10645-
Ok(payment_id) => (invoice, payment_id),
10646-
Err(()) => return ResponseInstruction::NoResponse,
10647-
},
10648-
};
10649-
1065010655
let result = {
1065110656
let features = self.bolt12_invoice_features();
1065210657
if invoice.invoice_features().requires_unknown_bits_from(&features) {

lightning/src/ln/offers_tests.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -921,10 +921,10 @@ fn pays_bolt12_invoice_asynchronously() {
921921
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
922922
bob.onion_messenger.handle_onion_message(&alice_id, &onion_message);
923923

924-
let invoice = match get_event!(bob, Event::InvoiceReceived) {
925-
Event::InvoiceReceived { payment_id: actual_payment_id, invoice, .. } => {
924+
let (invoice, context) = match get_event!(bob, Event::InvoiceReceived) {
925+
Event::InvoiceReceived { payment_id: actual_payment_id, invoice, context, .. } => {
926926
assert_eq!(actual_payment_id, payment_id);
927-
invoice
927+
(invoice, context)
928928
},
929929
_ => panic!("No Event::InvoiceReceived"),
930930
};
@@ -935,9 +935,9 @@ fn pays_bolt12_invoice_asynchronously() {
935935
assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
936936
}
937937

938-
assert!(bob.node.send_payment_for_bolt12_invoice(&invoice).is_ok());
938+
assert!(bob.node.send_payment_for_bolt12_invoice(&invoice, &context).is_ok());
939939
assert_eq!(
940-
bob.node.send_payment_for_bolt12_invoice(&invoice),
940+
bob.node.send_payment_for_bolt12_invoice(&invoice, &context),
941941
Err(Bolt12PaymentError::DuplicateInvoice),
942942
);
943943

@@ -948,7 +948,7 @@ fn pays_bolt12_invoice_asynchronously() {
948948
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
949949

950950
assert_eq!(
951-
bob.node.send_payment_for_bolt12_invoice(&invoice),
951+
bob.node.send_payment_for_bolt12_invoice(&invoice, &context),
952952
Err(Bolt12PaymentError::DuplicateInvoice),
953953
);
954954

@@ -957,7 +957,7 @@ fn pays_bolt12_invoice_asynchronously() {
957957
}
958958

959959
assert_eq!(
960-
bob.node.send_payment_for_bolt12_invoice(&invoice),
960+
bob.node.send_payment_for_bolt12_invoice(&invoice, &context),
961961
Err(Bolt12PaymentError::UnexpectedInvoice),
962962
);
963963
}

lightning/src/offers/invoice_request.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1483,10 +1483,6 @@ mod tests {
14831483
.unwrap()
14841484
.build().unwrap()
14851485
.sign(recipient_sign).unwrap();
1486-
match invoice.verify(&expanded_key, &secp_ctx) {
1487-
Ok(payment_id) => assert_eq!(payment_id, PaymentId([1; 32])),
1488-
Err(()) => panic!("verification failed"),
1489-
}
14901486
assert!(invoice.verify_using_payer_data(payment_id, nonce, &expanded_key, &secp_ctx));
14911487

14921488
// Fails verification with altered fields

lightning/src/offers/refund.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1106,10 +1106,6 @@ mod tests {
11061106
.unwrap()
11071107
.build().unwrap()
11081108
.sign(recipient_sign).unwrap();
1109-
match invoice.verify(&expanded_key, &secp_ctx) {
1110-
Ok(payment_id) => assert_eq!(payment_id, PaymentId([1; 32])),
1111-
Err(()) => panic!("verification failed"),
1112-
}
11131109
assert!(invoice.verify_using_payer_data(payment_id, nonce, &expanded_key, &secp_ctx));
11141110

11151111
// Fails verification with altered fields

lightning/src/offers/signer.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,7 @@ impl MetadataMaterial {
244244
self.hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
245245
self.maybe_include_encrypted_payment_id();
246246

247-
let mut bytes = self.encrypted_payment_id.map(|id| id.to_vec()).unwrap_or(vec![]);
248-
bytes.extend_from_slice(self.nonce.as_slice());
247+
let bytes = self.encrypted_payment_id.map(|id| id.to_vec()).unwrap_or(vec![]);
249248

250249
let hmac = Hmac::from_engine(self.hmac);
251250
let privkey = SecretKey::from_slice(hmac.as_byte_array()).unwrap();

0 commit comments

Comments
 (0)