Skip to content

Commit 2c19dea

Browse files
Add BlindedRoute Control Tlvs Padding tests
1 parent 10d4851 commit 2c19dea

File tree

3 files changed

+200
-2
lines changed

3 files changed

+200
-2
lines changed

lightning/src/onion_message/blinded_route.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,127 @@ impl Writeable for ReceiveTlvs {
200200
Ok(())
201201
}
202202
}
203+
204+
#[cfg(test)]
205+
mod test {
206+
use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1};
207+
use ::get_control_tlv_length;
208+
use super::{ForwardTlvs, ReceiveTlvs, blinded_hops};
209+
use util::ser::{VecWriter, Writeable};
210+
211+
#[test]
212+
fn padding_is_correctly_serialized() {
213+
let max_length = get_control_tlv_length!(true, true);
214+
215+
let dummy_next_node_id = PublicKey::from_slice(&hex::decode("030101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap();
216+
let dummy_blinding_override = PublicKey::from_slice(&hex::decode("030202020202020202020202020202020202020202020202020202020202020202").unwrap()[..]).unwrap();
217+
let dummy_path_id = [1; 32];
218+
219+
let no_padding_tlv = ForwardTlvs {
220+
next_node_id: dummy_next_node_id,
221+
next_blinding_override: Some(dummy_blinding_override),
222+
total_length: max_length,
223+
};
224+
225+
let blinding_override_padding_tlv = ForwardTlvs {
226+
next_node_id: dummy_next_node_id,
227+
next_blinding_override: None,
228+
total_length: max_length,
229+
};
230+
231+
let recieve_tlv_padding_tlv = ReceiveTlvs {
232+
path_id: Some(dummy_path_id),
233+
total_length: max_length,
234+
};
235+
236+
let full_padding_tlv = ReceiveTlvs {
237+
path_id: None,
238+
total_length: max_length,
239+
};
240+
241+
let mut w = VecWriter(Vec::new());
242+
no_padding_tlv.write(&mut w).unwrap();
243+
let serialized_no_padding_tlv = w.0;
244+
// As `serialized_no_padding_tlv` is the longest tlv, no padding is expected.
245+
// Expected data tlv is:
246+
// 1. 4 (type) for `next_node_id`
247+
// 2. 33 (length) for the length of a point/public key
248+
// 3. 33 bytes of the `dummy_next_node_id`
249+
// 4. 8 (type) for `next_blinding_override`
250+
// 5. 33 (length) for the length of a point/public key
251+
// 6. 33 bytes of the `dummy_blinding_override`
252+
let expected_serialized_no_padding_tlv_payload = &hex::decode("04210301010101010101010101010101010101010101010101010101010101010101010821030202020202020202020202020202020202020202020202020202020202020202").unwrap()[..];
253+
assert_eq!(serialized_no_padding_tlv, expected_serialized_no_padding_tlv_payload);
254+
assert_eq!(serialized_no_padding_tlv.len(), max_length as usize);
255+
256+
w = VecWriter(Vec::new());
257+
blinding_override_padding_tlv.write(&mut w).unwrap();
258+
let serialized_blinding_override_padding_tlv = w.0;
259+
// As `serialized_blinding_override_padding_tlv` has no `next_blinding_override`, 35 bytes
260+
// of padding is expected (the serialized length of `next_blinding_override`).
261+
// Expected data tlv is:
262+
// 1. 1 (type) for padding
263+
// 2. 33 (length) given the length of a the missing `next_blinding_override`
264+
// 3. 33 0 bytes of padding
265+
// 4. 4 (type) for `next_node_id`
266+
// 5. 33 (length) for the length of a point/public key
267+
// 6. 33 bytes of the `dummy_next_node_id`
268+
let expected_serialized_blinding_override_padding_tlv = &hex::decode("01210000000000000000000000000000000000000000000000000000000000000000000421030101010101010101010101010101010101010101010101010101010101010101").unwrap()[..];
269+
assert_eq!(serialized_blinding_override_padding_tlv, expected_serialized_blinding_override_padding_tlv);
270+
assert_eq!(serialized_blinding_override_padding_tlv.len(), max_length as usize);
271+
272+
w = VecWriter(Vec::new());
273+
recieve_tlv_padding_tlv.write(&mut w).unwrap();
274+
let serialized_recieve_tlv_padding_tlv = w.0;
275+
// As `recieve_tlv_padding_tlv` is a `ReceiveTlv` and has a `path_id`, 36 bytes of padding
276+
// is expected, ie. 70 (value of `max_length`) - 34 (the serialized length of `path_id`).
277+
// Expected data tlv is:
278+
// 1. 1 (type) for padding
279+
// 2. 34 (length) given 70 - 34
280+
// 3. 34 0 bytes of padding
281+
// 4. 6 (type) for `path_id`
282+
// 5. 32 (length) for the length of a `path_id`
283+
// 6. 32 bytes of the `path_id`
284+
let expected_serialized_recieve_tlv_padding_tlv_payload = &hex::decode("01220000000000000000000000000000000000000000000000000000000000000000000006200101010101010101010101010101010101010101010101010101010101010101").unwrap()[..];
285+
assert_eq!(serialized_recieve_tlv_padding_tlv, expected_serialized_recieve_tlv_padding_tlv_payload);
286+
assert_eq!(serialized_recieve_tlv_padding_tlv.len(), max_length as usize);
287+
288+
w = VecWriter(Vec::new());
289+
full_padding_tlv.write(&mut w).unwrap();
290+
let serialized_full_padding_tlv = w.0;
291+
// As `serialized_full_padding_tlv` is a `ReceiveTlv` with no data at alll, 70 bytes of
292+
// padding is expected (value of `max_length`).
293+
// Expected data tlv is:
294+
// 1. 1 (type) for padding
295+
// 2. 68 (length) the length of the padding minus the prefix
296+
// 3. 68 0 bytes of padding
297+
let expected_serialized_full_padding_tlv_payload = &hex::decode("01440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()[..];
298+
assert_eq!(serialized_full_padding_tlv, expected_serialized_full_padding_tlv_payload);
299+
assert_eq!(serialized_full_padding_tlv.len(), max_length as usize);
300+
}
301+
302+
#[test]
303+
fn blinded_hops_are_same_length() {
304+
let secp_ctx = Secp256k1::new();
305+
let first_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(format!("{:02}", 41).repeat(32)).unwrap()[..]).unwrap());
306+
let middle_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(format!("{:02}", 42).repeat(32)).unwrap()[..]).unwrap());
307+
let recieve_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(format!("{:02}", 43).repeat(32)).unwrap()[..]).unwrap());
308+
let session_priv = SecretKey::from_slice(&hex::decode(format!("{:02}", 3).repeat(32)).unwrap()[..]).unwrap();
309+
310+
let blinded_hops = blinded_hops(&secp_ctx, &[first_node_id, middle_node_id, recieve_node_id], &session_priv, false).unwrap();
311+
312+
// Verify that the blinded hops returned from `blinded_hops` have the same
313+
// `encrypted_payload` length, regardless of which type of payload it is.
314+
let mut expected_encrypted_payload_len = None;
315+
for blinded_hop in blinded_hops {
316+
match expected_encrypted_payload_len {
317+
None => {
318+
expected_encrypted_payload_len = Some(blinded_hop.encrypted_payload.len());
319+
},
320+
Some(expected_len) => {
321+
assert_eq!(blinded_hop.encrypted_payload.len(), expected_len)
322+
}
323+
}
324+
}
325+
}
326+
}

lightning/src/onion_message/functional_tests.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ use chain::keysinterface::{KeysInterface, Recipient};
1313
use ln::features::InitFeatures;
1414
use ln::msgs::{self, OnionMessageHandler};
1515
use super::{BlindedRoute, Destination, OnionMessenger, SendError};
16+
use super::messenger::packet_payloads_and_keys;
17+
use super::packet::{Payload, ForwardControlTlvs, ReceiveControlTlvs};
1618
use util::enforcing_trait_impls::EnforcingSigner;
1719
use util::test_utils;
1820

1921
use bitcoin::network::constants::Network;
20-
use bitcoin::secp256k1::{PublicKey, Secp256k1};
22+
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
2123

2224
use sync::Arc;
2325

@@ -180,3 +182,75 @@ fn peer_buffer_full() {
180182
let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap_err();
181183
assert_eq!(err, SendError::BufferFull);
182184
}
185+
186+
#[test]
187+
fn onion_message_blinded_control_tlv_payloads_are_same_length() {
188+
let nodes = create_nodes(4);
189+
let secp_ctx = Secp256k1::new();
190+
let two_blinded_hops = BlindedRoute::new(&[nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx, true).unwrap();
191+
let three_blinded_hops = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx, true).unwrap();
192+
let session_priv = SecretKey::from_slice(&hex::decode(format!("{:02}", 3).repeat(32)).unwrap()[..]).unwrap();
193+
194+
let only_unblinded_payloads = packet_payloads_and_keys(&secp_ctx, &[nodes[0].get_node_pk(), nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), None, &session_priv).unwrap().0;
195+
let one_unblinded_and_three_blinded_payloads = packet_payloads_and_keys(&secp_ctx, &[nodes[1].get_node_pk()], Destination::BlindedRoute(three_blinded_hops), None, &session_priv).unwrap().0;
196+
// When more that one unblinded payload exists, the blinded payloads should be the same length
197+
// as the largest unblinded payload.
198+
let multiple_unblinded_and_blinded_payloads = packet_payloads_and_keys(&secp_ctx, &[nodes[0].get_node_pk(), nodes[1].get_node_pk()], Destination::BlindedRoute(two_blinded_hops), None, &session_priv).unwrap().0;
199+
200+
// Verify that the blinded contol tlv payloads returned from `packet_payloads_and_keys` have
201+
// the same length, and that the payload for every blinded payload matches the length of the
202+
// largest unblinded payload length.
203+
for payloads in [only_unblinded_payloads, one_unblinded_and_three_blinded_payloads, multiple_unblinded_and_blinded_payloads] {
204+
let mut longest_tlv_length = None;
205+
206+
macro_rules! assign_longest_tlv_length {
207+
($unblinded_tlv_length: expr) => {
208+
if longest_tlv_length.map(|current_len| $unblinded_tlv_length > current_len).unwrap_or(true) {
209+
longest_tlv_length = Some($unblinded_tlv_length);
210+
}
211+
};
212+
}
213+
214+
macro_rules! assert_correct_tlv_length {
215+
($tlv_length: expr) => {
216+
match longest_tlv_length {
217+
None => {
218+
longest_tlv_length = Some($tlv_length);
219+
},
220+
Some(expected_len) => {
221+
assert_eq!($tlv_length, expected_len);
222+
}
223+
}
224+
};
225+
}
226+
227+
for payload in payloads {
228+
match payload.0 {
229+
Payload::Forward(control_tlvs) => {
230+
match control_tlvs {
231+
ForwardControlTlvs::Blinded(bytes) => {
232+
// 16 deducted to account for the 16 byte tag of the ChaCha encryption
233+
// in Blinded ControlTLVs
234+
assert_correct_tlv_length!(bytes.len() as u16 - 16);
235+
},
236+
ForwardControlTlvs::Unblinded(tlv) => {
237+
assign_longest_tlv_length!(tlv.total_length);
238+
},
239+
}
240+
},
241+
Payload::Receive { control_tlvs, .. } => {
242+
match control_tlvs {
243+
ReceiveControlTlvs::Blinded(bytes) => {
244+
// 16 deducted to account for the 16 byte tag of the ChaCha encryption
245+
// in Blinded ControlTLVs
246+
assert_correct_tlv_length!(bytes.len() as u16 - 16);
247+
},
248+
ReceiveControlTlvs::Unblinded(tlv) => {
249+
assign_longest_tlv_length!(tlv.total_length);
250+
},
251+
}
252+
},
253+
};
254+
}
255+
}
256+
}

lightning/src/onion_message/messenger.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger<InMemorySigner, &'a
396396

397397
/// Construct onion packet payloads and keys for sending an onion message along the given
398398
/// `unblinded_path` to the given `destination`.
399-
fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
399+
pub(super) fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
400400
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Destination, mut reply_path:
401401
Option<BlindedRoute>, session_priv: &SecretKey
402402
) -> Result<(Vec<(Payload, [u8; 32])>, Vec<onion_utils::OnionKeys>), secp256k1::Error> {

0 commit comments

Comments
 (0)