Skip to content

Implement route blinding test vectors #3204

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fuzz/src/invoice_request_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),
next_blinding_override: None,
},
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/onion_hop_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn onion_hop_data_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
let node_signer = test_utils::TestNodeSigner::new(test_utils::privkey(42));
let _ = <lightning::ln::msgs::InboundOnionPayload as ReadableArgs<(
Option<PublicKey>,
&&test_utils::TestNodeSigner,
&test_utils::TestNodeSigner,
)>>::read(&mut r, (None, &&node_signer));
}

Expand All @@ -34,6 +34,6 @@ pub extern "C" fn onion_hop_data_run(data: *const u8, datalen: usize) {
let node_signer = test_utils::TestNodeSigner::new(test_utils::privkey(42));
let _ = <lightning::ln::msgs::InboundOnionPayload as ReadableArgs<(
Option<PublicKey>,
&&test_utils::TestNodeSigner,
&test_utils::TestNodeSigner,
)>>::read(&mut r, (None, &&node_signer));
}
1 change: 1 addition & 0 deletions fuzz/src/refund_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),
next_blinding_override: None,
},
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
Expand Down
23 changes: 18 additions & 5 deletions lightning/src/blinded_path/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::offers::invoice_request::InvoiceRequestFields;
use crate::offers::offer::OfferId;
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
use crate::sign::{EntropySource, NodeSigner, Recipient};
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};

use core::mem;
use core::ops::Deref;
Expand Down Expand Up @@ -201,6 +201,9 @@ pub struct ForwardTlvs {
///
/// [`BlindedHop::encrypted_payload`]: crate::blinded_path::BlindedHop::encrypted_payload
pub features: BlindedHopFeatures,
/// Set if this [`BlindedPaymentPath`] is concatenated to another, to indicate the
/// [`BlindedPaymentPath::blinding_point`] of the appended blinded path.
pub next_blinding_override: Option<PublicKey>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why didn't we support this to begin with?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC I was under the impression that this field only applies to onion messages (it's required for OMs), not payments. And no one actually sets it for payments, so it never popped up in interop testing. :/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine no one set it ever, because its only useful for some kind of weird frankenstein trampoline afaict? What's the intended usecase for concatenating blinded paths? I mean I suppose we should just do it, but I'm curious why its there.

Copy link
Contributor Author

@valentinewallace valentinewallace Aug 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Rusty pointed out here that it can help prevent the intro node from being aware that it's the intro node: lightning/bolts#1182 (comment)? I think this is clarified in lightning/bolts#1182 but still need to review that.

Edit: it is clarified quite a bit in that PR:
Screenshot 2024-08-07 at 3 18 29 PM

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so basically its saying we should send onion messages as a blinded path from us to the intro node, prepended to the real blinded path? Do we do that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, using next_blinding_override in OMs has always been required to prepend the unblinded path to the intro node.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I think I misread your message. I'm not sure I follow Rusty's logic, actually. It seems like creating a blinded path from us to the intro node trades off the intro node knowing that they're the intro node for the node prior to the intro node knowing that the next hop is the intro node(?). Unless we set next_blinding_override for every hop in our prepended blinded path, which I suppose is possible.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I guess I'm still not really understanding why this is here, but its not much complexity to support, sooooo

}

/// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and
Expand Down Expand Up @@ -234,7 +237,7 @@ enum BlindedPaymentTlvsRef<'a> {
/// Parameters for relaying over a given [`BlindedHop`].
///
/// [`BlindedHop`]: crate::blinded_path::BlindedHop
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct PaymentRelay {
/// Number of blocks subtracted from an incoming HTLC's `cltv_expiry` for this [`BlindedHop`].
pub cltv_expiry_delta: u16,
Expand All @@ -248,7 +251,7 @@ pub struct PaymentRelay {
/// Constraints for relaying over a given [`BlindedHop`].
///
/// [`BlindedHop`]: crate::blinded_path::BlindedHop
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct PaymentConstraints {
/// The maximum total CLTV that is acceptable when relaying a payment over this [`BlindedHop`].
pub max_cltv_expiry: u32,
Expand Down Expand Up @@ -341,7 +344,7 @@ impl Writeable for ForwardTlvs {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
let features_opt =
if self.features == BlindedHopFeatures::empty() { None }
else { Some(&self.features) };
else { Some(WithoutLength(&self.features)) };
encode_tlv_stream!(w, {
(2, self.short_channel_id, required),
(10, self.payment_relay, required),
Expand Down Expand Up @@ -379,9 +382,10 @@ impl Readable for BlindedPaymentTlvs {
_init_and_read_tlv_stream!(r, {
(1, _padding, option),
(2, scid, option),
(8, next_blinding_override, option),
(10, payment_relay, option),
(12, payment_constraints, required),
(14, features, option),
(14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))),
(65536, payment_secret, option),
(65537, payment_context, (default_value, PaymentContext::unknown())),
});
Expand All @@ -395,6 +399,7 @@ impl Readable for BlindedPaymentTlvs {
short_channel_id,
payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
payment_constraints: payment_constraints.0.unwrap(),
next_blinding_override,
features: features.unwrap_or_else(BlindedHopFeatures::empty),
}))
} else {
Expand Down Expand Up @@ -602,6 +607,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 100,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value(),
Expand All @@ -618,6 +624,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 1_000,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value(),
Expand Down Expand Up @@ -675,6 +682,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 1,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
Expand All @@ -691,6 +699,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 2_000,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
Expand Down Expand Up @@ -726,6 +735,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 5_000,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
Expand All @@ -742,6 +752,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 2_000,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
Expand Down Expand Up @@ -781,6 +792,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 1,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: 5_000,
Expand All @@ -797,6 +809,7 @@ mod tests {
max_cltv_expiry: 0,
htlc_minimum_msat: 1,
},
next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: 10_000
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/blinded_path/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ where
}

// Panics if `unblinded_tlvs` length is less than `unblinded_pks` length
pub(super) fn construct_blinded_hops<'a, T, I1, I2>(
pub(crate) fn construct_blinded_hops<'a, T, I1, I2>(
secp_ctx: &Secp256k1<T>, unblinded_pks: I1, mut unblinded_tlvs: I2, session_priv: &SecretKey
) -> Result<Vec<BlindedHop>, secp256k1::Error>
where
Expand Down
Loading
Loading