From 30b74a6bcf177f8bc9c08dc0a0810eaf0a30b756 Mon Sep 17 00:00:00 2001 From: Evan Feenstra Date: Fri, 15 Sep 2023 15:47:23 -0700 Subject: [PATCH] public make_onion_message static method on OnionMessenger --- lightning/src/ln/msgs.rs | 3 +- lightning/src/onion_message/messenger.rs | 57 +++++++++++++++++------- lightning/src/onion_message/mod.rs | 3 +- lightning/src/onion_message/packet.rs | 16 ++++--- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index c617d97f..e4cc1f19 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -631,7 +631,8 @@ pub struct UpdateAddHTLC { pub struct OnionMessage { /// Used in decrypting the onion packet's payload. pub blinding_point: PublicKey, - pub(crate) onion_routing_packet: onion_message::Packet, + /// The full onion packet including hop data, pubkey, and hmac + pub onion_routing_packet: onion_message::Packet, } /// An [`update_fulfill_htlc`] message to be sent to or received from a peer. diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 1a6e2614..2a9c830d 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -283,6 +283,36 @@ where &self, path: OnionMessagePath, message: OnionMessageContents, reply_path: Option ) -> Result<(), SendError> { + let (introduction_node_id, onion_msg) = Self::create_onion_message( + &self.entropy_source, + &self.node_signer, + &self.secp_ctx, + path, + message, + reply_path + )?; + + let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap(); + if outbound_buffer_full(&introduction_node_id, &pending_per_peer_msgs) { return Err(SendError::BufferFull) } + match pending_per_peer_msgs.entry(introduction_node_id) { + hash_map::Entry::Vacant(_) => Err(SendError::InvalidFirstHop), + hash_map::Entry::Occupied(mut e) => { + e.get_mut().push_back(onion_msg); + Ok(()) + } + } + } + + /// Create an onion message with contents `message` to the destination of `path`. + /// Returns (introduction_node_id, onion_msg) + pub fn create_onion_message( + entropy_source: &ES, + node_signer: &NS, + secp_ctx: &Secp256k1, + path: OnionMessagePath, + message: OnionMessageContents, + reply_path: Option, + ) -> Result<(PublicKey, msgs::OnionMessage), SendError> { let OnionMessagePath { intermediate_nodes, mut destination } = path; if let Destination::BlindedPath(BlindedPath { ref blinded_hops, .. }) = destination { if blinded_hops.len() < 2 { @@ -296,43 +326,38 @@ where // advance the blinded path by 1 hop so the second hop is the new introduction node. if intermediate_nodes.len() == 0 { if let Destination::BlindedPath(ref mut blinded_path) = destination { - let our_node_id = self.node_signer.get_node_id(Recipient::Node) + let our_node_id = node_signer.get_node_id(Recipient::Node) .map_err(|()| SendError::GetNodeIdFailed)?; if blinded_path.introduction_node_id == our_node_id { - advance_path_by_one(blinded_path, &self.node_signer, &self.secp_ctx) + advance_path_by_one(blinded_path, node_signer, &secp_ctx) .map_err(|()| SendError::BlindedPathAdvanceFailed)?; } } } - let blinding_secret_bytes = self.entropy_source.get_secure_random_bytes(); + let blinding_secret_bytes = entropy_source.get_secure_random_bytes(); let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); let (introduction_node_id, blinding_point) = if intermediate_nodes.len() != 0 { - (intermediate_nodes[0], PublicKey::from_secret_key(&self.secp_ctx, &blinding_secret)) + (intermediate_nodes[0], PublicKey::from_secret_key(&secp_ctx, &blinding_secret)) } else { match destination { - Destination::Node(pk) => (pk, PublicKey::from_secret_key(&self.secp_ctx, &blinding_secret)), + Destination::Node(pk) => (pk, PublicKey::from_secret_key(&secp_ctx, &blinding_secret)), Destination::BlindedPath(BlindedPath { introduction_node_id, blinding_point, .. }) => (introduction_node_id, blinding_point), } }; let (packet_payloads, packet_keys) = packet_payloads_and_keys( - &self.secp_ctx, &intermediate_nodes, destination, message, reply_path, &blinding_secret) + &secp_ctx, &intermediate_nodes, destination, message, reply_path, &blinding_secret) .map_err(|e| SendError::Secp256k1(e))?; - let prng_seed = self.entropy_source.get_secure_random_bytes(); + let prng_seed = entropy_source.get_secure_random_bytes(); let onion_routing_packet = construct_onion_message_packet( packet_payloads, packet_keys, prng_seed).map_err(|()| SendError::TooBigPacket)?; - let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap(); - if outbound_buffer_full(&introduction_node_id, &pending_per_peer_msgs) { return Err(SendError::BufferFull) } - match pending_per_peer_msgs.entry(introduction_node_id) { - hash_map::Entry::Vacant(_) => Err(SendError::InvalidFirstHop), - hash_map::Entry::Occupied(mut e) => { - e.get_mut().push_back(msgs::OnionMessage { blinding_point, onion_routing_packet }); - Ok(()) - } - } + Ok((introduction_node_id, msgs::OnionMessage { + blinding_point, + onion_routing_packet + })) } fn respond_with_onion_message( diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 806f832f..ae8bae1f 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -29,4 +29,5 @@ mod functional_tests; // Re-export structs so they can be imported with just the `onion_message::` module prefix. pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; pub use self::offers::{OffersMessage, OffersMessageHandler}; -pub(crate) use self::packet::{ControlTlvs, Packet}; +pub use self::packet::Packet; +pub(crate) use self::packet::ControlTlvs; diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index a76371b3..d19bd30e 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -32,16 +32,22 @@ use crate::prelude::*; pub(super) const SMALL_PACKET_HOP_DATA_LEN: usize = 1300; pub(super) const BIG_PACKET_HOP_DATA_LEN: usize = 32768; +/// Packet of hop data for next peer #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct Packet { - pub(super) version: u8, - pub(super) public_key: PublicKey, +pub struct Packet { + /// Bolt 04 version number + pub version: u8, + /// A random sepc256k1 point, used to build the ECDH shared secret to decrypt hop_data + pub public_key: PublicKey, + /// Encrypted payload for the next hop + // // Unlike the onion packets used for payments, onion message packets can have payloads greater // than 1300 bytes. // TODO: if 1300 ends up being the most common size, optimize this to be: // enum { ThirteenHundred([u8; 1300]), VarLen(Vec) } - pub(super) hop_data: Vec, - pub(super) hmac: [u8; 32], + pub hop_data: Vec, + /// HMAC to verify the integrity of hop_data + pub hmac: [u8; 32], } impl onion_utils::Packet for Packet { -- 2.30.2