Skip to content

Commit 9e6c7dc

Browse files
Support sending and receiving reply paths
1 parent bfaeedd commit 9e6c7dc

File tree

4 files changed

+123
-23
lines changed

4 files changed

+123
-23
lines changed

lightning/src/onion_message/blinded_route.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1313

1414
use chain::keysinterface::{KeysInterface, Sign};
1515
use super::utils;
16+
use ln::msgs::DecodeError;
1617
use util::chacha20poly1305rfc::ChaChaPolyWriteAdapter;
17-
use util::ser::{VecWriter, Writeable, Writer};
18+
use util::ser::{FixedLengthReader, LengthReadable, Readable, ReadTrackingReader, VecReadWrapper, VecWriter, Writeable, Writer};
1819

1920
use core::iter::FromIterator;
2021
use io;
@@ -113,6 +114,41 @@ fn encrypt_payload<P: Writeable>(payload: P, encrypted_tlvs_ss: [u8; 32]) -> Vec
113114
writer.0
114115
}
115116

117+
impl Writeable for BlindedRoute {
118+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
119+
self.introduction_node_id.write(w)?;
120+
self.blinding_point.write(w)?;
121+
(self.blinded_hops.len() as u8).write(w)?;
122+
for hop in &self.blinded_hops {
123+
hop.write(w)?;
124+
}
125+
Ok(())
126+
}
127+
}
128+
129+
impl Readable for BlindedRoute {
130+
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
131+
let introduction_node_id = Readable::read(r)?;
132+
let blinding_point = Readable::read(r)?;
133+
let num_hops: u8 = Readable::read(r)?;
134+
if num_hops == 0 { return Err(DecodeError::InvalidValue) }
135+
let mut blinded_hops: Vec<BlindedHop> = Vec::with_capacity(num_hops.into());
136+
for i in 0..num_hops {
137+
blinded_hops.push(Readable::read(r)?);
138+
}
139+
Ok(BlindedRoute {
140+
introduction_node_id,
141+
blinding_point,
142+
blinded_hops,
143+
})
144+
}
145+
}
146+
147+
impl_writeable!(BlindedHop, {
148+
blinded_node_id,
149+
encrypted_payload
150+
});
151+
116152
/// TLVs to encode in an intermediate onion message packet's hop data. When provided in a blinded
117153
/// route, they are encoded into [`BlindedHop::encrypted_payload`].
118154
pub(crate) struct ForwardTlvs {

lightning/src/onion_message/functional_tests.rs

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ fn pass_along_path(path: &Vec<MessengerNode>, expected_path_id: Option<[u8; 32]>
7272
fn one_hop() {
7373
let nodes = create_nodes(2);
7474

75-
nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk())).unwrap();
75+
nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap();
7676
pass_along_path(&nodes, None);
7777
}
7878

7979
#[test]
8080
fn two_unblinded_hops() {
8181
let nodes = create_nodes(3);
8282

83-
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk())).unwrap();
83+
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), None).unwrap();
8484
pass_along_path(&nodes, None);
8585
}
8686

@@ -91,7 +91,7 @@ fn two_unblinded_two_blinded() {
9191
let secp_ctx = Secp256k1::new();
9292
let blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap();
9393

94-
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedRoute(blinded_route)).unwrap();
94+
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedRoute(blinded_route), None).unwrap();
9595
pass_along_path(&nodes, None);
9696
}
9797

@@ -102,7 +102,7 @@ fn three_blinded_hops() {
102102
let secp_ctx = Secp256k1::new();
103103
let blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
104104

105-
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route)).unwrap();
105+
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap();
106106
pass_along_path(&nodes, None);
107107
}
108108

@@ -116,7 +116,7 @@ fn too_big_packet_error() {
116116
let hop_node_id = PublicKey::from_secret_key(&secp_ctx, &hop_secret);
117117

118118
let hops = [hop_node_id; 400];
119-
let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id)).unwrap_err();
119+
let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), None).unwrap_err();
120120
assert_eq!(err, SendError::TooBigPacket);
121121
}
122122

@@ -129,13 +129,57 @@ fn invalid_blinded_route_error() {
129129
let secp_ctx = Secp256k1::new();
130130
let mut blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
131131
blinded_route.blinded_hops.clear();
132-
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route)).unwrap_err();
132+
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
133133
assert_eq!(err, SendError::TooFewBlindedHops);
134134

135135
// 1 hop
136136
let mut blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
137137
blinded_route.blinded_hops.remove(0);
138138
assert_eq!(blinded_route.blinded_hops.len(), 1);
139-
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route)).unwrap_err();
139+
let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
140140
assert_eq!(err, SendError::TooFewBlindedHops);
141141
}
142+
143+
#[test]
144+
fn two_hop_reply_path() {
145+
let mut nodes = create_nodes(3);
146+
let secp_ctx = Secp256k1::new();
147+
148+
// Destination::Node
149+
let reply_path = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
150+
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), Some(reply_path)).unwrap();
151+
pass_along_path(&nodes, None);
152+
nodes.reverse();
153+
pass_along_path(&nodes, None);
154+
155+
// Destination::BlindedRoute
156+
let blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
157+
let reply_path = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
158+
159+
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), Some(reply_path)).unwrap();
160+
pass_along_path(&nodes, None);
161+
nodes.reverse();
162+
pass_along_path(&nodes, None);
163+
}
164+
165+
#[test]
166+
fn three_hop_reply_path() {
167+
let mut nodes = create_nodes(4);
168+
let secp_ctx = Secp256k1::new();
169+
170+
// Destination::Node
171+
let reply_path = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
172+
nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), Some(reply_path)).unwrap();
173+
pass_along_path(&nodes, None);
174+
nodes.reverse();
175+
pass_along_path(&nodes, None);
176+
177+
// Destination::BlindedRoute
178+
let blinded_route = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
179+
let reply_path = BlindedRoute::new::<EnforcingSigner, _, _>(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
180+
181+
nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), Some(reply_path)).unwrap();
182+
pass_along_path(&nodes, None);
183+
nodes.reverse();
184+
pass_along_path(&nodes, None);
185+
}

lightning/src/onion_message/messenger.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
142142

143143
/// Send an empty onion message to `destination`, routing it through `intermediate_nodes`.
144144
/// See [`OnionMessenger`] for example usage.
145-
pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination) -> Result<(), SendError> {
145+
pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
146146
if let Destination::BlindedRoute(BlindedRoute { ref blinded_hops, .. }) = destination {
147147
if blinded_hops.len() < 2 {
148148
return Err(SendError::TooFewBlindedHops);
@@ -160,7 +160,7 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
160160
}
161161
};
162162
let (packet_payloads, packet_keys) = packet_payloads_and_keys(
163-
&self.secp_ctx, intermediate_nodes, destination, &blinding_secret)
163+
&self.secp_ctx, intermediate_nodes, destination, reply_path, &blinding_secret)
164164
.map_err(|e| SendError::Secp256k1(e))?;
165165

166166
let prng_seed = self.keys_manager.get_secure_random_bytes();
@@ -209,9 +209,17 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
209209
msg.onion_routing_packet.hmac, control_tlvs_ss)
210210
{
211211
Ok((Payload::Receive {
212-
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id })
212+
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
213213
}, None)) => {
214-
log_info!(self.logger, "Received an onion message with path_id: {:02x?}", path_id);
214+
log_info!(self.logger,
215+
"Received an onion message with path_id: {:02x?} and {}reply_path",
216+
path_id, if reply_path.is_some() { "" } else { "no " });
217+
#[cfg(test)]
218+
{
219+
if let Some(reply_path) = reply_path {
220+
self.send_onion_message(&[], Destination::BlindedRoute(reply_path), None).unwrap();
221+
}
222+
}
215223
},
216224
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
217225
next_node_id, next_blinding_override
@@ -296,7 +304,8 @@ pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger<InMemorySigner, &'a
296304
/// Construct onion packet payloads and keys for sending an onion message along the given
297305
/// `unblinded_path` to the given `destination`.
298306
fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
299-
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Destination, session_priv: &SecretKey
307+
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Destination, mut reply_path:
308+
Option<BlindedRoute>, session_priv: &SecretKey
300309
) -> Result<(Vec<(Payload, [u8; 32])>, Vec<onion_utils::OnionKeys>), secp256k1::Error> {
301310
let num_hops = unblinded_path.len() + destination.num_hops();
302311
let mut payloads = Vec::with_capacity(num_hops);
@@ -341,6 +350,7 @@ fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
341350
} else if let Some(encrypted_payload) = enc_payload_opt {
342351
payloads.push((Payload::Receive {
343352
control_tlvs: ReceiveControlTlvs::Blinded(encrypted_payload),
353+
reply_path: reply_path.take(),
344354
}, control_tlvs_ss));
345355
}
346356

@@ -358,7 +368,8 @@ fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
358368

359369
if let Some(control_tlvs_ss) = prev_control_tlvs_ss {
360370
payloads.push((Payload::Receive {
361-
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id: None, })
371+
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id: None, }),
372+
reply_path: reply_path.take(),
362373
}, control_tlvs_ss));
363374
}
364375

lightning/src/onion_message/packet.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
1414

1515
use ln::msgs::DecodeError;
1616
use ln::onion_utils;
17-
use super::blinded_route::{ForwardTlvs, ReceiveTlvs};
17+
use super::blinded_route::{BlindedRoute, ForwardTlvs, ReceiveTlvs};
1818
use util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
1919
use util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer};
2020

@@ -98,8 +98,8 @@ pub(super) enum Payload {
9898
/// This payload is for the final hop.
9999
Receive {
100100
control_tlvs: ReceiveControlTlvs,
101+
reply_path: Option<BlindedRoute>,
101102
// Coming soon:
102-
// reply_path: Option<BlindedRoute>,
103103
// message: Message,
104104
}
105105
}
@@ -135,21 +135,31 @@ pub(super) enum ReceiveControlTlvs {
135135
impl Writeable for (Payload, [u8; 32]) {
136136
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
137137
match &self.0 {
138-
Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) |
139-
Payload::Receive { control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes)} => {
138+
Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) => {
140139
encode_varint_length_prefixed_tlv!(w, {
141140
(4, encrypted_bytes, vec_type)
142141
})
143142
},
143+
Payload::Receive {
144+
control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes), reply_path
145+
} => {
146+
encode_varint_length_prefixed_tlv!(w, {
147+
(2, reply_path, option),
148+
(4, encrypted_bytes, vec_type)
149+
})
150+
},
144151
Payload::Forward(ForwardControlTlvs::Unblinded(control_tlvs)) => {
145152
let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
146153
encode_varint_length_prefixed_tlv!(w, {
147154
(4, write_adapter, required)
148155
})
149156
},
150-
Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs)} => {
157+
Payload::Receive {
158+
control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs), reply_path,
159+
} => {
151160
let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
152161
encode_varint_length_prefixed_tlv!(w, {
162+
(2, reply_path, option),
153163
(4, write_adapter, required)
154164
})
155165
},
@@ -163,12 +173,11 @@ impl ReadableArgs<SharedSecret> for Payload {
163173
fn read<R: Read>(mut r: &mut R, encrypted_tlvs_ss: SharedSecret) -> Result<Self, DecodeError> {
164174
let v: BigSize = Readable::read(r)?;
165175
let mut rd = FixedLengthReader::new(r, v.0);
166-
// TODO: support reply paths
167-
let mut _reply_path_bytes: Option<Vec<u8>> = Some(Vec::new());
176+
let mut reply_path: Option<BlindedRoute> = None;
168177
let mut read_adapter: Option<ChaChaPolyReadAdapter<ControlTlvs>> = None;
169178
let rho = onion_utils::gen_rho_from_shared_secret(&encrypted_tlvs_ss.secret_bytes());
170179
decode_tlv_stream!(&mut rd, {
171-
(2, _reply_path_bytes, vec_type),
180+
(2, reply_path, option),
172181
(4, read_adapter, (option: LengthReadableArgs, rho))
173182
});
174183
rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
@@ -179,7 +188,7 @@ impl ReadableArgs<SharedSecret> for Payload {
179188
Ok(Payload::Forward(ForwardControlTlvs::Unblinded(tlvs)))
180189
},
181190
Some(ChaChaPolyReadAdapter { readable: ControlTlvs::Receive(tlvs)}) => {
182-
Ok(Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(tlvs)})
191+
Ok(Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(tlvs), reply_path })
183192
},
184193
}
185194
}

0 commit comments

Comments
 (0)