Merge pull request #1839 from ariard/2022-11-increase-visibility-helpers
[rust-lightning] / lightning / src / onion_message / blinded_route.rs
index e47c77de35459ba0b1082117c06d7e291d052d5d..8a8d9924f9fb0ce33fcaca28602ff29a8598816d 100644 (file)
@@ -9,44 +9,52 @@
 
 //! Creating blinded routes and related utilities live here.
 
-use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
+use bitcoin::hashes::{Hash, HashEngine};
+use bitcoin::hashes::sha256::Hash as Sha256;
+use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
 
-use chain::keysinterface::KeysInterface;
+use crate::chain::keysinterface::{KeysInterface, Recipient};
+use super::packet::ControlTlvs;
 use super::utils;
-use ln::msgs::DecodeError;
-use util::chacha20poly1305rfc::ChaChaPolyWriteAdapter;
-use util::ser::{Readable, VecWriter, Writeable, Writer};
+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 io;
-use prelude::*;
+use core::mem;
+use core::ops::Deref;
+use crate::io::{self, Cursor};
+use crate::prelude::*;
 
 /// Onion messages can be sent and received to blinded routes, which serve to hide the identity of
 /// the recipient.
+#[derive(Clone, Debug, PartialEq)]
 pub struct BlindedRoute {
        /// To send to a blinded route, 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(super) introduction_node_id: PublicKey,
+       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(super) blinding_point: PublicKey,
+       pub(crate) blinding_point: PublicKey,
        /// The hops composing the blinded route.
-       pub(super) blinded_hops: Vec<BlindedHop>,
+       pub(crate) 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.
+#[derive(Clone, Debug, PartialEq)]
 pub struct BlindedHop {
        /// The blinded node id of this hop in a blinded route.
-       pub(super) blinded_node_id: PublicKey,
+       pub(crate) 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.
-       pub(super) encrypted_payload: Vec<u8>,
+       pub(crate) encrypted_payload: Vec<u8>,
 }
 
 impl BlindedRoute {
@@ -69,6 +77,41 @@ impl BlindedRoute {
                        blinded_hops: blinded_hops(secp_ctx, node_pks, &blinding_secret).map_err(|_| ())?,
                })
        }
+
+       // Advance the blinded route by one hop, so make the second hop into the new introduction node.
+       pub(super) fn advance_by_one<K: Deref, T: secp256k1::Signing + secp256k1::Verification>
+               (&mut self, keys_manager: &K, secp_ctx: &Secp256k1<T>) -> Result<(), ()>
+               where K::Target: KeysInterface
+       {
+               let control_tlvs_ss = keys_manager.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`.