mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 07:17:40 +01:00
Support sending onion messages
This adds several utilities in service of then adding OnionMessenger::send_onion_message, which can send to either an unblinded pubkey or a blinded route. Sending custom TLVs and sending an onion message containing a reply path are not yet supported. We also need to split the construct_keys_callback macro into two macros to avoid an unused assignment warning.
This commit is contained in:
parent
4c8dc2c2a0
commit
9051c38ebe
6 changed files with 275 additions and 24 deletions
|
@ -33,14 +33,14 @@ use io::{Cursor, Read};
|
|||
use core::convert::{AsMut, TryInto};
|
||||
use core::ops::Deref;
|
||||
|
||||
pub(super) struct OnionKeys {
|
||||
pub(crate) struct OnionKeys {
|
||||
#[cfg(test)]
|
||||
pub(super) shared_secret: SharedSecret,
|
||||
pub(crate) shared_secret: SharedSecret,
|
||||
#[cfg(test)]
|
||||
pub(super) blinding_factor: [u8; 32],
|
||||
pub(super) ephemeral_pubkey: PublicKey,
|
||||
pub(super) rho: [u8; 32],
|
||||
pub(super) mu: [u8; 32],
|
||||
pub(crate) blinding_factor: [u8; 32],
|
||||
pub(crate) ephemeral_pubkey: PublicKey,
|
||||
pub(crate) rho: [u8; 32],
|
||||
pub(crate) mu: [u8; 32],
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -52,7 +52,7 @@ pub(crate) fn gen_rho_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn gen_rho_mu_from_shared_secret(shared_secret: &[u8]) -> ([u8; 32], [u8; 32]) {
|
||||
pub(crate) fn gen_rho_mu_from_shared_secret(shared_secret: &[u8]) -> ([u8; 32], [u8; 32]) {
|
||||
assert_eq!(shared_secret.len(), 32);
|
||||
({
|
||||
let mut hmac = HmacEngine::<Sha256>::new(&[0x72, 0x68, 0x6f]); // rho
|
||||
|
@ -260,7 +260,23 @@ impl AsMut<[u8]> for FixedSizeOnionPacket {
|
|||
}
|
||||
}
|
||||
|
||||
/// panics if route_size_insane(payloads)
|
||||
pub(crate) fn payloads_serialized_length<HD: Writeable>(payloads: &Vec<HD>) -> usize {
|
||||
payloads.iter().map(|p| p.serialized_length() + 32 /* HMAC */).sum()
|
||||
}
|
||||
|
||||
/// panics if payloads_serialized_length(payloads) > packet_data_len
|
||||
pub(crate) fn construct_onion_message_packet<HD: Writeable, P: Packet<Data = Vec<u8>>>(
|
||||
payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], packet_data_len: usize) -> P
|
||||
{
|
||||
let mut packet_data = vec![0; packet_data_len];
|
||||
|
||||
let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
|
||||
chacha.process_in_place(&mut packet_data);
|
||||
|
||||
construct_onion_packet_with_init_noise::<_, _>(payloads, onion_keys, packet_data, None)
|
||||
}
|
||||
|
||||
/// panics if payloads_serialized_length(payloads) > packet_data.len()
|
||||
fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
|
||||
mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: P::Data, associated_data: Option<&PaymentHash>) -> P
|
||||
{
|
||||
|
|
|
@ -28,25 +28,25 @@ pub struct BlindedRoute {
|
|||
/// message's next hop and forward it along.
|
||||
///
|
||||
/// [`encrypted_payload`]: BlindedHop::encrypted_payload
|
||||
introduction_node_id: PublicKey,
|
||||
pub(super) introduction_node_id: PublicKey,
|
||||
/// Used by the introduction node to decrypt its [`encrypted_payload`] to forward the onion
|
||||
/// message.
|
||||
///
|
||||
/// [`encrypted_payload`]: BlindedHop::encrypted_payload
|
||||
blinding_point: PublicKey,
|
||||
pub(super) blinding_point: PublicKey,
|
||||
/// The hops composing the blinded route.
|
||||
blinded_hops: Vec<BlindedHop>,
|
||||
pub(super) blinded_hops: Vec<BlindedHop>,
|
||||
}
|
||||
|
||||
/// Used to construct the blinded hops portion of a blinded route. These hops cannot be identified
|
||||
/// by outside observers and thus can be used to hide the identity of the recipient.
|
||||
pub struct BlindedHop {
|
||||
/// The blinded node id of this hop in a blinded route.
|
||||
blinded_node_id: PublicKey,
|
||||
pub(super) blinded_node_id: PublicKey,
|
||||
/// The encrypted payload intended for this hop in a blinded route.
|
||||
// The node sending to this blinded route will later encode this payload into the onion packet for
|
||||
// this hop.
|
||||
encrypted_payload: Vec<u8>,
|
||||
pub(super) encrypted_payload: Vec<u8>,
|
||||
}
|
||||
|
||||
impl BlindedRoute {
|
||||
|
@ -78,7 +78,7 @@ fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
|
|||
let mut blinded_hops = Vec::with_capacity(unblinded_path.len());
|
||||
|
||||
let mut prev_ss_and_blinded_node_id = None;
|
||||
utils::construct_keys_callback(secp_ctx, unblinded_path, session_priv, |blinded_node_id, _, _, encrypted_payload_ss, unblinded_pk| {
|
||||
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 {
|
||||
|
@ -117,10 +117,10 @@ fn encrypt_payload<P: Writeable>(payload: P, encrypted_tlvs_ss: [u8; 32]) -> Vec
|
|||
/// 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.
|
||||
next_node_id: PublicKey,
|
||||
pub(super) next_node_id: PublicKey,
|
||||
/// Senders to a blinded route use this value to concatenate the route they find to the
|
||||
/// introduction node with the blinded route.
|
||||
next_blinding_override: Option<PublicKey>,
|
||||
pub(super) next_blinding_override: Option<PublicKey>,
|
||||
}
|
||||
|
||||
/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
|
||||
|
@ -128,7 +128,7 @@ pub(crate) struct ReceiveTlvs {
|
|||
/// If `path_id` is `Some`, it is used to identify the blinded route that this onion message is
|
||||
/// sending to. This is useful for receivers to check that said blinded route is being used in
|
||||
/// the right context.
|
||||
path_id: Option<[u8; 32]>,
|
||||
pub(super) path_id: Option<[u8; 32]>,
|
||||
}
|
||||
|
||||
impl Writeable for ForwardTlvs {
|
||||
|
|
|
@ -10,10 +10,14 @@
|
|||
//! LDK sends, receives, and forwards onion messages via the [`OnionMessenger`]. See its docs for
|
||||
//! more information.
|
||||
|
||||
use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
|
||||
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
|
||||
|
||||
use chain::keysinterface::{InMemorySigner, KeysInterface, KeysManager, Sign};
|
||||
use ln::msgs;
|
||||
use ln::onion_utils;
|
||||
use super::blinded_route::{BlindedRoute, ForwardTlvs, ReceiveTlvs};
|
||||
use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN};
|
||||
use super::utils;
|
||||
use util::logger::Logger;
|
||||
|
||||
use core::ops::Deref;
|
||||
|
@ -37,6 +41,23 @@ pub struct OnionMessenger<Signer: Sign, K: Deref, L: Deref>
|
|||
// custom_handler: CustomHandler, // handles custom onion messages
|
||||
}
|
||||
|
||||
/// The destination of an onion message.
|
||||
pub enum Destination {
|
||||
/// We're sending this onion message to a node.
|
||||
Node(PublicKey),
|
||||
/// We're sending this onion message to a blinded route.
|
||||
BlindedRoute(BlindedRoute),
|
||||
}
|
||||
|
||||
impl Destination {
|
||||
pub(super) fn num_hops(&self) -> usize {
|
||||
match self {
|
||||
Destination::Node(_) => 1,
|
||||
Destination::BlindedRoute(BlindedRoute { blinded_hops, .. }) => blinded_hops.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
|
||||
where K::Target: KeysInterface<Signer = Signer>,
|
||||
L::Target: Logger,
|
||||
|
@ -53,6 +74,36 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
|
|||
logger,
|
||||
}
|
||||
}
|
||||
|
||||
/// Send an empty onion message to `destination`, routing it through `intermediate_nodes`.
|
||||
pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination) -> Result<(), secp256k1::Error> {
|
||||
let blinding_secret_bytes = self.keys_manager.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))
|
||||
} else {
|
||||
match destination {
|
||||
Destination::Node(pk) => (pk, PublicKey::from_secret_key(&self.secp_ctx, &blinding_secret)),
|
||||
Destination::BlindedRoute(BlindedRoute { 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, &blinding_secret)?;
|
||||
|
||||
let prng_seed = self.keys_manager.get_secure_random_bytes();
|
||||
let onion_packet = construct_onion_message_packet(packet_payloads, packet_keys, prng_seed);
|
||||
|
||||
let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap();
|
||||
let pending_msgs = pending_per_peer_msgs.entry(introduction_node_id).or_insert(Vec::new());
|
||||
pending_msgs.push(
|
||||
msgs::OnionMessage {
|
||||
blinding_point,
|
||||
onion_routing_packet: onion_packet,
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: parameterize the below Simple* types with OnionMessenger and handle the messages it
|
||||
|
@ -69,3 +120,90 @@ pub type SimpleArcOnionMessenger<L> = OnionMessenger<InMemorySigner, Arc<KeysMan
|
|||
///[`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager
|
||||
///[`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager
|
||||
pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger<InMemorySigner, &'a KeysManager, &'b L>;
|
||||
|
||||
/// Construct onion packet payloads and keys for sending an onion message along the given
|
||||
/// `unblinded_path` to the given `destination`.
|
||||
fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
|
||||
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Destination, session_priv: &SecretKey
|
||||
) -> Result<(Vec<(Payload, [u8; 32])>, Vec<onion_utils::OnionKeys>), secp256k1::Error> {
|
||||
let num_hops = unblinded_path.len() + destination.num_hops();
|
||||
let mut payloads = Vec::with_capacity(num_hops);
|
||||
let mut onion_packet_keys = Vec::with_capacity(num_hops);
|
||||
|
||||
let (mut intro_node_id_blinding_pt, num_blinded_hops) = if let Destination::BlindedRoute(BlindedRoute {
|
||||
introduction_node_id, blinding_point, blinded_hops }) = &destination {
|
||||
(Some((*introduction_node_id, *blinding_point)), blinded_hops.len()) } else { (None, 0) };
|
||||
let num_unblinded_hops = num_hops - num_blinded_hops;
|
||||
|
||||
let mut unblinded_path_idx = 0;
|
||||
let mut blinded_path_idx = 0;
|
||||
let mut prev_control_tlvs_ss = None;
|
||||
utils::construct_keys_callback(secp_ctx, unblinded_path, Some(destination), session_priv, |_, onion_packet_ss, ephemeral_pubkey, control_tlvs_ss, unblinded_pk_opt, enc_payload_opt| {
|
||||
if num_unblinded_hops != 0 && unblinded_path_idx < num_unblinded_hops {
|
||||
if let Some(ss) = prev_control_tlvs_ss.take() {
|
||||
payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(
|
||||
ForwardTlvs {
|
||||
next_node_id: unblinded_pk_opt.unwrap(),
|
||||
next_blinding_override: None,
|
||||
}
|
||||
)), ss));
|
||||
}
|
||||
prev_control_tlvs_ss = Some(control_tlvs_ss);
|
||||
unblinded_path_idx += 1;
|
||||
} else if let Some((intro_node_id, blinding_pt)) = intro_node_id_blinding_pt.take() {
|
||||
if let Some(control_tlvs_ss) = prev_control_tlvs_ss.take() {
|
||||
payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
|
||||
next_node_id: intro_node_id,
|
||||
next_blinding_override: Some(blinding_pt),
|
||||
})), control_tlvs_ss));
|
||||
}
|
||||
if let Some(encrypted_payload) = enc_payload_opt {
|
||||
payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(encrypted_payload)),
|
||||
control_tlvs_ss));
|
||||
} else { debug_assert!(false); }
|
||||
blinded_path_idx += 1;
|
||||
} else if blinded_path_idx < num_blinded_hops - 1 && enc_payload_opt.is_some() {
|
||||
payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(enc_payload_opt.unwrap())),
|
||||
control_tlvs_ss));
|
||||
blinded_path_idx += 1;
|
||||
} else if let Some(encrypted_payload) = enc_payload_opt {
|
||||
payloads.push((Payload::Receive {
|
||||
control_tlvs: ReceiveControlTlvs::Blinded(encrypted_payload),
|
||||
}, control_tlvs_ss));
|
||||
}
|
||||
|
||||
let (rho, mu) = onion_utils::gen_rho_mu_from_shared_secret(onion_packet_ss.as_ref());
|
||||
onion_packet_keys.push(onion_utils::OnionKeys {
|
||||
#[cfg(test)]
|
||||
shared_secret: onion_packet_ss,
|
||||
#[cfg(test)]
|
||||
blinding_factor: [0; 32],
|
||||
ephemeral_pubkey,
|
||||
rho,
|
||||
mu,
|
||||
});
|
||||
})?;
|
||||
|
||||
if let Some(control_tlvs_ss) = prev_control_tlvs_ss {
|
||||
payloads.push((Payload::Receive {
|
||||
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id: None, })
|
||||
}, control_tlvs_ss));
|
||||
}
|
||||
|
||||
Ok((payloads, onion_packet_keys))
|
||||
}
|
||||
|
||||
fn construct_onion_message_packet(payloads: Vec<(Payload, [u8; 32])>, onion_keys: Vec<onion_utils::OnionKeys>, prng_seed: [u8; 32]) -> Packet {
|
||||
// Spec rationale:
|
||||
// "`len` allows larger messages to be sent than the standard 1300 bytes allowed for an HTLC
|
||||
// onion, but this should be used sparingly as it is reduces anonymity set, hence the
|
||||
// recommendation that it either look like an HTLC onion, or if larger, be a fixed size."
|
||||
let payloads_ser_len = onion_utils::payloads_serialized_length(&payloads);
|
||||
let hop_data_len = if payloads_ser_len <= SMALL_PACKET_HOP_DATA_LEN {
|
||||
SMALL_PACKET_HOP_DATA_LEN
|
||||
} else if payloads_ser_len <= BIG_PACKET_HOP_DATA_LEN {
|
||||
BIG_PACKET_HOP_DATA_LEN
|
||||
} else { payloads_ser_len };
|
||||
|
||||
onion_utils::construct_onion_message_packet::<_, _>(payloads, onion_keys, prng_seed, hop_data_len)
|
||||
}
|
||||
|
|
|
@ -16,5 +16,5 @@ mod utils;
|
|||
|
||||
// Re-export structs so they can be imported with just the `onion_message::` module prefix.
|
||||
pub use self::blinded_route::{BlindedRoute, BlindedHop};
|
||||
pub use self::messenger::{OnionMessenger, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
|
||||
pub use self::messenger::{Destination, OnionMessenger, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
|
||||
pub(crate) use self::packet::Packet;
|
||||
|
|
|
@ -13,12 +13,19 @@ use bitcoin::secp256k1::PublicKey;
|
|||
|
||||
use ln::msgs::DecodeError;
|
||||
use ln::onion_utils;
|
||||
use super::blinded_route::{ForwardTlvs, ReceiveTlvs};
|
||||
use util::chacha20poly1305rfc::ChaChaPolyWriteAdapter;
|
||||
use util::ser::{LengthRead, LengthReadable, Readable, Writeable, Writer};
|
||||
|
||||
use core::cmp;
|
||||
use io;
|
||||
use prelude::*;
|
||||
|
||||
// Per the spec, an onion message packet's `hop_data` field length should be
|
||||
// SMALL_PACKET_HOP_DATA_LEN if it fits, else BIG_PACKET_HOP_DATA_LEN if it fits.
|
||||
pub(super) const SMALL_PACKET_HOP_DATA_LEN: usize = 1300;
|
||||
pub(super) const BIG_PACKET_HOP_DATA_LEN: usize = 32768;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) struct Packet {
|
||||
version: u8,
|
||||
|
@ -80,3 +87,72 @@ impl LengthReadable for Packet {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Onion message payloads contain "control" TLVs and "data" TLVs. Control TLVs are used to route
|
||||
/// the onion message from hop to hop and for path verification, whereas data TLVs contain the onion
|
||||
/// message content itself, such as an invoice request.
|
||||
pub(super) enum Payload {
|
||||
/// This payload is for an intermediate hop.
|
||||
Forward(ForwardControlTlvs),
|
||||
/// This payload is for the final hop.
|
||||
Receive {
|
||||
control_tlvs: ReceiveControlTlvs,
|
||||
// Coming soon:
|
||||
// reply_path: Option<BlindedRoute>,
|
||||
// message: Message,
|
||||
}
|
||||
}
|
||||
|
||||
// Coming soon:
|
||||
// enum Message {
|
||||
// InvoiceRequest(InvoiceRequest),
|
||||
// Invoice(Invoice),
|
||||
// InvoiceError(InvoiceError),
|
||||
// CustomMessage<T>,
|
||||
// }
|
||||
|
||||
/// Forward control TLVs in their blinded and unblinded form.
|
||||
pub(super) enum ForwardControlTlvs {
|
||||
/// If we're sending to a blinded route, the node that constructed the blinded route has provided
|
||||
/// this hop's control TLVs, already encrypted into bytes.
|
||||
Blinded(Vec<u8>),
|
||||
/// If we're constructing an onion message hop through an intermediate unblinded node, we'll need
|
||||
/// to construct the intermediate hop's control TLVs in their unblinded state to avoid encoding
|
||||
/// them into an intermediate Vec. See [`super::blinded_route::ForwardTlvs`] for more info.
|
||||
Unblinded(ForwardTlvs),
|
||||
}
|
||||
|
||||
/// Receive control TLVs in their blinded and unblinded form.
|
||||
pub(super) enum ReceiveControlTlvs {
|
||||
/// See [`ForwardControlTlvs::Blinded`].
|
||||
Blinded(Vec<u8>),
|
||||
/// See [`ForwardControlTlvs::Unblinded`] and [`super::blinded_route::ReceiveTlvs`].
|
||||
Unblinded(ReceiveTlvs),
|
||||
}
|
||||
|
||||
// Uses the provided secret to simultaneously encode and encrypt the unblinded control TLVs.
|
||||
impl Writeable for (Payload, [u8; 32]) {
|
||||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
|
||||
match &self.0 {
|
||||
Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) |
|
||||
Payload::Receive { control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes)} => {
|
||||
encode_varint_length_prefixed_tlv!(w, {
|
||||
(4, encrypted_bytes, vec_type)
|
||||
})
|
||||
},
|
||||
Payload::Forward(ForwardControlTlvs::Unblinded(control_tlvs)) => {
|
||||
let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
|
||||
encode_varint_length_prefixed_tlv!(w, {
|
||||
(4, write_adapter, required)
|
||||
})
|
||||
},
|
||||
Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs)} => {
|
||||
let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
|
||||
encode_varint_length_prefixed_tlv!(w, {
|
||||
(4, write_adapter, required)
|
||||
})
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,16 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
|
|||
use bitcoin::secp256k1::ecdh::SharedSecret;
|
||||
|
||||
use ln::onion_utils;
|
||||
use super::blinded_route::BlindedRoute;
|
||||
use super::messenger::Destination;
|
||||
|
||||
use prelude::*;
|
||||
|
||||
// TODO: DRY with onion_utils::construct_onion_keys_callback
|
||||
#[inline]
|
||||
pub(super) fn construct_keys_callback<T: secp256k1::Signing + secp256k1::Verification,
|
||||
FType: FnMut(PublicKey, SharedSecret, PublicKey, [u8; 32], Option<PublicKey>)>(
|
||||
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey],
|
||||
FType: FnMut(PublicKey, SharedSecret, PublicKey, [u8; 32], Option<PublicKey>, Option<Vec<u8>>)>(
|
||||
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Option<Destination>,
|
||||
session_priv: &SecretKey, mut callback: FType
|
||||
) -> Result<(), secp256k1::Error> {
|
||||
let mut msg_blinding_point_priv = session_priv.clone();
|
||||
|
@ -32,7 +34,7 @@ pub(super) fn construct_keys_callback<T: secp256k1::Signing + secp256k1::Verific
|
|||
let mut onion_packet_pubkey = msg_blinding_point.clone();
|
||||
|
||||
macro_rules! build_keys {
|
||||
($pk: expr, $blinded: expr) => {
|
||||
($pk: expr, $blinded: expr, $encrypted_payload: expr) => {{
|
||||
let encrypted_data_ss = SharedSecret::new(&$pk, &msg_blinding_point_priv);
|
||||
|
||||
let blinded_hop_pk = if $blinded { $pk } else {
|
||||
|
@ -49,7 +51,14 @@ pub(super) fn construct_keys_callback<T: secp256k1::Signing + secp256k1::Verific
|
|||
|
||||
let rho = onion_utils::gen_rho_from_shared_secret(encrypted_data_ss.as_ref());
|
||||
let unblinded_pk_opt = if $blinded { None } else { Some($pk) };
|
||||
callback(blinded_hop_pk, onion_packet_ss, onion_packet_pubkey, rho, unblinded_pk_opt);
|
||||
callback(blinded_hop_pk, onion_packet_ss, onion_packet_pubkey, rho, unblinded_pk_opt, $encrypted_payload);
|
||||
(encrypted_data_ss, onion_packet_ss)
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! build_keys_in_loop {
|
||||
($pk: expr, $blinded: expr, $encrypted_payload: expr) => {
|
||||
let (encrypted_data_ss, onion_packet_ss) = build_keys!($pk, $blinded, $encrypted_payload);
|
||||
|
||||
let msg_blinding_point_blinding_factor = {
|
||||
let mut sha = Sha256::engine();
|
||||
|
@ -73,7 +82,19 @@ pub(super) fn construct_keys_callback<T: secp256k1::Signing + secp256k1::Verific
|
|||
}
|
||||
|
||||
for pk in unblinded_path {
|
||||
build_keys!(*pk, false);
|
||||
build_keys_in_loop!(*pk, false, None);
|
||||
}
|
||||
if let Some(dest) = destination {
|
||||
match dest {
|
||||
Destination::Node(pk) => {
|
||||
build_keys!(pk, false, None);
|
||||
},
|
||||
Destination::BlindedRoute(BlindedRoute { blinded_hops, .. }) => {
|
||||
for hop in blinded_hops {
|
||||
build_keys_in_loop!(hop.blinded_node_id, true, Some(hop.encrypted_payload));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue