X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fblinded_path%2Fmessage.rs;h=9a282a5f87d42658599870dd7446d5eef2e1ea5c;hb=b8d4ac1371bf0db3b28339d4e12fadf02f6add3d;hp=024fb451d00a78d1fe42a0524b042cfe3f42b9ec;hpb=381cc646c66538f69599ae4ee1224783eb5abe6a;p=rust-lightning diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 024fb451..9a282a5f 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -1,15 +1,26 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; -use crate::blinded_path::BlindedHop; + +#[allow(unused_imports)] +use crate::prelude::*; + +use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NextMessageHop, NodeIdLookUp}; use crate::blinded_path::utils; use crate::io; -use crate::prelude::*; -use crate::util::ser::{Writeable, Writer}; +use crate::io::Cursor; +use crate::ln::onion_utils; +use crate::onion_message::packet::ControlTlvs; +use crate::sign::{NodeSigner, Recipient}; +use crate::crypto::streams::ChaChaPolyReadAdapter; +use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Writeable, Writer}; + +use core::mem; +use core::ops::Deref; /// TLVs to encode in an intermediate onion message packet's hop data. When provided in a blinded /// route, they are encoded into [`BlindedHop::encrypted_payload`]. pub(crate) struct ForwardTlvs { - /// The node id of the next hop in the onion message's path. - pub(crate) next_node_id: PublicKey, + /// The next hop in the onion message's path. + pub(crate) next_hop: NextMessageHop, /// Senders to a blinded path use this value to concatenate the route they find to the /// introduction node with the blinded path. pub(crate) next_blinding_override: Option, @@ -25,9 +36,14 @@ pub(crate) struct ReceiveTlvs { impl Writeable for ForwardTlvs { fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let (next_node_id, short_channel_id) = match self.next_hop { + NextMessageHop::NodeId(pubkey) => (Some(pubkey), None), + NextMessageHop::ShortChannelId(scid) => (None, Some(scid)), + }; // TODO: write padding encode_tlv_stream!(writer, { - (4, self.next_node_id, required), + (2, short_channel_id, option), + (4, next_node_id, option), (8, self.next_blinding_override, option) }); Ok(()) @@ -48,32 +64,52 @@ impl Writeable for ReceiveTlvs { pub(super) fn blinded_hops( secp_ctx: &Secp256k1, unblinded_path: &[PublicKey], session_priv: &SecretKey ) -> Result, secp256k1::Error> { - let mut blinded_hops = Vec::with_capacity(unblinded_path.len()); + let blinded_tlvs = unblinded_path.iter() + .skip(1) // The first node's TLVs contains the next node's pubkey + .map(|pk| ForwardTlvs { next_hop: NextMessageHop::NodeId(*pk), next_blinding_override: None }) + .map(|tlvs| ControlTlvs::Forward(tlvs)) + .chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { path_id: None }))); - let mut prev_ss_and_blinded_node_id = None; - utils::construct_keys_callback(secp_ctx, unblinded_path, None, session_priv, |blinded_node_id, _, _, encrypted_payload_ss, unblinded_pk, _| { - if let Some((prev_ss, prev_blinded_node_id)) = prev_ss_and_blinded_node_id { - if let Some(pk) = unblinded_pk { - let payload = ForwardTlvs { - next_node_id: pk, - next_blinding_override: None, - }; - blinded_hops.push(BlindedHop { - blinded_node_id: prev_blinded_node_id, - encrypted_payload: utils::encrypt_payload(payload, prev_ss), - }); - } else { debug_assert!(false); } - } - prev_ss_and_blinded_node_id = Some((encrypted_payload_ss, blinded_node_id)); - })?; - - if let Some((final_ss, final_blinded_node_id)) = prev_ss_and_blinded_node_id { - let final_payload = ReceiveTlvs { path_id: None }; - blinded_hops.push(BlindedHop { - blinded_node_id: final_blinded_node_id, - encrypted_payload: utils::encrypt_payload(final_payload, final_ss), - }); - } else { debug_assert!(false) } + utils::construct_blinded_hops(secp_ctx, unblinded_path.iter(), blinded_tlvs, session_priv) +} - Ok(blinded_hops) +// Advance the blinded onion message path by one hop, so make the second hop into the new +// introduction node. +pub(crate) fn advance_path_by_one( + path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1 +) -> Result<(), ()> +where + NS::Target: NodeSigner, + NL::Target: NodeIdLookUp, + T: secp256k1::Signing + secp256k1::Verification, +{ + let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?; + let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes()); + let encrypted_control_tlvs = path.blinded_hops.remove(0).encrypted_payload; + let mut s = Cursor::new(&encrypted_control_tlvs); + let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64); + match ChaChaPolyReadAdapter::read(&mut reader, rho) { + Ok(ChaChaPolyReadAdapter { + readable: ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override }) + }) => { + let next_node_id = match next_hop { + NextMessageHop::NodeId(pubkey) => pubkey, + NextMessageHop::ShortChannelId(scid) => match node_id_lookup.next_node_id(scid) { + Some(pubkey) => pubkey, + None => return Err(()), + }, + }; + let mut new_blinding_point = match next_blinding_override { + Some(blinding_point) => blinding_point, + None => { + onion_utils::next_hop_pubkey(secp_ctx, path.blinding_point, + control_tlvs_ss.as_ref()).map_err(|_| ())? + } + }; + mem::swap(&mut path.blinding_point, &mut new_blinding_point); + path.introduction_node = IntroductionNode::NodeId(next_node_id); + Ok(()) + }, + _ => Err(()) + } }