Skip to content

Commit d82af8c

Browse files
authored
Merge pull request #3917 from shaavan/3845-mac
Introduce ReceiveAuthKey
2 parents 17c469c + 93e3708 commit d82af8c

26 files changed

+1182
-1054
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ use lightning::routing::router::{
6363
InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, Router,
6464
};
6565
use lightning::sign::{
66-
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, Recipient, SignerProvider,
66+
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient,
67+
SignerProvider,
6768
};
6869
use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
6970
use lightning::util::config::UserConfig;
@@ -142,8 +143,8 @@ impl MessageRouter for FuzzRouter {
142143
}
143144

144145
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
145-
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
146-
_secp_ctx: &Secp256k1<T>,
146+
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
147+
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
147148
) -> Result<Vec<BlindedMessagePath>, ()> {
148149
unreachable!()
149150
}
@@ -347,6 +348,10 @@ impl NodeSigner for KeyProvider {
347348
PeerStorageKey { inner: [42; 32] }
348349
}
349350

351+
fn get_receive_auth_key(&self) -> ReceiveAuthKey {
352+
ReceiveAuthKey([41; 32])
353+
}
354+
350355
fn sign_bolt12_invoice(
351356
&self, _invoice: &UnsignedBolt12Invoice,
352357
) -> Result<schnorr::Signature, ()> {

fuzz/src/full_stack.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ use lightning::routing::router::{
5757
};
5858
use lightning::routing::utxo::UtxoLookup;
5959
use lightning::sign::{
60-
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, Recipient, SignerProvider,
60+
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient,
61+
SignerProvider,
6162
};
6263
use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
6364
use lightning::util::config::{ChannelConfig, UserConfig};
@@ -173,8 +174,8 @@ impl MessageRouter for FuzzRouter {
173174
}
174175

175176
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
176-
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
177-
_secp_ctx: &Secp256k1<T>,
177+
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
178+
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
178179
) -> Result<Vec<BlindedMessagePath>, ()> {
179180
unreachable!()
180181
}
@@ -438,6 +439,10 @@ impl NodeSigner for KeyProvider {
438439
fn get_peer_storage_key(&self) -> PeerStorageKey {
439440
PeerStorageKey { inner: [42; 32] }
440441
}
442+
443+
fn get_receive_auth_key(&self) -> ReceiveAuthKey {
444+
ReceiveAuthKey([41; 32])
445+
}
441446
}
442447

443448
impl SignerProvider for KeyProvider {

fuzz/src/onion_message.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ use lightning::onion_message::messenger::{
2424
};
2525
use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler};
2626
use lightning::onion_message::packet::OnionMessageContents;
27-
use lightning::sign::{EntropySource, NodeSigner, PeerStorageKey, Recipient, SignerProvider};
27+
use lightning::sign::{
28+
EntropySource, NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient, SignerProvider,
29+
};
2830
use lightning::types::features::InitFeatures;
2931
use lightning::util::logger::Logger;
3032
use lightning::util::ser::{LengthReadable, Writeable, Writer};
@@ -104,8 +106,8 @@ impl MessageRouter for TestMessageRouter {
104106
}
105107

106108
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
107-
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
108-
_secp_ctx: &Secp256k1<T>,
109+
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
110+
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
109111
) -> Result<Vec<BlindedMessagePath>, ()> {
110112
unreachable!()
111113
}
@@ -278,6 +280,10 @@ impl NodeSigner for KeyProvider {
278280
fn get_peer_storage_key(&self) -> PeerStorageKey {
279281
unreachable!()
280282
}
283+
284+
fn get_receive_auth_key(&self) -> ReceiveAuthKey {
285+
ReceiveAuthKey([41; 32])
286+
}
281287
}
282288

283289
impl SignerProvider for KeyProvider {

lightning-dns-resolver/src/lib.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ mod test {
174174
AOnionMessenger, Destination, MessageRouter, OnionMessagePath, OnionMessenger,
175175
};
176176
use lightning::routing::router::RouteParametersConfig;
177-
use lightning::sign::{KeysManager, NodeSigner, Recipient};
177+
use lightning::sign::{KeysManager, NodeSigner, ReceiveAuthKey, Recipient};
178178
use lightning::types::features::InitFeatures;
179179
use lightning::types::payment::PaymentHash;
180180
use lightning::util::logger::Logger;
@@ -230,11 +230,18 @@ mod test {
230230
}
231231

232232
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
233-
&self, recipient: PublicKey, context: MessageContext, _peers: Vec<PublicKey>,
234-
secp_ctx: &Secp256k1<T>,
233+
&self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey,
234+
context: MessageContext, _peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
235235
) -> Result<Vec<BlindedMessagePath>, ()> {
236236
let keys = KeysManager::new(&[0; 32], 42, 43);
237-
Ok(vec![BlindedMessagePath::one_hop(recipient, context, &keys, secp_ctx).unwrap()])
237+
Ok(vec![BlindedMessagePath::one_hop(
238+
recipient,
239+
local_node_receive_key,
240+
context,
241+
&keys,
242+
secp_ctx,
243+
)
244+
.unwrap()])
238245
}
239246
}
240247
impl Deref for DirectlyConnectedRouter {
@@ -336,8 +343,15 @@ mod test {
336343
let (msg, context) =
337344
payer.resolver.resolve_name(payment_id, name.clone(), &*payer_keys).unwrap();
338345
let query_context = MessageContext::DNSResolver(context);
339-
let reply_path =
340-
BlindedMessagePath::one_hop(payer_id, query_context, &*payer_keys, &secp_ctx).unwrap();
346+
let receive_key = payer_keys.get_receive_auth_key();
347+
let reply_path = BlindedMessagePath::one_hop(
348+
payer_id,
349+
receive_key,
350+
query_context,
351+
&*payer_keys,
352+
&secp_ctx,
353+
)
354+
.unwrap();
341355
payer.pending_messages.lock().unwrap().push((
342356
DNSResolverMessage::DNSSECQuery(msg),
343357
MessageSendInstructions::WithSpecifiedReplyPath {

lightning/src/blinded_path/message.rs

Lines changed: 28 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ use crate::offers::nonce::Nonce;
2626
use crate::offers::offer::OfferId;
2727
use crate::onion_message::packet::ControlTlvs;
2828
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
29-
use crate::sign::{EntropySource, NodeSigner, Recipient};
29+
use crate::sign::{EntropySource, NodeSigner, ReceiveAuthKey, Recipient};
3030
use crate::types::payment::PaymentHash;
3131
use crate::util::scid_utils;
3232
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, Writeable, Writer};
33-
use bitcoin::hashes::hmac::Hmac;
34-
use bitcoin::hashes::sha256::Hash as Sha256;
3533

3634
use core::mem;
3735
use core::ops::Deref;
@@ -57,13 +55,13 @@ impl Readable for BlindedMessagePath {
5755
impl BlindedMessagePath {
5856
/// Create a one-hop blinded path for a message.
5957
pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
60-
recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES,
61-
secp_ctx: &Secp256k1<T>,
58+
recipient_node_id: PublicKey, local_node_receive_key: ReceiveAuthKey,
59+
context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>,
6260
) -> Result<Self, ()>
6361
where
6462
ES::Target: EntropySource,
6563
{
66-
Self::new(&[], recipient_node_id, context, entropy_source, secp_ctx)
64+
Self::new(&[], recipient_node_id, local_node_receive_key, context, entropy_source, secp_ctx)
6765
}
6866

6967
/// Create a path for an onion message, to be forwarded along `node_pks`. The last node
@@ -73,7 +71,8 @@ impl BlindedMessagePath {
7371
// TODO: make all payloads the same size with padding + add dummy hops
7472
pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
7573
intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey,
76-
context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>,
74+
local_node_receive_key: ReceiveAuthKey, context: MessageContext, entropy_source: ES,
75+
secp_ctx: &Secp256k1<T>,
7776
) -> Result<Self, ()>
7877
where
7978
ES::Target: EntropySource,
@@ -94,6 +93,7 @@ impl BlindedMessagePath {
9493
recipient_node_id,
9594
context,
9695
&blinding_secret,
96+
local_node_receive_key,
9797
)
9898
.map_err(|_| ())?,
9999
}))
@@ -404,12 +404,6 @@ pub enum OffersContext {
404404
/// [`Refund`]: crate::offers::refund::Refund
405405
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
406406
nonce: Nonce,
407-
408-
/// Authentication code for the [`PaymentId`], which should be checked when the context is
409-
/// used with an [`InvoiceError`].
410-
///
411-
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
412-
hmac: Option<Hmac<Sha256>>,
413407
},
414408
/// Context used by a [`BlindedMessagePath`] as a reply path for a [`Bolt12Invoice`].
415409
///
@@ -422,19 +416,6 @@ pub enum OffersContext {
422416
///
423417
/// [`Bolt12Invoice::payment_hash`]: crate::offers::invoice::Bolt12Invoice::payment_hash
424418
payment_hash: PaymentHash,
425-
426-
/// A nonce used for authenticating that a received [`InvoiceError`] is for a valid
427-
/// sent [`Bolt12Invoice`].
428-
///
429-
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
430-
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
431-
nonce: Nonce,
432-
433-
/// Authentication code for the [`PaymentHash`], which should be checked when the context is
434-
/// used to log the received [`InvoiceError`].
435-
///
436-
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
437-
hmac: Hmac<Sha256>,
438419
},
439420
}
440421

@@ -542,35 +523,12 @@ pub enum AsyncPaymentsContext {
542523
///
543524
/// [`Offer`]: crate::offers::offer::Offer
544525
payment_id: PaymentId,
545-
/// A nonce used for authenticating that a [`ReleaseHeldHtlc`] message is valid for a preceding
546-
/// [`HeldHtlcAvailable`] message.
547-
///
548-
/// [`ReleaseHeldHtlc`]: crate::onion_message::async_payments::ReleaseHeldHtlc
549-
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
550-
nonce: Nonce,
551-
/// Authentication code for the [`PaymentId`].
552-
///
553-
/// Prevents the recipient from being able to deanonymize us by creating a blinded path to us
554-
/// containing the expected [`PaymentId`].
555-
hmac: Hmac<Sha256>,
556526
},
557527
/// Context contained within the [`BlindedMessagePath`]s we put in static invoices, provided back
558528
/// to us in corresponding [`HeldHtlcAvailable`] messages.
559529
///
560530
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
561531
InboundPayment {
562-
/// A nonce used for authenticating that a [`HeldHtlcAvailable`] message is valid for a
563-
/// preceding static invoice.
564-
///
565-
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
566-
nonce: Nonce,
567-
/// Authentication code for the [`HeldHtlcAvailable`] message.
568-
///
569-
/// Prevents nodes from creating their own blinded path to us, sending a [`HeldHtlcAvailable`]
570-
/// message and trivially getting notified whenever we come online.
571-
///
572-
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
573-
hmac: Hmac<Sha256>,
574532
/// The time as duration since the Unix epoch at which this path expires and messages sent over
575533
/// it should be ignored. Without this, anyone with the path corresponding to this context is
576534
/// able to trivially ask if we're online forever.
@@ -585,19 +543,27 @@ impl_writeable_tlv_based_enum!(MessageContext,
585543
{3, DNSResolver} => (),
586544
);
587545

546+
// NOTE:
547+
// Several TLV fields (`nonce`, `hmac`, etc.) were removed in LDK v0.2
548+
// following the introduction of `ReceiveAuthKey`-based authentication for
549+
// inbound `BlindedMessagePath`s. These fields are now commented out and
550+
// their `type` values must not be reused unless support for LDK v0.2
551+
// and earlier is fully dropped.
552+
//
553+
// For context-specific removals, see the commented-out fields within each enum variant.
588554
impl_writeable_tlv_based_enum!(OffersContext,
589555
(0, InvoiceRequest) => {
590556
(0, nonce, required),
591557
},
592558
(1, OutboundPayment) => {
593559
(0, payment_id, required),
594560
(1, nonce, required),
595-
(2, hmac, option),
561+
// Removed: (2, hmac, option)
596562
},
597563
(2, InboundPayment) => {
598564
(0, payment_hash, required),
599-
(1, nonce, required),
600-
(2, hmac, required)
565+
// Removed: (1, nonce, required),
566+
// Removed: (2, hmac, required)
601567
},
602568
(3, StaticInvoiceRequested) => {
603569
(0, recipient_id, required),
@@ -609,12 +575,12 @@ impl_writeable_tlv_based_enum!(OffersContext,
609575
impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
610576
(0, OutboundPayment) => {
611577
(0, payment_id, required),
612-
(2, nonce, required),
613-
(4, hmac, required),
578+
// Removed: (2, nonce, required),
579+
// Removed: (4, hmac, required),
614580
},
615581
(1, InboundPayment) => {
616-
(0, nonce, required),
617-
(2, hmac, required),
582+
// Removed: (0, nonce, required),
583+
// Removed: (2, hmac, required),
618584
(4, path_absolute_expiry, required),
619585
},
620586
(2, OfferPaths) => {
@@ -642,10 +608,8 @@ impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
642608
/// [`DNSSECProof`]: crate::onion_message::dns_resolution::DNSSECProof
643609
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
644610
pub struct DNSResolverContext {
645-
/// A nonce which uniquely describes a DNS resolution.
646-
///
647-
/// When we receive a DNSSEC proof message, we should check that it was sent over the blinded
648-
/// path we included in the request by comparing a stored nonce with this one.
611+
/// A nonce which uniquely describes a DNS resolution, useful for looking up metadata about the
612+
/// request.
649613
pub nonce: [u8; 16],
650614
}
651615

@@ -661,18 +625,19 @@ pub(crate) const MESSAGE_PADDING_ROUND_OFF: usize = 100;
661625
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
662626
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[MessageForwardNode],
663627
recipient_node_id: PublicKey, context: MessageContext, session_priv: &SecretKey,
628+
local_node_receive_key: ReceiveAuthKey,
664629
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
665630
let pks = intermediate_nodes
666631
.iter()
667-
.map(|node| node.node_id)
668-
.chain(core::iter::once(recipient_node_id));
632+
.map(|node| (node.node_id, None))
633+
.chain(core::iter::once((recipient_node_id, Some(local_node_receive_key))));
669634
let is_compact = intermediate_nodes.iter().any(|node| node.short_channel_id.is_some());
670635

671636
let tlvs = pks
672637
.clone()
673638
.skip(1) // The first node's TLVs contains the next node's pubkey
674639
.zip(intermediate_nodes.iter().map(|node| node.short_channel_id))
675-
.map(|(pubkey, scid)| match scid {
640+
.map(|((pubkey, _), scid)| match scid {
676641
Some(scid) => NextMessageHop::ShortChannelId(scid),
677642
None => NextMessageHop::NodeId(pubkey),
678643
})

lightning/src/blinded_path/payment.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -664,8 +664,10 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
664664
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
665665
payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
666666
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
667-
let pks =
668-
intermediate_nodes.iter().map(|node| node.node_id).chain(core::iter::once(payee_node_id));
667+
let pks = intermediate_nodes
668+
.iter()
669+
.map(|node| (node.node_id, None))
670+
.chain(core::iter::once((payee_node_id, None)));
669671
let tlvs = intermediate_nodes
670672
.iter()
671673
.map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))

0 commit comments

Comments
 (0)