Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support constructing blinded path onion keys #2411

Merged
14 changes: 3 additions & 11 deletions lightning/src/blinded_path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@

pub(crate) mod utils;

use bitcoin::hashes::{Hash, HashEngine};
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};

use crate::sign::{EntropySource, NodeSigner, Recipient};
use crate::onion_message::ControlTlvs;
Expand Down Expand Up @@ -97,14 +95,8 @@ impl BlindedPath {
let mut new_blinding_point = match next_blinding_override {
Some(blinding_point) => blinding_point,
None => {
let blinding_factor = {
let mut sha = Sha256::engine();
sha.input(&self.blinding_point.serialize()[..]);
sha.input(control_tlvs_ss.as_ref());
Sha256::from_engine(sha).into_inner()
};
self.blinding_point.mul_tweak(secp_ctx, &Scalar::from_be_bytes(blinding_factor).unwrap())
.map_err(|_| ())?
onion_utils::next_hop_pubkey(secp_ctx, self.blinding_point,
control_tlvs_ss.as_ref()).map_err(|_| ())?
}
};
mem::swap(&mut self.blinding_point, &mut new_blinding_point);
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2868,9 +2868,9 @@ where
short_channel_id, amt_to_forward, outgoing_cltv_value
}, ..
} => {
let next_pk = onion_utils::next_hop_packet_pubkey(&self.secp_ctx,
let next_packet_pk = onion_utils::next_hop_pubkey(&self.secp_ctx,
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_pk))
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
},
// We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
// inbound channel's state.
Expand Down
53 changes: 51 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use crate::util::errors::APIError;

use bitcoin::hash_types::BlockHash;

use bitcoin::hashes::Hash;
use bitcoin::hashes::{Hash, HashEngine};
use bitcoin::hashes::hmac::{Hmac, HmacEngine};
use bitcoin::hashes::sha256::Hash as Sha256;

use bitcoin::secp256k1;
Expand All @@ -57,7 +58,12 @@ fn run_onion_failure_test<F1,F2>(_name: &str, test_case: u8, nodes: &Vec<Node>,
// 3: final node fails backward (but tamper onion payloads from node0)
// 100: trigger error in the intermediate node and tamper returning fail_htlc
// 200: trigger error in the final node and tamper returning fail_htlc
fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(_name: &str, test_case: u8, nodes: &Vec<Node>, route: &Route, payment_hash: &PaymentHash, payment_secret: &PaymentSecret, mut callback_msg: F1, mut callback_fail: F2, mut callback_node: F3, expected_retryable: bool, expected_error_code: Option<u16>, expected_channel_update: Option<NetworkUpdate>, expected_short_channel_id: Option<u64>)
fn run_onion_failure_test_with_fail_intercept<F1,F2,F3>(
_name: &str, test_case: u8, nodes: &Vec<Node>, route: &Route, payment_hash: &PaymentHash,
payment_secret: &PaymentSecret, mut callback_msg: F1, mut callback_fail: F2,
mut callback_node: F3, expected_retryable: bool, expected_error_code: Option<u16>,
expected_channel_update: Option<NetworkUpdate>, expected_short_channel_id: Option<u64>
)
where F1: for <'a> FnMut(&'a mut msgs::UpdateAddHTLC),
F2: for <'a> FnMut(&'a mut msgs::UpdateFailHTLC),
F3: FnMut(),
Expand Down Expand Up @@ -620,6 +626,49 @@ fn test_onion_failure() {
}, ||{
nodes[2].node.fail_htlc_backwards(&payment_hash);
}, true, Some(23), None, None);

run_onion_failure_test_with_fail_intercept("bogus err packet with valid hmac", 200, &nodes,
&route, &payment_hash, &payment_secret, |_msg| {}, |msg| {
let session_priv = SecretKey::from_slice(&[3; 32]).unwrap();
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
let mut decoded_err_packet = msgs::DecodedOnionErrorPacket {
failuremsg: vec![0],
pad: vec![0; 255],
hmac: [0; 32],
};
let um = onion_utils::gen_um_from_shared_secret(&onion_keys[1].shared_secret.as_ref());
let mut hmac = HmacEngine::<Sha256>::new(&um);
hmac.input(&decoded_err_packet.encode()[32..]);
decoded_err_packet.hmac = Hmac::from_engine(hmac).into_inner();
msg.reason = onion_utils::encrypt_failure_packet(
&onion_keys[1].shared_secret.as_ref(), &decoded_err_packet.encode()[..])
}, || nodes[2].node.fail_htlc_backwards(&payment_hash), false, None,
Some(NetworkUpdate::NodeFailure { node_id: route.paths[0].hops[1].pubkey, is_permanent: true }),
Some(channels[1].0.contents.short_channel_id));
run_onion_failure_test_with_fail_intercept("0-length channel update in UPDATE onion failure", 200, &nodes,
&route, &payment_hash, &payment_secret, |_msg| {}, |msg| {
let session_priv = SecretKey::from_slice(&[3; 32]).unwrap();
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
let mut decoded_err_packet = msgs::DecodedOnionErrorPacket {
failuremsg: vec![
0x10, 0x7, // UPDATE|7
0x0, 0x0 // 0-len channel update
],
pad: vec![0; 255 - 4 /* 4-byte error message */],
hmac: [0; 32],
};
let um = onion_utils::gen_um_from_shared_secret(&onion_keys[1].shared_secret.as_ref());
let mut hmac = HmacEngine::<Sha256>::new(&um);
hmac.input(&decoded_err_packet.encode()[32..]);
decoded_err_packet.hmac = Hmac::from_engine(hmac).into_inner();
msg.reason = onion_utils::encrypt_failure_packet(
&onion_keys[1].shared_secret.as_ref(), &decoded_err_packet.encode()[..])
}, || nodes[2].node.fail_htlc_backwards(&payment_hash), true, Some(0x1000|7),
Some(NetworkUpdate::ChannelFailure {
short_channel_id: channels[1].0.contents.short_channel_id,
is_permanent: false,
}),
Some(channels[1].0.contents.short_channel_id));
}

#[test]
Expand Down
Loading