Skip to content

Commit 4cdff56

Browse files
committed
(f?) Calculate shared secret within decode_next_payment_hop
1 parent 38284a0 commit 4cdff56

File tree

5 files changed

+94
-54
lines changed

5 files changed

+94
-54
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,7 @@ fn route_blinding_spec_test_vector() {
15611561
let bob_node_signer = TestEcdhSigner { node_secret: bob_secret };
15621562
// Can't use the public API here as we need to avoid the CLTV delta checks (test vector uses
15631563
// < MIN_CLTV_EXPIRY_DELTA).
1564-
let (bob_peeled_onion, _, next_packet_details_opt) =
1564+
let (bob_peeled_onion, next_packet_details_opt) =
15651565
match onion_payment::decode_incoming_update_add_htlc_onion(
15661566
&bob_update_add, &bob_node_signer, &logger, &secp_ctx
15671567
) {
@@ -1571,7 +1571,7 @@ fn route_blinding_spec_test_vector() {
15711571
let (carol_packet_bytes, carol_hmac) = if let onion_utils::Hop::BlindedForward {
15721572
next_hop_data: msgs::InboundOnionBlindedForwardPayload {
15731573
short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override
1574-
}, next_hop_hmac, new_packet_bytes
1574+
}, next_hop_hmac, new_packet_bytes, ..
15751575
} = bob_peeled_onion {
15761576
assert_eq!(short_channel_id, 1729);
15771577
assert!(next_blinding_override.is_none());
@@ -1595,7 +1595,7 @@ fn route_blinding_spec_test_vector() {
15951595
carol_onion
15961596
);
15971597
let carol_node_signer = TestEcdhSigner { node_secret: carol_secret };
1598-
let (carol_peeled_onion, _, next_packet_details_opt) =
1598+
let (carol_peeled_onion, next_packet_details_opt) =
15991599
match onion_payment::decode_incoming_update_add_htlc_onion(
16001600
&carol_update_add, &carol_node_signer, &logger, &secp_ctx
16011601
) {
@@ -1605,7 +1605,7 @@ fn route_blinding_spec_test_vector() {
16051605
let (dave_packet_bytes, dave_hmac) = if let onion_utils::Hop::BlindedForward {
16061606
next_hop_data: msgs::InboundOnionBlindedForwardPayload {
16071607
short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override
1608-
}, next_hop_hmac, new_packet_bytes
1608+
}, next_hop_hmac, new_packet_bytes, ..
16091609
} = carol_peeled_onion {
16101610
assert_eq!(short_channel_id, 1105);
16111611
assert_eq!(next_blinding_override, Some(pubkey_from_hex("031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f")));
@@ -1629,7 +1629,7 @@ fn route_blinding_spec_test_vector() {
16291629
dave_onion
16301630
);
16311631
let dave_node_signer = TestEcdhSigner { node_secret: dave_secret };
1632-
let (dave_peeled_onion, _, next_packet_details_opt) =
1632+
let (dave_peeled_onion, next_packet_details_opt) =
16331633
match onion_payment::decode_incoming_update_add_htlc_onion(
16341634
&dave_update_add, &dave_node_signer, &logger, &secp_ctx
16351635
) {
@@ -1639,7 +1639,7 @@ fn route_blinding_spec_test_vector() {
16391639
let (eve_packet_bytes, eve_hmac) = if let onion_utils::Hop::BlindedForward {
16401640
next_hop_data: msgs::InboundOnionBlindedForwardPayload {
16411641
short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override
1642-
}, next_hop_hmac, new_packet_bytes
1642+
}, next_hop_hmac, new_packet_bytes, ..
16431643
} = dave_peeled_onion {
16441644
assert_eq!(short_channel_id, 561);
16451645
assert!(next_blinding_override.is_none());

lightning/src/ln/channelmanager.rs

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ use crate::routing::router::{BlindedTail, FixedRouter, InFlightHtlcs, Path, Paye
6161
use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundHTLCErr, NextPacketDetails};
6262
use crate::ln::msgs;
6363
use crate::ln::onion_utils;
64-
use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
64+
use crate::ln::onion_utils::{Hop, HTLCFailReason, INVALID_ONION_BLINDING};
6565
use crate::ln::msgs::{ChannelMessageHandler, CommitmentUpdate, DecodeError, LightningError};
6666
#[cfg(test)]
6767
use crate::ln::outbound_payment;
@@ -4427,27 +4427,16 @@ where
44274427
}
44284428
}
44294429
match decoded_hop {
4430-
onion_utils::Hop::Receive(next_hop_data) => {
4431-
// OUR PAYMENT!
4432-
let current_height: u32 = self.best_block.read().unwrap().height;
4433-
match create_recv_pending_htlc_info(msgs::InboundOnionPayload::Receive(next_hop_data), shared_secret, msg.payment_hash,
4434-
msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat,
4435-
current_height)
4436-
{
4437-
Ok(info) => {
4438-
// Note that we could obviously respond immediately with an update_fulfill_htlc
4439-
// message, however that would leak that we are the recipient of this payment, so
4440-
// instead we stay symmetric with the forwarding case, only responding (after a
4441-
// delay) once they've send us a commitment_signed!
4442-
PendingHTLCStatus::Forward(info)
4443-
},
4444-
Err(InboundHTLCErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data)
4445-
}
4446-
},
4447-
onion_utils::Hop::BlindedReceive(next_hop_data) => {
4430+
onion_utils::Hop::Receive { .. } | onion_utils::Hop::BlindedReceive { .. } => {
4431+
let inbound_onion_payload = match decoded_hop {
4432+
Hop::Receive { hop_data, .. } => msgs::InboundOnionPayload::Receive(hop_data),
4433+
Hop::BlindedReceive { hop_data, .. } => msgs::InboundOnionPayload::BlindedReceive(hop_data),
4434+
_ => unreachable!()
4435+
};
4436+
44484437
// OUR PAYMENT!
44494438
let current_height: u32 = self.best_block.read().unwrap().height;
4450-
match create_recv_pending_htlc_info(msgs::InboundOnionPayload::BlindedReceive(next_hop_data), shared_secret, msg.payment_hash,
4439+
match create_recv_pending_htlc_info(inbound_onion_payload, shared_secret, msg.payment_hash,
44514440
msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat,
44524441
current_height)
44534442
{
@@ -4461,14 +4450,14 @@ where
44614450
Err(InboundHTLCErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data)
44624451
}
44634452
},
4464-
onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
4453+
onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes, .. } => {
44654454
match create_fwd_pending_htlc_info(msg, msgs::InboundOnionPayload::Forward(next_hop_data), next_hop_hmac,
44664455
new_packet_bytes, shared_secret, next_packet_pubkey_opt) {
44674456
Ok(info) => PendingHTLCStatus::Forward(info),
44684457
Err(InboundHTLCErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data)
44694458
}
44704459
},
4471-
onion_utils::Hop::BlindedForward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
4460+
onion_utils::Hop::BlindedForward { next_hop_data, next_hop_hmac, new_packet_bytes, .. } => {
44724461
match create_fwd_pending_htlc_info(msg, msgs::InboundOnionPayload::BlindedForward(next_hop_data), next_hop_hmac,
44734462
new_packet_bytes, shared_secret, next_packet_pubkey_opt) {
44744463
Ok(info) => PendingHTLCStatus::Forward(info),
@@ -5696,7 +5685,7 @@ where
56965685
let mut htlc_forwards = Vec::new();
56975686
let mut htlc_fails = Vec::new();
56985687
for update_add_htlc in &update_add_htlcs {
5699-
let (next_hop, shared_secret, next_packet_details_opt) = match decode_incoming_update_add_htlc_onion(
5688+
let (next_hop, next_packet_details_opt) = match decode_incoming_update_add_htlc_onion(
57005689
&update_add_htlc, &*self.node_signer, &*self.logger, &self.secp_ctx
57015690
) {
57025691
Ok(decoded_onion) => decoded_onion,
@@ -5708,6 +5697,7 @@ where
57085697

57095698
let is_intro_node_blinded_forward = next_hop.is_intro_node_blinded_forward();
57105699
let outgoing_scid_opt = next_packet_details_opt.as_ref().map(|d| d.outgoing_scid);
5700+
let shared_secret = next_hop.shared_secret().secret_bytes();
57115701

57125702
// Process the HTLC on the incoming channel.
57135703
match self.do_funded_channel_callback(incoming_scid, |chan: &mut FundedChannel<SP>| {
@@ -5868,8 +5858,8 @@ where
58685858
if phantom_pubkey_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id, &self.chain_hash) {
58695859
let phantom_shared_secret = self.node_signer.ecdh(Recipient::PhantomNode, &onion_packet.public_key.unwrap(), None).unwrap().secret_bytes();
58705860
let next_hop = match onion_utils::decode_next_payment_hop(
5871-
phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac,
5872-
payment_hash, None, &*self.node_signer
5861+
Recipient::PhantomNode, &onion_packet.public_key.unwrap(), &onion_packet.hop_data,
5862+
onion_packet.hmac, payment_hash, None, &*self.node_signer
58735863
) {
58745864
Ok(res) => res,
58755865
Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
@@ -5885,8 +5875,8 @@ where
58855875
},
58865876
};
58875877
let inbound_onion_payload = match next_hop {
5888-
onion_utils::Hop::Receive(hop_data) => msgs::InboundOnionPayload::Receive(hop_data),
5889-
onion_utils::Hop::BlindedReceive(hop_data) => msgs::InboundOnionPayload::BlindedReceive(hop_data),
5878+
onion_utils::Hop::Receive { hop_data, .. } => msgs::InboundOnionPayload::Receive(hop_data),
5879+
onion_utils::Hop::BlindedReceive { hop_data, .. } => msgs::InboundOnionPayload::BlindedReceive(hop_data),
58905880
_ => panic!()
58915881
};
58925882
let current_height: u32 = self.best_block.read().unwrap().height;

lightning/src/ln/onion_payment.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ where
285285
NS::Target: NodeSigner,
286286
L::Target: Logger,
287287
{
288-
let (hop, shared_secret, next_packet_details_opt) =
288+
let (hop, next_packet_details_opt) =
289289
decode_incoming_update_add_htlc_onion(msg, node_signer, logger, secp_ctx
290290
).map_err(|e| {
291291
let (err_code, err_data) = match e {
@@ -296,7 +296,8 @@ where
296296
InboundHTLCErr { msg, err_code, err_data }
297297
})?;
298298
Ok(match hop {
299-
onion_utils::Hop::Forward { next_hop_hmac, new_packet_bytes, .. } | onion_utils::Hop::BlindedForward { next_hop_hmac, new_packet_bytes, .. } => {
299+
onion_utils::Hop::Forward { shared_secret, next_hop_hmac, new_packet_bytes, .. } |
300+
onion_utils::Hop::BlindedForward { shared_secret, next_hop_hmac, new_packet_bytes, .. } => {
300301
let inbound_onion_payload = match hop {
301302
onion_utils::Hop::Forward { next_hop_data, .. } => msgs::InboundOnionPayload::Forward(next_hop_data),
302303
onion_utils::Hop::BlindedForward { next_hop_data, .. } => msgs::InboundOnionPayload::BlindedForward(next_hop_data),
@@ -328,19 +329,19 @@ where
328329
// TODO: If this is potentially a phantom payment we should decode the phantom payment
329330
// onion here and check it.
330331
create_fwd_pending_htlc_info(
331-
msg, inbound_onion_payload, next_hop_hmac, new_packet_bytes, shared_secret,
332+
msg, inbound_onion_payload, next_hop_hmac, new_packet_bytes, shared_secret.secret_bytes(),
332333
Some(next_packet_pubkey),
333334
)?
334335
},
335-
onion_utils::Hop::Receive(received_data) => {
336+
onion_utils::Hop::Receive{hop_data, shared_secret} => {
336337
create_recv_pending_htlc_info(
337-
msgs::InboundOnionPayload::Receive(received_data), shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
338+
msgs::InboundOnionPayload::Receive(hop_data), shared_secret.secret_bytes(), msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
338339
None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height,
339340
)?
340341
},
341-
onion_utils::Hop::BlindedReceive(received_data) => {
342+
onion_utils::Hop::BlindedReceive{hop_data, shared_secret} => {
342343
create_recv_pending_htlc_info(
343-
msgs::InboundOnionPayload::BlindedReceive(received_data), shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
344+
msgs::InboundOnionPayload::BlindedReceive(hop_data), shared_secret.secret_bytes(), msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
344345
None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height,
345346
)?
346347
}
@@ -356,7 +357,7 @@ pub(super) struct NextPacketDetails {
356357

357358
pub(super) fn decode_incoming_update_add_htlc_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
358359
msg: &msgs::UpdateAddHTLC, node_signer: NS, logger: L, secp_ctx: &Secp256k1<T>,
359-
) -> Result<(onion_utils::Hop, [u8; 32], Option<NextPacketDetails>), HTLCFailureMsg>
360+
) -> Result<(onion_utils::Hop, Option<NextPacketDetails>), HTLCFailureMsg>
360361
where
361362
NS::Target: NodeSigner,
362363
L::Target: Logger,
@@ -422,7 +423,7 @@ where
422423
}
423424

424425
let next_hop = match onion_utils::decode_next_payment_hop(
425-
shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
426+
Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
426427
msg.payment_hash, msg.blinding_point, node_signer
427428
) {
428429
Ok(res) => res,
@@ -463,7 +464,7 @@ where
463464
_ => None
464465
};
465466

466-
Ok((next_hop, shared_secret, next_packet_details))
467+
Ok((next_hop, next_packet_details))
467468
}
468469

469470
pub(super) fn check_incoming_htlc_cltv(

lightning/src/ln/onion_utils.rs

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::ln::msgs;
1616
use crate::offers::invoice_request::InvoiceRequest;
1717
use crate::routing::gossip::NetworkUpdate;
1818
use crate::routing::router::{BlindedTail, Path, RouteHop, RouteParameters, TrampolineHop};
19-
use crate::sign::NodeSigner;
19+
use crate::sign::{NodeSigner, Recipient};
2020
use crate::types::features::{ChannelFeatures, NodeFeatures};
2121
use crate::types::payment::{PaymentHash, PaymentPreimage};
2222
use crate::util::errors::{self, APIError};
@@ -1419,6 +1419,8 @@ pub(crate) enum Hop {
14191419
Forward {
14201420
/// Onion payload data used in forwarding the payment.
14211421
next_hop_data: msgs::InboundOnionForwardPayload,
1422+
/// Shared secret that was used to decrypt next_hop_data.
1423+
shared_secret: SharedSecret,
14221424
/// HMAC of the next hop's onion packet.
14231425
next_hop_hmac: [u8; 32],
14241426
/// Bytes of the onion packet we're forwarding.
@@ -1428,17 +1430,29 @@ pub(crate) enum Hop {
14281430
BlindedForward {
14291431
/// Onion payload data used in forwarding the payment.
14301432
next_hop_data: msgs::InboundOnionBlindedForwardPayload,
1433+
/// Shared secret that was used to decrypt next_hop_data.
1434+
shared_secret: SharedSecret,
14311435
/// HMAC of the next hop's onion packet.
14321436
next_hop_hmac: [u8; 32],
14331437
/// Bytes of the onion packet we're forwarding.
14341438
new_packet_bytes: [u8; ONION_DATA_LEN],
14351439
},
14361440
/// This onion payload was for us, not for forwarding to a next-hop. Contains information for
14371441
/// verifying the incoming payment.
1438-
Receive(msgs::InboundOnionReceivePayload),
1442+
Receive {
1443+
/// Onion payload data used to receive our payment.
1444+
hop_data: msgs::InboundOnionReceivePayload,
1445+
/// Shared secret that was used to decrypt hop_data.
1446+
shared_secret: SharedSecret,
1447+
},
14391448
/// This onion payload was for us, not for forwarding to a next-hop. Contains information for
14401449
/// verifying the incoming payment.
1441-
BlindedReceive(msgs::InboundOnionBlindedReceivePayload),
1450+
BlindedReceive {
1451+
/// Onion payload data used to receive our payment.
1452+
hop_data: msgs::InboundOnionBlindedReceivePayload,
1453+
/// Shared secret that was used to decrypt hop_data.
1454+
shared_secret: SharedSecret,
1455+
},
14421456
}
14431457

14441458
impl Hop {
@@ -1454,6 +1468,15 @@ impl Hop {
14541468
_ => false,
14551469
}
14561470
}
1471+
1472+
pub(crate) fn shared_secret(&self) -> SharedSecret {
1473+
match self {
1474+
Hop::Forward { shared_secret, .. } => shared_secret.clone(),
1475+
Hop::BlindedForward { shared_secret, .. } => shared_secret.clone(),
1476+
Hop::Receive { shared_secret, .. } => shared_secret.clone(),
1477+
Hop::BlindedReceive { shared_secret, .. } => shared_secret.clone(),
1478+
}
1479+
}
14571480
}
14581481

14591482
/// Error returned when we fail to decode the onion packet.
@@ -1466,12 +1489,23 @@ pub(crate) enum OnionDecodeErr {
14661489
}
14671490

14681491
pub(crate) fn decode_next_payment_hop<NS: Deref>(
1469-
shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32], payment_hash: PaymentHash,
1470-
blinding_point: Option<PublicKey>, node_signer: NS,
1492+
recipient: Recipient, hop_pubkey: &PublicKey, hop_data: &[u8], hmac_bytes: [u8; 32],
1493+
payment_hash: PaymentHash, blinding_point: Option<PublicKey>, node_signer: NS,
14711494
) -> Result<Hop, OnionDecodeErr>
14721495
where
14731496
NS::Target: NodeSigner,
14741497
{
1498+
let blinded_node_id_tweak = blinding_point.map(|bp| {
1499+
let blinded_tlvs_ss = node_signer.ecdh(recipient, &bp, None).unwrap().secret_bytes();
1500+
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
1501+
hmac.input(blinded_tlvs_ss.as_ref());
1502+
Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap()
1503+
});
1504+
let shared_secret = node_signer
1505+
.ecdh(recipient, hop_pubkey, blinded_node_id_tweak.as_ref())
1506+
.unwrap()
1507+
.secret_bytes();
1508+
14751509
let decoded_hop: Result<(msgs::InboundOnionPayload, Option<_>), _> = decode_next_hop(
14761510
shared_secret,
14771511
hop_data,
@@ -1482,11 +1516,19 @@ where
14821516
match decoded_hop {
14831517
Ok((next_hop_data, Some((next_hop_hmac, FixedSizeOnionPacket(new_packet_bytes))))) => {
14841518
match next_hop_data {
1485-
msgs::InboundOnionPayload::Forward(next_hop_data) => {
1486-
Ok(Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes })
1487-
},
1519+
msgs::InboundOnionPayload::Forward(next_hop_data) => Ok(Hop::Forward {
1520+
shared_secret: SharedSecret::from_bytes(shared_secret),
1521+
next_hop_data,
1522+
next_hop_hmac,
1523+
new_packet_bytes,
1524+
}),
14881525
msgs::InboundOnionPayload::BlindedForward(next_hop_data) => {
1489-
Ok(Hop::BlindedForward { next_hop_data, next_hop_hmac, new_packet_bytes })
1526+
Ok(Hop::BlindedForward {
1527+
shared_secret: SharedSecret::from_bytes(shared_secret),
1528+
next_hop_data,
1529+
next_hop_hmac,
1530+
new_packet_bytes,
1531+
})
14901532
},
14911533
_ => Err(OnionDecodeErr::Relay {
14921534
err_msg: "Final Node OnionHopData provided for us as an intermediary node",
@@ -1495,8 +1537,14 @@ where
14951537
}
14961538
},
14971539
Ok((next_hop_data, None)) => match next_hop_data {
1498-
msgs::InboundOnionPayload::Receive(payload) => Ok(Hop::Receive(payload)),
1499-
msgs::InboundOnionPayload::BlindedReceive(payload) => Ok(Hop::BlindedReceive(payload)),
1540+
msgs::InboundOnionPayload::Receive(hop_data) => Ok(Hop::Receive {
1541+
shared_secret: SharedSecret::from_bytes(shared_secret),
1542+
hop_data,
1543+
}),
1544+
msgs::InboundOnionPayload::BlindedReceive(hop_data) => Ok(Hop::BlindedReceive {
1545+
shared_secret: SharedSecret::from_bytes(shared_secret),
1546+
hop_data,
1547+
}),
15001548
_ => Err(OnionDecodeErr::Relay {
15011549
err_msg: "Intermediate Node OnionHopData provided for us as a final node",
15021550
err_code: 0x4000 | 22,

lightning/src/sign/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,7 @@ pub trait ChannelSigner {
822822
///
823823
/// This indicates to [`NodeSigner::sign_invoice`] what node secret key should be used to sign
824824
/// the invoice.
825+
#[derive(Clone, Copy)]
825826
pub enum Recipient {
826827
/// The invoice should be signed with the local node secret key.
827828
Node,

0 commit comments

Comments
 (0)