Skip to content

Introduce ReceiveAuthKey #3917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
11 changes: 8 additions & 3 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ use lightning::routing::router::{
InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, Router,
};
use lightning::sign::{
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, Recipient, SignerProvider,
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient,
SignerProvider,
};
use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::util::config::UserConfig;
Expand Down Expand Up @@ -142,8 +143,8 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
_secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
}
Expand Down Expand Up @@ -347,6 +348,10 @@ impl NodeSigner for KeyProvider {
PeerStorageKey { inner: [42; 32] }
}

fn get_receive_auth_key(&self) -> ReceiveAuthKey {
unreachable!()
}

fn sign_bolt12_invoice(
&self, _invoice: &UnsignedBolt12Invoice,
) -> Result<schnorr::Signature, ()> {
Expand Down
11 changes: 8 additions & 3 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ use lightning::routing::router::{
};
use lightning::routing::utxo::UtxoLookup;
use lightning::sign::{
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, Recipient, SignerProvider,
EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient,
SignerProvider,
};
use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::util::config::{ChannelConfig, UserConfig};
Expand Down Expand Up @@ -173,8 +174,8 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
_secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
}
Expand Down Expand Up @@ -438,6 +439,10 @@ impl NodeSigner for KeyProvider {
fn get_peer_storage_key(&self) -> PeerStorageKey {
PeerStorageKey { inner: [42; 32] }
}

fn get_receive_auth_key(&self) -> ReceiveAuthKey {
unreachable!()
}
}

impl SignerProvider for KeyProvider {
Expand Down
12 changes: 9 additions & 3 deletions fuzz/src/onion_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ use lightning::onion_message::messenger::{
};
use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler};
use lightning::onion_message::packet::OnionMessageContents;
use lightning::sign::{EntropySource, NodeSigner, PeerStorageKey, Recipient, SignerProvider};
use lightning::sign::{
EntropySource, NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient, SignerProvider,
};
use lightning::types::features::InitFeatures;
use lightning::util::logger::Logger;
use lightning::util::ser::{LengthReadable, Writeable, Writer};
Expand Down Expand Up @@ -104,8 +106,8 @@ impl MessageRouter for TestMessageRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
_secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
}
Expand Down Expand Up @@ -278,6 +280,10 @@ impl NodeSigner for KeyProvider {
fn get_peer_storage_key(&self) -> PeerStorageKey {
unreachable!()
}

fn get_receive_auth_key(&self) -> ReceiveAuthKey {
unreachable!()
}
}

impl SignerProvider for KeyProvider {
Expand Down
26 changes: 20 additions & 6 deletions lightning-dns-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ mod test {
AOnionMessenger, Destination, MessageRouter, OnionMessagePath, OnionMessenger,
};
use lightning::routing::router::RouteParametersConfig;
use lightning::sign::{KeysManager, NodeSigner, Recipient};
use lightning::sign::{KeysManager, NodeSigner, ReceiveAuthKey, Recipient};
use lightning::types::features::InitFeatures;
use lightning::types::payment::PaymentHash;
use lightning::util::logger::Logger;
Expand Down Expand Up @@ -230,11 +230,18 @@ mod test {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, recipient: PublicKey, context: MessageContext, _peers: Vec<PublicKey>,
secp_ctx: &Secp256k1<T>,
&self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey,
context: MessageContext, _peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
let keys = KeysManager::new(&[0; 32], 42, 43);
Ok(vec![BlindedMessagePath::one_hop(recipient, context, &keys, secp_ctx).unwrap()])
Ok(vec![BlindedMessagePath::one_hop(
recipient,
local_node_receive_key,
context,
&keys,
secp_ctx,
)
.unwrap()])
}
}
impl Deref for DirectlyConnectedRouter {
Expand Down Expand Up @@ -336,8 +343,15 @@ mod test {
let (msg, context) =
payer.resolver.resolve_name(payment_id, name.clone(), &*payer_keys).unwrap();
let query_context = MessageContext::DNSResolver(context);
let reply_path =
BlindedMessagePath::one_hop(payer_id, query_context, &*payer_keys, &secp_ctx).unwrap();
let receive_key = payer_keys.get_receive_auth_key();
let reply_path = BlindedMessagePath::one_hop(
payer_id,
receive_key,
query_context,
&*payer_keys,
&secp_ctx,
)
.unwrap();
payer.pending_messages.lock().unwrap().push((
DNSResolverMessage::DNSSECQuery(msg),
MessageSendInstructions::WithSpecifiedReplyPath {
Expand Down
70 changes: 11 additions & 59 deletions lightning/src/blinded_path/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ use crate::offers::nonce::Nonce;
use crate::offers::offer::OfferId;
use crate::onion_message::packet::ControlTlvs;
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
use crate::sign::{EntropySource, NodeSigner, Recipient};
use crate::sign::{EntropySource, NodeSigner, ReceiveAuthKey, Recipient};
use crate::types::payment::PaymentHash;
use crate::util::scid_utils;
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, Writeable, Writer};
use bitcoin::hashes::hmac::Hmac;
use bitcoin::hashes::sha256::Hash as Sha256;

use core::mem;
use core::ops::Deref;
Expand All @@ -56,13 +54,13 @@ impl Readable for BlindedMessagePath {
impl BlindedMessagePath {
/// Create a one-hop blinded path for a message.
pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES,
secp_ctx: &Secp256k1<T>,
recipient_node_id: PublicKey, local_node_receive_key: ReceiveAuthKey,
context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>,
) -> Result<Self, ()>
where
ES::Target: EntropySource,
{
Self::new(&[], recipient_node_id, context, entropy_source, secp_ctx)
Self::new(&[], recipient_node_id, local_node_receive_key, context, entropy_source, secp_ctx)
}

/// Create a path for an onion message, to be forwarded along `node_pks`. The last node
Expand All @@ -72,7 +70,8 @@ impl BlindedMessagePath {
// TODO: make all payloads the same size with padding + add dummy hops
pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey,
context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>,
local_node_receive_key: ReceiveAuthKey, context: MessageContext, entropy_source: ES,
secp_ctx: &Secp256k1<T>,
) -> Result<Self, ()>
where
ES::Target: EntropySource,
Expand All @@ -93,6 +92,7 @@ impl BlindedMessagePath {
recipient_node_id,
context,
&blinding_secret,
local_node_receive_key,
)
.map_err(|_| ())?,
}))
Expand Down Expand Up @@ -366,12 +366,6 @@ pub enum OffersContext {
/// [`Refund`]: crate::offers::refund::Refund
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
nonce: Nonce,

/// Authentication code for the [`PaymentId`], which should be checked when the context is
/// used with an [`InvoiceError`].
///
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
hmac: Option<Hmac<Sha256>>,
},
/// Context used by a [`BlindedMessagePath`] as a reply path for a [`Bolt12Invoice`].
///
Expand All @@ -384,19 +378,6 @@ pub enum OffersContext {
///
/// [`Bolt12Invoice::payment_hash`]: crate::offers::invoice::Bolt12Invoice::payment_hash
payment_hash: PaymentHash,

/// A nonce used for authenticating that a received [`InvoiceError`] is for a valid
/// sent [`Bolt12Invoice`].
///
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
nonce: Nonce,

/// Authentication code for the [`PaymentHash`], which should be checked when the context is
/// used to log the received [`InvoiceError`].
///
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
hmac: Hmac<Sha256>,
},
}

Expand Down Expand Up @@ -451,35 +432,12 @@ pub enum AsyncPaymentsContext {
///
/// [`Offer`]: crate::offers::offer::Offer
payment_id: PaymentId,
/// A nonce used for authenticating that a [`ReleaseHeldHtlc`] message is valid for a preceding
/// [`HeldHtlcAvailable`] message.
///
/// [`ReleaseHeldHtlc`]: crate::onion_message::async_payments::ReleaseHeldHtlc
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
nonce: Nonce,
/// Authentication code for the [`PaymentId`].
///
/// Prevents the recipient from being able to deanonymize us by creating a blinded path to us
/// containing the expected [`PaymentId`].
hmac: Hmac<Sha256>,
},
/// Context contained within the [`BlindedMessagePath`]s we put in static invoices, provided back
/// to us in corresponding [`HeldHtlcAvailable`] messages.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
InboundPayment {
/// A nonce used for authenticating that a [`HeldHtlcAvailable`] message is valid for a
/// preceding static invoice.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
nonce: Nonce,
/// Authentication code for the [`HeldHtlcAvailable`] message.
///
/// Prevents nodes from creating their own blinded path to us, sending a [`HeldHtlcAvailable`]
/// message and trivially getting notified whenever we come online.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
hmac: Hmac<Sha256>,
/// The time as duration since the Unix epoch at which this path expires and messages sent over
/// it should be ignored. Without this, anyone with the path corresponding to this context is
/// able to trivially ask if we're online forever.
Expand All @@ -501,24 +459,17 @@ impl_writeable_tlv_based_enum!(OffersContext,
(1, OutboundPayment) => {
(0, payment_id, required),
(1, nonce, required),
(2, hmac, option),
},
(2, InboundPayment) => {
(0, payment_hash, required),
(1, nonce, required),
(2, hmac, required)
},
);

impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
(0, OutboundPayment) => {
(0, payment_id, required),
(2, nonce, required),
(4, hmac, required),
},
(1, InboundPayment) => {
(0, nonce, required),
(2, hmac, required),
(4, path_absolute_expiry, required),
},
(2, OfferPaths) => {
Expand Down Expand Up @@ -556,18 +507,19 @@ pub(crate) const MESSAGE_PADDING_ROUND_OFF: usize = 100;
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[MessageForwardNode],
recipient_node_id: PublicKey, context: MessageContext, session_priv: &SecretKey,
local_node_receive_key: ReceiveAuthKey,
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
let pks = intermediate_nodes
.iter()
.map(|node| node.node_id)
.chain(core::iter::once(recipient_node_id));
.map(|node| (node.node_id, None))
.chain(core::iter::once((recipient_node_id, Some(local_node_receive_key))));
let is_compact = intermediate_nodes.iter().any(|node| node.short_channel_id.is_some());

let tlvs = pks
.clone()
.skip(1) // The first node's TLVs contains the next node's pubkey
.zip(intermediate_nodes.iter().map(|node| node.short_channel_id))
.map(|(pubkey, scid)| match scid {
.map(|((pubkey, _), scid)| match scid {
Some(scid) => NextMessageHop::ShortChannelId(scid),
None => NextMessageHop::NodeId(pubkey),
})
Expand Down
6 changes: 4 additions & 2 deletions lightning/src/blinded_path/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,8 +664,10 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
let pks =
intermediate_nodes.iter().map(|node| node.node_id).chain(core::iter::once(payee_node_id));
let pks = intermediate_nodes
.iter()
.map(|node| (node.node_id, None))
.chain(core::iter::once((payee_node_id, None)));
let tlvs = intermediate_nodes
.iter()
.map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
Expand Down
Loading
Loading