Move blinded_path and its utils into a new module
authorValentine Wallace <vwallace@protonmail.com>
Thu, 16 Mar 2023 01:56:57 +0000 (21:56 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Thu, 20 Apr 2023 14:14:15 +0000 (10:14 -0400)
16 files changed:
fuzz/src/invoice_request_deser.rs
fuzz/src/refund_deser.rs
lightning/src/blinded_path/mod.rs [new file with mode: 0644]
lightning/src/blinded_path/utils.rs [new file with mode: 0644]
lightning/src/lib.rs
lightning/src/offers/invoice.rs
lightning/src/offers/invoice_request.rs
lightning/src/offers/offer.rs
lightning/src/offers/refund.rs
lightning/src/offers/test_utils.rs
lightning/src/onion_message/blinded_path.rs [deleted file]
lightning/src/onion_message/functional_tests.rs
lightning/src/onion_message/messenger.rs
lightning/src/onion_message/mod.rs
lightning/src/onion_message/packet.rs
lightning/src/onion_message/utils.rs [deleted file]

index aa3045ccb247e36d82990dc314caf15ecc5f0e5e..5239c1e7911f9a4e27bb63666d7041edf74eca2a 100644 (file)
 use bitcoin::secp256k1::{KeyPair, Parity, PublicKey, Secp256k1, SecretKey, self};
 use crate::utils::test_logger;
 use core::convert::{Infallible, TryFrom};
+use lightning::blinded_path::BlindedPath;
 use lightning::chain::keysinterface::EntropySource;
 use lightning::ln::PaymentHash;
 use lightning::ln::features::BlindedHopFeatures;
 use lightning::offers::invoice::{BlindedPayInfo, UnsignedInvoice};
 use lightning::offers::invoice_request::InvoiceRequest;
 use lightning::offers::parse::SemanticError;
-use lightning::onion_message::BlindedPath;
 use lightning::util::ser::Writeable;
 
 #[inline]
index 9adaa3e953cb63c97152eef3ea3ce8f339968f26..fab303050901d0fb4b51fa7fee3e3423206f6d45 100644 (file)
 use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey, self};
 use crate::utils::test_logger;
 use core::convert::{Infallible, TryFrom};
+use lightning::blinded_path::BlindedPath;
 use lightning::chain::keysinterface::EntropySource;
 use lightning::ln::PaymentHash;
 use lightning::ln::features::BlindedHopFeatures;
 use lightning::offers::invoice::{BlindedPayInfo, UnsignedInvoice};
 use lightning::offers::parse::SemanticError;
 use lightning::offers::refund::Refund;
-use lightning::onion_message::BlindedPath;
 use lightning::util::ser::Writeable;
 
 #[inline]
diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs
new file mode 100644 (file)
index 0000000..a4128d6
--- /dev/null
@@ -0,0 +1,232 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Creating blinded paths and related utilities live here.
+
+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 crate::chain::keysinterface::{EntropySource, NodeSigner, Recipient};
+use crate::onion_message::ControlTlvs;
+use crate::ln::msgs::DecodeError;
+use crate::ln::onion_utils;
+use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
+use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, VecWriter, Writeable, Writer};
+
+use core::mem;
+use core::ops::Deref;
+use crate::io::{self, Cursor};
+use crate::prelude::*;
+
+/// Onion messages can be sent and received to blinded paths, which serve to hide the identity of
+/// the recipient.
+#[derive(Clone, Debug, PartialEq)]
+pub struct BlindedPath {
+       /// To send to a blinded path, the sender first finds a route to the unblinded
+       /// `introduction_node_id`, which can unblind its [`encrypted_payload`] to find out the onion
+       /// message's next hop and forward it along.
+       ///
+       /// [`encrypted_payload`]: BlindedHop::encrypted_payload
+       pub(crate) introduction_node_id: PublicKey,
+       /// Used by the introduction node to decrypt its [`encrypted_payload`] to forward the onion
+       /// message.
+       ///
+       /// [`encrypted_payload`]: BlindedHop::encrypted_payload
+       pub(crate) blinding_point: PublicKey,
+       /// The hops composing the blinded path.
+       pub(crate) blinded_hops: Vec<BlindedHop>,
+}
+
+/// Used to construct the blinded hops portion of a blinded path. These hops cannot be identified
+/// by outside observers and thus can be used to hide the identity of the recipient.
+#[derive(Clone, Debug, PartialEq)]
+pub struct BlindedHop {
+       /// The blinded node id of this hop in a blinded path.
+       pub(crate) blinded_node_id: PublicKey,
+       /// The encrypted payload intended for this hop in a blinded path.
+       // The node sending to this blinded path will later encode this payload into the onion packet for
+       // this hop.
+       pub(crate) encrypted_payload: Vec<u8>,
+}
+
+impl BlindedPath {
+       /// Create a blinded path to be forwarded along `node_pks`. The last node pubkey in `node_pks`
+       /// will be the destination node.
+       ///
+       /// Errors if less than two hops are provided or if `node_pk`(s) are invalid.
+       //  TODO: make all payloads the same size with padding + add dummy hops
+       pub fn new<ES: EntropySource, T: secp256k1::Signing + secp256k1::Verification>
+               (node_pks: &[PublicKey], entropy_source: &ES, secp_ctx: &Secp256k1<T>) -> Result<Self, ()>
+       {
+               if node_pks.len() < 2 { return Err(()) }
+               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 = node_pks[0];
+
+               Ok(BlindedPath {
+                       introduction_node_id,
+                       blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
+                       blinded_hops: blinded_hops(secp_ctx, node_pks, &blinding_secret).map_err(|_| ())?,
+               })
+       }
+
+       // Advance the blinded path by one hop, so make the second hop into the new introduction node.
+       pub(super) fn advance_by_one<NS: Deref, T: secp256k1::Signing + secp256k1::Verification>
+               (&mut self, node_signer: &NS, secp_ctx: &Secp256k1<T>) -> Result<(), ()>
+               where NS::Target: NodeSigner
+       {
+               let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.blinding_point, None)?;
+               let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
+               let encrypted_control_tlvs = self.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 {
+                               mut next_node_id, next_blinding_override,
+                       })}) => {
+                               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(|_| ())?
+                                       }
+                               };
+                               mem::swap(&mut self.blinding_point, &mut new_blinding_point);
+                               mem::swap(&mut self.introduction_node_id, &mut next_node_id);
+                               Ok(())
+                       },
+                       _ => Err(())
+               }
+       }
+}
+
+/// Construct blinded hops for the given `unblinded_path`.
+fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
+       secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], session_priv: &SecretKey
+) -> Result<Vec<BlindedHop>, secp256k1::Error> {
+       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, 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: 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: encrypt_payload(final_payload, final_ss),
+               });
+       } else { debug_assert!(false) }
+
+       Ok(blinded_hops)
+}
+
+/// Encrypt TLV payload to be used as a [`BlindedHop::encrypted_payload`].
+fn encrypt_payload<P: Writeable>(payload: P, encrypted_tlvs_ss: [u8; 32]) -> Vec<u8> {
+       let mut writer = VecWriter(Vec::new());
+       let write_adapter = ChaChaPolyWriteAdapter::new(encrypted_tlvs_ss, &payload);
+       write_adapter.write(&mut writer).expect("In-memory writes cannot fail");
+       writer.0
+}
+
+impl Writeable for BlindedPath {
+       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               self.introduction_node_id.write(w)?;
+               self.blinding_point.write(w)?;
+               (self.blinded_hops.len() as u8).write(w)?;
+               for hop in &self.blinded_hops {
+                       hop.write(w)?;
+               }
+               Ok(())
+       }
+}
+
+impl Readable for BlindedPath {
+       fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
+               let introduction_node_id = Readable::read(r)?;
+               let blinding_point = Readable::read(r)?;
+               let num_hops: u8 = Readable::read(r)?;
+               if num_hops == 0 { return Err(DecodeError::InvalidValue) }
+               let mut blinded_hops: Vec<BlindedHop> = Vec::with_capacity(num_hops.into());
+               for _ in 0..num_hops {
+                       blinded_hops.push(Readable::read(r)?);
+               }
+               Ok(BlindedPath {
+                       introduction_node_id,
+                       blinding_point,
+                       blinded_hops,
+               })
+       }
+}
+
+impl_writeable!(BlindedHop, {
+       blinded_node_id,
+       encrypted_payload
+});
+
+/// 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(super) next_node_id: PublicKey,
+       /// Senders to a blinded path use this value to concatenate the route they find to the
+       /// introduction node with the blinded path.
+       pub(super) next_blinding_override: Option<PublicKey>,
+}
+
+/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
+pub(crate) struct ReceiveTlvs {
+       /// If `path_id` is `Some`, it is used to identify the blinded path that this onion message is
+       /// sending to. This is useful for receivers to check that said blinded path is being used in
+       /// the right context.
+       pub(super) path_id: Option<[u8; 32]>,
+}
+
+impl Writeable for ForwardTlvs {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               // TODO: write padding
+               encode_tlv_stream!(writer, {
+                       (4, self.next_node_id, required),
+                       (8, self.next_blinding_override, option)
+               });
+               Ok(())
+       }
+}
+
+impl Writeable for ReceiveTlvs {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               // TODO: write padding
+               encode_tlv_stream!(writer, {
+                       (6, self.path_id, option),
+               });
+               Ok(())
+       }
+}
diff --git a/lightning/src/blinded_path/utils.rs b/lightning/src/blinded_path/utils.rs
new file mode 100644 (file)
index 0000000..1993ad9
--- /dev/null
@@ -0,0 +1,98 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Onion message utility methods live here.
+
+use bitcoin::hashes::{Hash, HashEngine};
+use bitcoin::hashes::hmac::{Hmac, HmacEngine};
+use bitcoin::hashes::sha256::Hash as Sha256;
+use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey, Scalar};
+use bitcoin::secp256k1::ecdh::SharedSecret;
+
+use super::BlindedPath;
+use crate::ln::onion_utils;
+use crate::onion_message::Destination;
+
+use crate::prelude::*;
+
+// TODO: DRY with onion_utils::construct_onion_keys_callback
+#[inline]
+pub(crate) fn construct_keys_callback<T: secp256k1::Signing + secp256k1::Verification,
+       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();
+       let mut msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
+       let mut onion_packet_pubkey_priv = msg_blinding_point_priv.clone();
+       let mut onion_packet_pubkey = msg_blinding_point.clone();
+
+       macro_rules! build_keys {
+               ($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 {
+                               let hop_pk_blinding_factor = {
+                                       let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
+                                       hmac.input(encrypted_data_ss.as_ref());
+                                       Hmac::from_engine(hmac).into_inner()
+                               };
+                               $pk.mul_tweak(secp_ctx, &Scalar::from_be_bytes(hop_pk_blinding_factor).unwrap())?
+                       };
+                       let onion_packet_ss = SharedSecret::new(&blinded_hop_pk, &onion_packet_pubkey_priv);
+
+                       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, $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();
+                               sha.input(&msg_blinding_point.serialize()[..]);
+                               sha.input(encrypted_data_ss.as_ref());
+                               Sha256::from_engine(sha).into_inner()
+                       };
+
+                       msg_blinding_point_priv = msg_blinding_point_priv.mul_tweak(&Scalar::from_be_bytes(msg_blinding_point_blinding_factor).unwrap())?;
+                       msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
+
+                       let onion_packet_pubkey_blinding_factor = {
+                               let mut sha = Sha256::engine();
+                               sha.input(&onion_packet_pubkey.serialize()[..]);
+                               sha.input(onion_packet_ss.as_ref());
+                               Sha256::from_engine(sha).into_inner()
+                       };
+                       onion_packet_pubkey_priv = onion_packet_pubkey_priv.mul_tweak(&Scalar::from_be_bytes(onion_packet_pubkey_blinding_factor).unwrap())?;
+                       onion_packet_pubkey = PublicKey::from_secret_key(secp_ctx, &onion_packet_pubkey_priv);
+               };
+       }
+
+       for pk in unblinded_path {
+               build_keys_in_loop!(*pk, false, None);
+       }
+       if let Some(dest) = destination {
+               match dest {
+                       Destination::Node(pk) => {
+                               build_keys!(pk, false, None);
+                       },
+                       Destination::BlindedPath(BlindedPath { blinded_hops, .. }) => {
+                               for hop in blinded_hops {
+                                       build_keys_in_loop!(hop.blinded_node_id, true, Some(hop.encrypted_payload));
+                               }
+                       },
+               }
+       }
+       Ok(())
+}
index ad16914c35c3476992a1e855e7c8385e9811a7ff..668f752e6c261c455f36be6114f1597c70bb204b 100644 (file)
@@ -81,6 +81,7 @@ pub mod ln;
 pub mod offers;
 pub mod routing;
 pub mod onion_message;
+pub mod blinded_path;
 pub mod events;
 
 #[cfg(feature = "std")]
index b2717f7338f193cd17589ee7e3216c972d7463ad..5c314800887e0d05eabd660767f824cdd30d1ab2 100644 (file)
@@ -29,7 +29,7 @@
 //!
 //! # use lightning::ln::PaymentHash;
 //! # use lightning::offers::invoice::BlindedPayInfo;
-//! # use lightning::onion_message::BlindedPath;
+//! # use lightning::blinded_path::BlindedPath;
 //! #
 //! # fn create_payment_paths() -> Vec<(BlindedPath, BlindedPayInfo)> { unimplemented!() }
 //! # fn create_payment_hash() -> PaymentHash { unimplemented!() }
@@ -104,6 +104,7 @@ use bitcoin::util::schnorr::TweakedPublicKey;
 use core::convert::{Infallible, TryFrom};
 use core::time::Duration;
 use crate::io;
+use crate::blinded_path::BlindedPath;
 use crate::ln::PaymentHash;
 use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
 use crate::ln::inbound_payment::ExpandedKey;
@@ -115,7 +116,6 @@ use crate::offers::parse::{ParseError, ParsedMessage, SemanticError};
 use crate::offers::payer::{PAYER_METADATA_TYPE, PayerTlvStream, PayerTlvStreamRef};
 use crate::offers::refund::{IV_BYTES as REFUND_IV_BYTES, Refund, RefundContents};
 use crate::offers::signer;
-use crate::onion_message::BlindedPath;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, Iterable, SeekReadable, WithoutLength, Writeable, Writer};
 
 use crate::prelude::*;
@@ -926,6 +926,7 @@ mod tests {
        use bitcoin::util::schnorr::TweakedPublicKey;
        use core::convert::TryFrom;
        use core::time::Duration;
+       use crate::blinded_path::{BlindedHop, BlindedPath};
        use crate::chain::keysinterface::KeyMaterial;
        use crate::ln::features::Bolt12InvoiceFeatures;
        use crate::ln::inbound_payment::ExpandedKey;
@@ -937,7 +938,6 @@ mod tests {
        use crate::offers::payer::PayerTlvStreamRef;
        use crate::offers::refund::RefundBuilder;
        use crate::offers::test_utils::*;
-       use crate::onion_message::{BlindedHop, BlindedPath};
        use crate::util::ser::{BigSize, Iterable, Writeable};
 
        trait ToBytes {
index 92fabd6fdf0c7ab5f49c46cfd0793e02a8886774..e8aeb2c827b68e03a6f24c804532d903b53893c3 100644 (file)
@@ -60,6 +60,7 @@ use core::convert::{Infallible, TryFrom};
 use core::ops::Deref;
 use crate::chain::keysinterface::EntropySource;
 use crate::io;
+use crate::blinded_path::BlindedPath;
 use crate::ln::PaymentHash;
 use crate::ln::features::InvoiceRequestFeatures;
 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
@@ -70,7 +71,6 @@ use crate::offers::offer::{Offer, OfferContents, OfferTlvStream, OfferTlvStreamR
 use crate::offers::parse::{ParseError, ParsedMessage, SemanticError};
 use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
 use crate::offers::signer::{Metadata, MetadataMaterial};
-use crate::onion_message::BlindedPath;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, SeekReadable, WithoutLength, Writeable, Writer};
 use crate::util::string::PrintableString;
 
index d2918e809429d8f5db858b52930e8e19634e869e..2d25f8d22b062d373cd02fc9c2595d34b5f4359f 100644 (file)
@@ -27,7 +27,7 @@
 //! use lightning::offers::parse::ParseError;
 //! use lightning::util::ser::{Readable, Writeable};
 //!
-//! # use lightning::onion_message::BlindedPath;
+//! # use lightning::blinded_path::BlindedPath;
 //! # #[cfg(feature = "std")]
 //! # use std::time::SystemTime;
 //! #
@@ -76,6 +76,7 @@ use core::str::FromStr;
 use core::time::Duration;
 use crate::chain::keysinterface::EntropySource;
 use crate::io;
+use crate::blinded_path::BlindedPath;
 use crate::ln::features::OfferFeatures;
 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
 use crate::ln::msgs::MAX_VALUE_MSAT;
@@ -83,7 +84,6 @@ use crate::offers::invoice_request::{DerivedPayerId, ExplicitPayerId, InvoiceReq
 use crate::offers::merkle::TlvStream;
 use crate::offers::parse::{Bech32Encode, ParseError, ParsedMessage, SemanticError};
 use crate::offers::signer::{Metadata, MetadataMaterial, self};
-use crate::onion_message::BlindedPath;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, WithoutLength, Writeable, Writer};
 use crate::util::string::PrintableString;
 
@@ -832,13 +832,13 @@ mod tests {
        use core::convert::TryFrom;
        use core::num::NonZeroU64;
        use core::time::Duration;
+       use crate::blinded_path::{BlindedHop, BlindedPath};
        use crate::chain::keysinterface::KeyMaterial;
        use crate::ln::features::OfferFeatures;
        use crate::ln::inbound_payment::ExpandedKey;
        use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
        use crate::offers::parse::{ParseError, SemanticError};
        use crate::offers::test_utils::*;
-       use crate::onion_message::{BlindedHop, BlindedPath};
        use crate::util::ser::{BigSize, Writeable};
        use crate::util::string::PrintableString;
 
index f677a2a9cdb61fcdf5f5fe9f5389a6dba895512c..1aa36167b94a14a81af7134da8e7a4630f8d5e97 100644 (file)
@@ -32,7 +32,7 @@
 //! use lightning::offers::refund::{Refund, RefundBuilder};
 //! use lightning::util::ser::{Readable, Writeable};
 //!
-//! # use lightning::onion_message::BlindedPath;
+//! # use lightning::blinded_path::BlindedPath;
 //! # #[cfg(feature = "std")]
 //! # use std::time::SystemTime;
 //! #
@@ -80,6 +80,7 @@ use core::str::FromStr;
 use core::time::Duration;
 use crate::chain::keysinterface::EntropySource;
 use crate::io;
+use crate::blinded_path::BlindedPath;
 use crate::ln::PaymentHash;
 use crate::ln::features::InvoiceRequestFeatures;
 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
@@ -90,7 +91,6 @@ use crate::offers::offer::{OfferTlvStream, OfferTlvStreamRef};
 use crate::offers::parse::{Bech32Encode, ParseError, ParsedMessage, SemanticError};
 use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
 use crate::offers::signer::{Metadata, MetadataMaterial, self};
-use crate::onion_message::BlindedPath;
 use crate::util::ser::{SeekReadable, WithoutLength, Writeable, Writer};
 use crate::util::string::PrintableString;
 
@@ -697,6 +697,7 @@ mod tests {
        use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey};
        use core::convert::TryFrom;
        use core::time::Duration;
+       use crate::blinded_path::{BlindedHop, BlindedPath};
        use crate::chain::keysinterface::KeyMaterial;
        use crate::ln::features::{InvoiceRequestFeatures, OfferFeatures};
        use crate::ln::inbound_payment::ExpandedKey;
@@ -706,7 +707,6 @@ mod tests {
        use crate::offers::parse::{ParseError, SemanticError};
        use crate::offers::payer::PayerTlvStreamRef;
        use crate::offers::test_utils::*;
-       use crate::onion_message::{BlindedHop, BlindedPath};
        use crate::util::ser::{BigSize, Writeable};
        use crate::util::string::PrintableString;
 
index 43664079dbd55580b224f1926e017525c85c9249..8ded4a66e37b0dec874e56e51b9880a02a5303f5 100644 (file)
@@ -13,11 +13,11 @@ use bitcoin::secp256k1::{KeyPair, Message, PublicKey, Secp256k1, SecretKey};
 use bitcoin::secp256k1::schnorr::Signature;
 use core::convert::Infallible;
 use core::time::Duration;
+use crate::blinded_path::{BlindedHop, BlindedPath};
 use crate::chain::keysinterface::EntropySource;
 use crate::ln::PaymentHash;
 use crate::ln::features::BlindedHopFeatures;
 use crate::offers::invoice::BlindedPayInfo;
-use crate::onion_message::{BlindedHop, BlindedPath};
 
 pub(super) fn payer_keys() -> KeyPair {
        let secp_ctx = Secp256k1::new();
diff --git a/lightning/src/onion_message/blinded_path.rs b/lightning/src/onion_message/blinded_path.rs
deleted file mode 100644 (file)
index 946e5e7..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-// This file is Copyright its original authors, visible in version control
-// history.
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-//! Creating blinded paths and related utilities live here.
-
-use bitcoin::hashes::{Hash, HashEngine};
-use bitcoin::hashes::sha256::Hash as Sha256;
-use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
-
-use crate::chain::keysinterface::{EntropySource, NodeSigner, Recipient};
-use super::packet::ControlTlvs;
-use super::utils;
-use crate::ln::msgs::DecodeError;
-use crate::ln::onion_utils;
-use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
-use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, VecWriter, Writeable, Writer};
-
-use core::mem;
-use core::ops::Deref;
-use crate::io::{self, Cursor};
-use crate::prelude::*;
-
-/// Onion messages can be sent and received to blinded paths, which serve to hide the identity of
-/// the recipient.
-#[derive(Clone, Debug, PartialEq)]
-pub struct BlindedPath {
-       /// To send to a blinded path, the sender first finds a route to the unblinded
-       /// `introduction_node_id`, which can unblind its [`encrypted_payload`] to find out the onion
-       /// message's next hop and forward it along.
-       ///
-       /// [`encrypted_payload`]: BlindedHop::encrypted_payload
-       pub(crate) introduction_node_id: PublicKey,
-       /// Used by the introduction node to decrypt its [`encrypted_payload`] to forward the onion
-       /// message.
-       ///
-       /// [`encrypted_payload`]: BlindedHop::encrypted_payload
-       pub(crate) blinding_point: PublicKey,
-       /// The hops composing the blinded path.
-       pub(crate) blinded_hops: Vec<BlindedHop>,
-}
-
-/// Used to construct the blinded hops portion of a blinded path. These hops cannot be identified
-/// by outside observers and thus can be used to hide the identity of the recipient.
-#[derive(Clone, Debug, PartialEq)]
-pub struct BlindedHop {
-       /// The blinded node id of this hop in a blinded path.
-       pub(crate) blinded_node_id: PublicKey,
-       /// The encrypted payload intended for this hop in a blinded path.
-       // The node sending to this blinded path will later encode this payload into the onion packet for
-       // this hop.
-       pub(crate) encrypted_payload: Vec<u8>,
-}
-
-impl BlindedPath {
-       /// Create a blinded path to be forwarded along `node_pks`. The last node pubkey in `node_pks`
-       /// will be the destination node.
-       ///
-       /// Errors if less than two hops are provided or if `node_pk`(s) are invalid.
-       //  TODO: make all payloads the same size with padding + add dummy hops
-       pub fn new<ES: EntropySource, T: secp256k1::Signing + secp256k1::Verification>
-               (node_pks: &[PublicKey], entropy_source: &ES, secp_ctx: &Secp256k1<T>) -> Result<Self, ()>
-       {
-               if node_pks.len() < 2 { return Err(()) }
-               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 = node_pks[0];
-
-               Ok(BlindedPath {
-                       introduction_node_id,
-                       blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
-                       blinded_hops: blinded_hops(secp_ctx, node_pks, &blinding_secret).map_err(|_| ())?,
-               })
-       }
-
-       // Advance the blinded path by one hop, so make the second hop into the new introduction node.
-       pub(super) fn advance_by_one<NS: Deref, T: secp256k1::Signing + secp256k1::Verification>
-               (&mut self, node_signer: &NS, secp_ctx: &Secp256k1<T>) -> Result<(), ()>
-               where NS::Target: NodeSigner
-       {
-               let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.blinding_point, None)?;
-               let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
-               let encrypted_control_tlvs = self.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 {
-                               mut next_node_id, next_blinding_override,
-                       })}) => {
-                               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(|_| ())?
-                                       }
-                               };
-                               mem::swap(&mut self.blinding_point, &mut new_blinding_point);
-                               mem::swap(&mut self.introduction_node_id, &mut next_node_id);
-                               Ok(())
-                       },
-                       _ => Err(())
-               }
-       }
-}
-
-/// Construct blinded hops for the given `unblinded_path`.
-fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
-       secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], session_priv: &SecretKey
-) -> Result<Vec<BlindedHop>, secp256k1::Error> {
-       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, 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: 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: encrypt_payload(final_payload, final_ss),
-               });
-       } else { debug_assert!(false) }
-
-       Ok(blinded_hops)
-}
-
-/// Encrypt TLV payload to be used as a [`BlindedHop::encrypted_payload`].
-fn encrypt_payload<P: Writeable>(payload: P, encrypted_tlvs_ss: [u8; 32]) -> Vec<u8> {
-       let mut writer = VecWriter(Vec::new());
-       let write_adapter = ChaChaPolyWriteAdapter::new(encrypted_tlvs_ss, &payload);
-       write_adapter.write(&mut writer).expect("In-memory writes cannot fail");
-       writer.0
-}
-
-impl Writeable for BlindedPath {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               self.introduction_node_id.write(w)?;
-               self.blinding_point.write(w)?;
-               (self.blinded_hops.len() as u8).write(w)?;
-               for hop in &self.blinded_hops {
-                       hop.write(w)?;
-               }
-               Ok(())
-       }
-}
-
-impl Readable for BlindedPath {
-       fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
-               let introduction_node_id = Readable::read(r)?;
-               let blinding_point = Readable::read(r)?;
-               let num_hops: u8 = Readable::read(r)?;
-               if num_hops == 0 { return Err(DecodeError::InvalidValue) }
-               let mut blinded_hops: Vec<BlindedHop> = Vec::with_capacity(num_hops.into());
-               for _ in 0..num_hops {
-                       blinded_hops.push(Readable::read(r)?);
-               }
-               Ok(BlindedPath {
-                       introduction_node_id,
-                       blinding_point,
-                       blinded_hops,
-               })
-       }
-}
-
-impl_writeable!(BlindedHop, {
-       blinded_node_id,
-       encrypted_payload
-});
-
-/// 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(super) next_node_id: PublicKey,
-       /// Senders to a blinded path use this value to concatenate the route they find to the
-       /// introduction node with the blinded path.
-       pub(super) next_blinding_override: Option<PublicKey>,
-}
-
-/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
-pub(crate) struct ReceiveTlvs {
-       /// If `path_id` is `Some`, it is used to identify the blinded path that this onion message is
-       /// sending to. This is useful for receivers to check that said blinded path is being used in
-       /// the right context.
-       pub(super) path_id: Option<[u8; 32]>,
-}
-
-impl Writeable for ForwardTlvs {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
-               // TODO: write padding
-               encode_tlv_stream!(writer, {
-                       (4, self.next_node_id, required),
-                       (8, self.next_blinding_override, option)
-               });
-               Ok(())
-       }
-}
-
-impl Writeable for ReceiveTlvs {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
-               // TODO: write padding
-               encode_tlv_stream!(writer, {
-                       (6, self.path_id, option),
-               });
-               Ok(())
-       }
-}
index 89582305c2107baabcce522937ab13f793b0efbc..df13aa2cbec24e5068b7a3cdca31da609a3136aa 100644 (file)
@@ -9,10 +9,11 @@
 
 //! Onion message testing and test utilities live here.
 
+use crate::blinded_path::BlindedPath;
 use crate::chain::keysinterface::{NodeSigner, Recipient};
 use crate::ln::features::InitFeatures;
 use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
-use super::{BlindedPath, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError};
+use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError};
 use crate::util::ser::{Writeable, Writer};
 use crate::util::test_utils;
 
index b9269c7cf2c058dc9297b451f029fb068fa06793..72b67dc92912ecb7d499353ea5f1e4328e7eec71 100644 (file)
@@ -15,16 +15,15 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine};
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
 
+use crate::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs, utils};
 use crate::chain::keysinterface::{EntropySource, KeysManager, NodeSigner, Recipient};
 use crate::events::OnionMessageProvider;
 use crate::ln::features::{InitFeatures, NodeFeatures};
 use crate::ln::msgs::{self, OnionMessageHandler};
 use crate::ln::onion_utils;
 use crate::ln::peer_handler::IgnoringMessageHandler;
-use super::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs};
 pub use super::packet::{CustomOnionMessageContents, OnionMessageContents};
 use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN};
-use super::utils;
 use crate::util::logger::Logger;
 use crate::util::ser::Writeable;
 
@@ -43,9 +42,10 @@ use crate::prelude::*;
 /// # extern crate bitcoin;
 /// # use bitcoin::hashes::_export::_core::time::Duration;
 /// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
+/// # use lightning::blinded_path::BlindedPath;
 /// # use lightning::chain::keysinterface::KeysManager;
 /// # use lightning::ln::peer_handler::IgnoringMessageHandler;
-/// # use lightning::onion_message::{BlindedPath, CustomOnionMessageContents, Destination, OnionMessageContents, OnionMessenger};
+/// # use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents, OnionMessenger};
 /// # use lightning::util::logger::{Logger, Record};
 /// # use lightning::util::ser::{Writeable, Writer};
 /// # use lightning::io;
index e735b428ea03dea6a26018bf23ac8ff4670e7c33..713b83c62d67d3e0a2fdcc39fd5a004d8a744e6c 100644 (file)
 //! information on its usage.
 //!
 //! [offers]: <https://github.com/lightning/bolts/pull/798>
-//! [blinded paths]: crate::onion_message::BlindedPath
+//! [blinded paths]: crate::blinded_path::BlindedPath
 
-mod blinded_path;
 mod messenger;
 mod packet;
-mod utils;
 #[cfg(test)]
 mod functional_tests;
 
 // Re-export structs so they can be imported with just the `onion_message::` module prefix.
-pub use self::blinded_path::{BlindedPath, BlindedHop};
 pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
-pub(crate) use self::packet::Packet;
+pub(crate) use self::packet::{ControlTlvs, Packet};
index d22ff0682da285ed5d717158060c72144f70b533..2fb2407dbdd093bdbe4ae260e31f12fbe4722d8a 100644 (file)
@@ -12,9 +12,9 @@
 use bitcoin::secp256k1::PublicKey;
 use bitcoin::secp256k1::ecdh::SharedSecret;
 
+use crate::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs};
 use crate::ln::msgs::DecodeError;
 use crate::ln::onion_utils;
-use super::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs};
 use super::messenger::CustomOnionMessageHandler;
 use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
 use crate::util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer};
@@ -149,7 +149,7 @@ pub(super) enum ForwardControlTlvs {
        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_path::ForwardTlvs`] for more info.
+       /// them into an intermediate Vec. See [`crate::blinded_path::ForwardTlvs`] for more info.
        Unblinded(ForwardTlvs),
 }
 
@@ -157,7 +157,7 @@ pub(super) enum ForwardControlTlvs {
 pub(super) enum ReceiveControlTlvs {
        /// See [`ForwardControlTlvs::Blinded`].
        Blinded(Vec<u8>),
-       /// See [`ForwardControlTlvs::Unblinded`] and [`super::blinded_path::ReceiveTlvs`].
+       /// See [`ForwardControlTlvs::Unblinded`] and [`crate::blinded_path::ReceiveTlvs`].
        Unblinded(ReceiveTlvs),
 }
 
@@ -255,7 +255,7 @@ impl<H: CustomOnionMessageHandler> ReadableArgs<(SharedSecret, &H)> for Payload<
 /// When reading a packet off the wire, we don't know a priori whether the packet is to be forwarded
 /// or received. Thus we read a ControlTlvs rather than reading a ForwardControlTlvs or
 /// ReceiveControlTlvs directly.
-pub(super) enum ControlTlvs {
+pub(crate) enum ControlTlvs {
        /// This onion message is intended to be forwarded.
        Forward(ForwardTlvs),
        /// This onion message is intended to be received.
diff --git a/lightning/src/onion_message/utils.rs b/lightning/src/onion_message/utils.rs
deleted file mode 100644 (file)
index ae9e0a7..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-// This file is Copyright its original authors, visible in version control
-// history.
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-//! Onion message utility methods live here.
-
-use bitcoin::hashes::{Hash, HashEngine};
-use bitcoin::hashes::hmac::{Hmac, HmacEngine};
-use bitcoin::hashes::sha256::Hash as Sha256;
-use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey, Scalar};
-use bitcoin::secp256k1::ecdh::SharedSecret;
-
-use crate::ln::onion_utils;
-use super::blinded_path::BlindedPath;
-use super::messenger::Destination;
-
-use crate::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>, 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();
-       let mut msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
-       let mut onion_packet_pubkey_priv = msg_blinding_point_priv.clone();
-       let mut onion_packet_pubkey = msg_blinding_point.clone();
-
-       macro_rules! build_keys {
-               ($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 {
-                               let hop_pk_blinding_factor = {
-                                       let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
-                                       hmac.input(encrypted_data_ss.as_ref());
-                                       Hmac::from_engine(hmac).into_inner()
-                               };
-                               $pk.mul_tweak(secp_ctx, &Scalar::from_be_bytes(hop_pk_blinding_factor).unwrap())?
-                       };
-                       let onion_packet_ss = SharedSecret::new(&blinded_hop_pk, &onion_packet_pubkey_priv);
-
-                       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, $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();
-                               sha.input(&msg_blinding_point.serialize()[..]);
-                               sha.input(encrypted_data_ss.as_ref());
-                               Sha256::from_engine(sha).into_inner()
-                       };
-
-                       msg_blinding_point_priv = msg_blinding_point_priv.mul_tweak(&Scalar::from_be_bytes(msg_blinding_point_blinding_factor).unwrap())?;
-                       msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
-
-                       let onion_packet_pubkey_blinding_factor = {
-                               let mut sha = Sha256::engine();
-                               sha.input(&onion_packet_pubkey.serialize()[..]);
-                               sha.input(onion_packet_ss.as_ref());
-                               Sha256::from_engine(sha).into_inner()
-                       };
-                       onion_packet_pubkey_priv = onion_packet_pubkey_priv.mul_tweak(&Scalar::from_be_bytes(onion_packet_pubkey_blinding_factor).unwrap())?;
-                       onion_packet_pubkey = PublicKey::from_secret_key(secp_ctx, &onion_packet_pubkey_priv);
-               };
-       }
-
-       for pk in unblinded_path {
-               build_keys_in_loop!(*pk, false, None);
-       }
-       if let Some(dest) = destination {
-               match dest {
-                       Destination::Node(pk) => {
-                               build_keys!(pk, false, None);
-                       },
-                       Destination::BlindedPath(BlindedPath { blinded_hops, .. }) => {
-                               for hop in blinded_hops {
-                                       build_keys_in_loop!(hop.blinded_node_id, true, Some(hop.encrypted_payload));
-                               }
-                       },
-               }
-       }
-       Ok(())
-}