Skip to content

Commit 216345e

Browse files
committed
Decrypt Trampoline onions [expound]
1 parent ea61bd9 commit 216345e

File tree

4 files changed

+82
-3
lines changed

4 files changed

+82
-3
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4453,6 +4453,9 @@ where
44534453
Err(InboundHTLCErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data)
44544454
}
44554455
},
4456+
onion_utils::Hop::TrampolineForward { outer_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, .. } => {
4457+
todo!()
4458+
},
44564459
onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes, .. } => {
44574460
match create_fwd_pending_htlc_info(msg, msgs::InboundOnionPayload::Forward(next_hop_data), next_hop_hmac,
44584461
new_packet_bytes, shared_secret, next_packet_pubkey_opt) {

lightning/src/ln/msgs.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1800,7 +1800,7 @@ mod fuzzy_internal_msgs {
18001800

18011801
#[allow(unused_imports)]
18021802
use crate::prelude::*;
1803-
1803+
use crate::routing::gossip::NodeId;
18041804
// These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
18051805
// them from untrusted input):
18061806

@@ -1811,6 +1811,13 @@ mod fuzzy_internal_msgs {
18111811
pub outgoing_cltv_value: u32,
18121812
}
18131813

1814+
pub struct InboundTrampolineForwardPayload {
1815+
pub next_node_id: NodeId,
1816+
/// The value, in msat, of the payment after this hop's fee is deducted.
1817+
pub amt_to_forward: u64,
1818+
pub outgoing_cltv_value: u32,
1819+
}
1820+
18141821
pub struct InboundTrampolineEntrypointPayload {
18151822
pub amt_to_forward: u64,
18161823
pub outgoing_cltv_value: u32,
@@ -1853,6 +1860,9 @@ mod fuzzy_internal_msgs {
18531860
Receive(InboundOnionReceivePayload),
18541861
BlindedForward(InboundOnionBlindedForwardPayload),
18551862
BlindedReceive(InboundOnionBlindedReceivePayload),
1863+
1864+
// these are inner Trampoline onions that should not be applicable outside
1865+
TrampolineForward(InboundTrampolineForwardPayload)
18561866
}
18571867

18581868
pub(crate) enum OutboundOnionPayload<'a> {

lightning/src/ln/onion_payment.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ pub(super) fn create_fwd_pending_htlc_info(
105105
}),
106106
msgs::InboundOnionPayload::TrampolineEntrypoint { .. } => {
107107
todo!()
108+
},
109+
msgs::InboundOnionPayload::TrampolineForward(_) => {
110+
// we should never be receiving inner onion packets here
111+
return Err(InboundHTLCErr {
112+
msg: "Trampoline OnionHopData provided for us as an outer onion",
113+
err_code: 0x4000 | 22,
114+
err_data: Vec::new(),
115+
})
108116
}
109117
};
110118

@@ -181,6 +189,13 @@ pub(super) fn create_recv_pending_htlc_info(
181189
msg: "Got blinded non final data with an HMAC of 0",
182190
})
183191
},
192+
onion_utils::Hop::TrampolineForward { .. } => {
193+
return Err(InboundHTLCErr {
194+
err_code: 0x4000|22,
195+
err_data: Vec::new(),
196+
msg: "Got non-final Trampoline data with an HMAC of 0",
197+
})
198+
},
184199
};
185200
// final_incorrect_cltv_expiry
186201
if onion_cltv_expiry > cltv_expiry {

lightning/src/ln/onion_utils.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey};
3434

3535
use crate::io::{Cursor, Read};
3636
use core::ops::Deref;
37-
37+
use crate::ln::msgs::InboundOnionPayload;
3838
#[allow(unused_imports)]
3939
use crate::prelude::*;
4040

@@ -1426,6 +1426,16 @@ pub(crate) enum Hop {
14261426
/// Bytes of the onion packet we're forwarding.
14271427
new_packet_bytes: [u8; ONION_DATA_LEN],
14281428
},
1429+
/// This onion was received via Trampoline, and needs to be forwarded to a subsequent Trampoline
1430+
/// node.
1431+
TrampolineForward {
1432+
outer_hop_data: msgs::InboundTrampolineEntrypointPayload,
1433+
outer_shared_secret: SharedSecret,
1434+
next_trampoline_hop_data: msgs::InboundTrampolineForwardPayload,
1435+
trampoline_shared_secret: SharedSecret,
1436+
next_trampoline_hop_hmac: [u8; 32],
1437+
new_trampoline_packet_bytes: Vec<u8>
1438+
},
14291439
/// This onion payload needs to be forwarded to a next-hop.
14301440
BlindedForward {
14311441
/// Onion payload data used in forwarding the payment.
@@ -1473,6 +1483,7 @@ impl Hop {
14731483
match self {
14741484
Hop::Forward { shared_secret, .. } => shared_secret,
14751485
Hop::BlindedForward { shared_secret, .. } => shared_secret,
1486+
Hop::TrampolineForward { outer_shared_secret, .. } => outer_shared_secret,
14761487
Hop::Receive { shared_secret, .. } => shared_secret,
14771488
Hop::BlindedReceive { shared_secret, .. } => shared_secret,
14781489
}
@@ -1509,7 +1520,7 @@ where
15091520
hop_data,
15101521
hmac_bytes,
15111522
Some(payment_hash),
1512-
(blinding_point, node_signer),
1523+
(blinding_point, &(*node_signer)),
15131524
);
15141525
match decoded_hop {
15151526
Ok((next_hop_data, Some((next_hop_hmac, FixedSizeOnionPacket(new_packet_bytes))))) => {
@@ -1551,6 +1562,46 @@ where
15511562
msgs::InboundOnionPayload::BlindedReceive(hop_data) => {
15521563
Ok(Hop::BlindedReceive { shared_secret, hop_data })
15531564
},
1565+
msgs::InboundOnionPayload::TrampolineEntrypoint(hop_data) => {
1566+
let trampoline_shared_secret = node_signer.ecdh(
1567+
recipient, &hop_data.trampoline_packet.public_key, blinded_node_id_tweak.as_ref(),
1568+
).unwrap().secret_bytes();
1569+
let decoded_trampoline_hop: Result<(msgs::InboundOnionPayload, Option<([u8; 32], Vec<u8>)>), _> = decode_next_hop(
1570+
trampoline_shared_secret,
1571+
&hop_data.trampoline_packet.hop_data,
1572+
hop_data.trampoline_packet.hmac,
1573+
Some(payment_hash),
1574+
(blinding_point, node_signer),
1575+
);
1576+
match decoded_trampoline_hop {
1577+
Ok((next_trampoline_hop_data, Some((next_trampoline_hop_hmac, new_trampoline_packet_bytes)))) => {
1578+
match next_trampoline_hop_data {
1579+
InboundOnionPayload::TrampolineForward(trampoline_hop_data) => {
1580+
Ok(Hop::TrampolineForward {
1581+
outer_hop_data: hop_data,
1582+
outer_shared_secret: shared_secret,
1583+
next_trampoline_hop_data: trampoline_hop_data,
1584+
trampoline_shared_secret: SharedSecret::from_bytes(trampoline_shared_secret),
1585+
next_trampoline_hop_hmac,
1586+
new_trampoline_packet_bytes,
1587+
})
1588+
}
1589+
_ => Err(OnionDecodeErr::Malformed {
1590+
err_msg: "Non-Trampoline onion data provided to us as inner onion",
1591+
// todo: find more suitable error code
1592+
err_code: 0x4000 | 22,
1593+
})
1594+
}
1595+
}
1596+
Ok((_next_trampoline_hop_data, None)) => {
1597+
// this is a trampoline receive
1598+
todo!()
1599+
},
1600+
Err(e) => {
1601+
Err(e)
1602+
}
1603+
}
1604+
},
15541605
_ => {
15551606
if blinding_point.is_some() {
15561607
return Err(OnionDecodeErr::Malformed {

0 commit comments

Comments
 (0)