X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fonion_message%2Fblinded_route.rs;h=8a8d9924f9fb0ce33fcaca28602ff29a8598816d;hb=d6aa1bc85a537e2f1e61da3edb50bc24fcd80f7e;hp=9f1d8db46dd84d3477600e1d5a19015b3cb9e6aa;hpb=ee2f1a929ed427c5b2f963a3d13da2fec1a1cc24;p=rust-lightning diff --git a/lightning/src/onion_message/blinded_route.rs b/lightning/src/onion_message/blinded_route.rs index 9f1d8db4..8a8d9924 100644 --- a/lightning/src/onion_message/blinded_route.rs +++ b/lightning/src/onion_message/blinded_route.rs @@ -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, Sign}; +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, + pub(crate) blinded_hops: Vec, } /// 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, + pub(crate) encrypted_payload: Vec, } impl BlindedRoute { @@ -55,7 +63,7 @@ impl BlindedRoute { /// /// 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 + pub fn new (node_pks: &[PublicKey], keys_manager: &K, secp_ctx: &Secp256k1) -> Result { if node_pks.len() < 2 { return Err(()) } @@ -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 + (&mut self, keys_manager: &K, secp_ctx: &Secp256k1) -> 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`.