Skip to content

Commit 0f587ff

Browse files
committed
Introduce parsing logic for DummyTlvs
1 parent d4c12db commit 0f587ff

File tree

1 file changed

+226
-76
lines changed

1 file changed

+226
-76
lines changed

lightning/src/onion_message/messenger.rs

Lines changed: 226 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,30 @@
1313
use bitcoin::hashes::hmac::{Hmac, HmacEngine};
1414
use bitcoin::hashes::sha256::Hash as Sha256;
1515
use bitcoin::hashes::{Hash, HashEngine};
16+
use bitcoin::secp256k1::ecdh::SharedSecret;
1617
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
1718

1819
#[cfg(async_payments)]
1920
use super::async_payments::AsyncPaymentsMessage;
2021
use super::async_payments::AsyncPaymentsMessageHandler;
2122
use super::dns_resolution::{DNSResolverMessage, DNSResolverMessageHandler};
2223
use super::offers::{OffersMessage, OffersMessageHandler};
23-
use super::packet::OnionMessageContents;
2424
use super::packet::ParsedOnionMessageContents;
25+
use super::packet::{DummyControlTlvs, OnionMessageContents};
2526
use super::packet::{
2627
ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, BIG_PACKET_HOP_DATA_LEN,
2728
SMALL_PACKET_HOP_DATA_LEN,
2829
};
2930
#[cfg(async_payments)]
3031
use crate::blinded_path::message::AsyncPaymentsContext;
3132
use crate::blinded_path::message::{
32-
BlindedMessagePath, DNSResolverContext, ForwardTlvs, MessageContext, MessageForwardNode,
33-
NextMessageHop, OffersContext, ReceiveTlvs,
33+
BlindedMessagePath, DNSResolverContext, DummyTlv, ForwardTlvs, MessageContext,
34+
MessageForwardNode, NextMessageHop, OffersContext, PrimaryDummyTlv, ReceiveTlvs,
3435
};
3536
use crate::blinded_path::utils;
3637
use crate::blinded_path::{IntroductionNode, NodeIdLookUp};
3738
use crate::events::{Event, EventHandler, EventsProvider, ReplayEvent};
39+
use crate::ln::channelmanager::Verification;
3840
use crate::ln::msgs::{
3941
self, BaseMessageHandler, MessageSendEvent, OnionMessage, OnionMessageHandler, SocketAddress,
4042
};
@@ -1045,44 +1047,46 @@ where
10451047
L::Target: Logger,
10461048
CMH::Target: CustomOnionMessageHandler,
10471049
{
1048-
let control_tlvs_ss = match node_signer.ecdh(Recipient::Node, &msg.blinding_point, None) {
1049-
Ok(ss) => ss,
1050-
Err(e) => {
1051-
log_error!(logger, "Failed to retrieve node secret: {:?}", e);
1052-
return Err(());
1053-
},
1054-
};
1055-
let onion_decode_ss = {
1056-
let blinding_factor = {
1057-
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
1058-
hmac.input(control_tlvs_ss.as_ref());
1059-
let hmac = Hmac::from_engine(hmac).to_byte_array();
1060-
Scalar::from_be_bytes(hmac).unwrap()
1061-
};
1062-
let packet_pubkey = &msg.onion_routing_packet.public_key;
1063-
match node_signer.ecdh(Recipient::Node, packet_pubkey, Some(&blinding_factor)) {
1064-
Ok(ss) => ss.secret_bytes(),
1065-
Err(()) => {
1066-
log_trace!(logger, "Failed to compute onion packet shared secret");
1050+
// Helper function to compute shared secrets for onion decoding
1051+
let compute_shared_secrets = |blinding_point: &PublicKey,
1052+
packet_pubkey: &PublicKey|
1053+
-> Result<(SharedSecret, [u8; 32]), ()> {
1054+
let control_tlvs_ss = match node_signer.ecdh(Recipient::Node, blinding_point, None) {
1055+
Ok(ss) => ss,
1056+
Err(e) => {
1057+
log_error!(logger, "Failed to retrieve node secret: {:?}", e);
10671058
return Err(());
10681059
},
1069-
}
1060+
};
1061+
1062+
let onion_decode_ss = {
1063+
let blinding_factor = {
1064+
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
1065+
hmac.input(control_tlvs_ss.as_ref());
1066+
let hmac = Hmac::from_engine(hmac).to_byte_array();
1067+
Scalar::from_be_bytes(hmac).unwrap()
1068+
};
1069+
match node_signer.ecdh(Recipient::Node, packet_pubkey, Some(&blinding_factor)) {
1070+
Ok(ss) => ss.secret_bytes(),
1071+
Err(()) => {
1072+
log_trace!(logger, "Failed to compute onion packet shared secret");
1073+
return Err(());
1074+
},
1075+
}
1076+
};
1077+
1078+
Ok((control_tlvs_ss, onion_decode_ss))
10701079
};
1071-
let next_hop = onion_utils::decode_next_untagged_hop(
1072-
onion_decode_ss,
1073-
&msg.onion_routing_packet.hop_data[..],
1074-
msg.onion_routing_packet.hmac,
1075-
(control_tlvs_ss, custom_handler.deref(), logger.deref()),
1076-
);
1077-
match next_hop {
1078-
Ok((
1079-
Payload::Receive {
1080-
message,
1081-
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context }),
1082-
reply_path,
1083-
},
1084-
None,
1085-
)) => match (message, context) {
1080+
1081+
// Helper function to process receive payloads
1082+
let process_receive_payload = |message,
1083+
context,
1084+
reply_path|
1085+
-> Result<
1086+
PeeledOnion<<<CMH>::Target as CustomOnionMessageHandler>::CustomMessage>,
1087+
(),
1088+
> {
1089+
match (message, context) {
10861090
(ParsedOnionMessageContents::Offers(msg), Some(MessageContext::Offers(ctx))) => {
10871091
Ok(PeeledOnion::Offers(msg, Some(ctx), reply_path))
10881092
},
@@ -1114,55 +1118,201 @@ where
11141118
);
11151119
Err(())
11161120
},
1117-
},
1118-
Ok((
1119-
Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
1120-
next_hop,
1121-
next_blinding_override,
1122-
})),
1123-
Some((next_hop_hmac, new_packet_bytes)),
1124-
)) => {
1125-
// TODO: we need to check whether `next_hop` is our node, in which case this is a dummy
1126-
// blinded hop and this onion message is destined for us. In this situation, we should keep
1127-
// unwrapping the onion layers to get to the final payload. Since we don't have the option
1128-
// of creating blinded paths with dummy hops currently, we should be ok to not handle this
1129-
// for now.
1130-
let packet_pubkey = msg.onion_routing_packet.public_key;
1131-
let new_pubkey_opt =
1132-
onion_utils::next_hop_pubkey(&secp_ctx, packet_pubkey, &onion_decode_ss);
1133-
let new_pubkey = match new_pubkey_opt {
1134-
Ok(pk) => pk,
1121+
}
1122+
};
1123+
1124+
// Constructs the next onion message using packet data and blinding logic.
1125+
let compute_onion_message = |packet_pubkey: PublicKey,
1126+
next_hop_hmac: [u8; 32],
1127+
new_packet_bytes: Vec<u8>,
1128+
current_blinding_point: PublicKey,
1129+
current_control_tlvs_ss: SharedSecret,
1130+
current_onion_decode_ss: [u8; 32],
1131+
blinding_point_opt: Option<PublicKey>|
1132+
-> Result<OnionMessage, ()> {
1133+
let new_pubkey = match onion_utils::next_hop_pubkey(
1134+
&secp_ctx,
1135+
packet_pubkey,
1136+
&current_onion_decode_ss,
1137+
) {
1138+
Ok(pk) => pk,
1139+
Err(e) => {
1140+
log_trace!(logger, "Failed to compute next hop packet pubkey: {}", e);
1141+
return Err(());
1142+
},
1143+
};
1144+
let outgoing_packet = Packet {
1145+
version: 0,
1146+
public_key: new_pubkey,
1147+
hop_data: new_packet_bytes,
1148+
hmac: next_hop_hmac,
1149+
};
1150+
let blinding_point = match blinding_point_opt {
1151+
Some(bp) => bp,
1152+
None => match onion_utils::next_hop_pubkey(
1153+
&secp_ctx,
1154+
current_blinding_point,
1155+
current_control_tlvs_ss.as_ref(),
1156+
) {
1157+
Ok(bp) => bp,
11351158
Err(e) => {
1136-
log_trace!(logger, "Failed to compute next hop packet pubkey: {}", e);
1159+
log_trace!(logger, "Failed to compute next blinding point: {}", e);
11371160
return Err(());
11381161
},
1139-
};
1140-
let outgoing_packet = Packet {
1141-
version: 0,
1142-
public_key: new_pubkey,
1143-
hop_data: new_packet_bytes,
1144-
hmac: next_hop_hmac,
1145-
};
1146-
let onion_message = OnionMessage {
1147-
blinding_point: match next_blinding_override {
1148-
Some(blinding_point) => blinding_point,
1149-
None => {
1150-
match onion_utils::next_hop_pubkey(
1162+
},
1163+
};
1164+
Ok(OnionMessage { blinding_point, onion_routing_packet: outgoing_packet })
1165+
};
1166+
1167+
let (control_tlvs_ss, onion_decode_ss) =
1168+
compute_shared_secrets(&msg.blinding_point, &msg.onion_routing_packet.public_key)?;
1169+
1170+
let next_hop = onion_utils::decode_next_untagged_hop(
1171+
onion_decode_ss,
1172+
&msg.onion_routing_packet.hop_data[..],
1173+
msg.onion_routing_packet.hmac,
1174+
(control_tlvs_ss, custom_handler.deref(), logger.deref()),
1175+
);
1176+
1177+
match next_hop {
1178+
Ok((
1179+
Payload::Receive {
1180+
message,
1181+
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context }),
1182+
reply_path,
1183+
},
1184+
None,
1185+
)) => process_receive_payload(message, context, reply_path),
1186+
Ok((
1187+
Payload::Dummy(DummyControlTlvs::Unblinded(DummyTlv::Primary(PrimaryDummyTlv {
1188+
dummy_tlv,
1189+
authentication,
1190+
}))),
1191+
Some((next_hop_hmac, new_packet_bytes)),
1192+
)) => {
1193+
let expanded_key = node_signer.get_expanded_key();
1194+
dummy_tlv.verify_data(authentication.0, authentication.1, &expanded_key)?;
1195+
1196+
// Start iterative processing of the dummy chain
1197+
let mut current_message = compute_onion_message(
1198+
msg.onion_routing_packet.public_key,
1199+
next_hop_hmac,
1200+
new_packet_bytes,
1201+
msg.blinding_point,
1202+
control_tlvs_ss,
1203+
onion_decode_ss,
1204+
None,
1205+
)?;
1206+
1207+
// Process subsequent dummy hops iteratively
1208+
loop {
1209+
let (current_control_tlvs_ss, current_onion_decode_ss) = compute_shared_secrets(
1210+
&current_message.blinding_point,
1211+
&current_message.onion_routing_packet.public_key,
1212+
)?;
1213+
1214+
let current_next_hop = onion_utils::decode_next_untagged_hop(
1215+
current_onion_decode_ss,
1216+
&current_message.onion_routing_packet.hop_data[..],
1217+
current_message.onion_routing_packet.hmac,
1218+
(current_control_tlvs_ss, custom_handler.deref(), logger.deref()),
1219+
);
1220+
1221+
match current_next_hop {
1222+
Ok((
1223+
Payload::Dummy(DummyControlTlvs::Unblinded(DummyTlv::Subsequent)),
1224+
Some((next_hop_hmac, new_packet_bytes)),
1225+
)) => {
1226+
// Valid: Subsequent dummy after Primary dummy, continue processing
1227+
let new_pubkey = match onion_utils::next_hop_pubkey(
1228+
&secp_ctx,
1229+
current_message.onion_routing_packet.public_key,
1230+
&current_onion_decode_ss,
1231+
) {
1232+
Ok(pk) => pk,
1233+
Err(e) => {
1234+
log_trace!(
1235+
logger,
1236+
"Failed to compute next hop packet pubkey: {}",
1237+
e
1238+
);
1239+
return Err(());
1240+
},
1241+
};
1242+
let outgoing_packet = Packet {
1243+
version: 0,
1244+
public_key: new_pubkey,
1245+
hop_data: new_packet_bytes,
1246+
hmac: next_hop_hmac,
1247+
};
1248+
let blinding_point = match onion_utils::next_hop_pubkey(
11511249
&secp_ctx,
1152-
msg.blinding_point,
1153-
control_tlvs_ss.as_ref(),
1250+
current_message.blinding_point,
1251+
current_control_tlvs_ss.as_ref(),
11541252
) {
11551253
Ok(bp) => bp,
11561254
Err(e) => {
11571255
log_trace!(logger, "Failed to compute next blinding point: {}", e);
11581256
return Err(());
11591257
},
1160-
}
1258+
};
1259+
current_message =
1260+
OnionMessage { blinding_point, onion_routing_packet: outgoing_packet };
11611261
},
1162-
},
1163-
onion_routing_packet: outgoing_packet,
1164-
};
1165-
1262+
Ok((
1263+
Payload::Receive {
1264+
message,
1265+
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context }),
1266+
reply_path,
1267+
},
1268+
None,
1269+
)) => {
1270+
// End of dummy chain, process the final receive payload
1271+
return process_receive_payload(message, context, reply_path);
1272+
},
1273+
Err(e) => {
1274+
log_trace!(
1275+
logger,
1276+
"Errored decoding onion message packet in dummy chain: {:?}",
1277+
e
1278+
);
1279+
return Err(());
1280+
},
1281+
_ => {
1282+
// Invalid: anything else breaks the expected structure
1283+
log_trace!(
1284+
logger,
1285+
"Invalid payload type in dummy chain. Expected Subsequent dummy or Receive payload."
1286+
);
1287+
return Err(());
1288+
},
1289+
}
1290+
}
1291+
},
1292+
Ok((Payload::Dummy(DummyControlTlvs::Unblinded(DummyTlv::Subsequent)), _)) => {
1293+
// ERROR: Subsequent dummy without preceding Primary dummy
1294+
log_trace!(
1295+
logger,
1296+
"Received Subsequent dummy without preceding Primary dummy - invalid structure"
1297+
);
1298+
Err(())
1299+
},
1300+
Ok((
1301+
Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
1302+
next_hop,
1303+
next_blinding_override,
1304+
})),
1305+
Some((next_hop_hmac, new_packet_bytes)),
1306+
)) => {
1307+
let onion_message = compute_onion_message(
1308+
msg.onion_routing_packet.public_key,
1309+
next_hop_hmac,
1310+
new_packet_bytes,
1311+
msg.blinding_point,
1312+
control_tlvs_ss,
1313+
onion_decode_ss,
1314+
next_blinding_override,
1315+
)?;
11661316
Ok(PeeledOnion::Forward(next_hop, onion_message))
11671317
},
11681318
Err(e) => {

0 commit comments

Comments
 (0)