X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fonion_message%2Fblinded_route.rs;h=82a325a9e046bbd714d2b1fc6a53b89c1808d014;hb=f0775f837987dee29d85b3c717fb0b9edd1bda02;hp=d18372e3b009bb09d82a5d7b6eb62ebcdda7d4ca;hpb=9051c38ebe42e171fd0fcfa22d2b9ff6a1607b3b;p=rust-lightning diff --git a/lightning/src/onion_message/blinded_route.rs b/lightning/src/onion_message/blinded_route.rs index d18372e3..82a325a9 100644 --- a/lightning/src/onion_message/blinded_route.rs +++ b/lightning/src/onion_message/blinded_route.rs @@ -9,16 +9,22 @@ //! 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 util::chacha20poly1305rfc::ChaChaPolyWriteAdapter; -use util::ser::{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 core::iter::FromIterator; -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. @@ -55,7 +61,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 +75,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`. @@ -113,6 +154,41 @@ fn encrypt_payload(payload: P, encrypted_tlvs_ss: [u8; 32]) -> Vec writer.0 } +impl Writeable for BlindedRoute { + fn write(&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 BlindedRoute { + fn read(r: &mut R) -> Result { + 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 = Vec::with_capacity(num_hops.into()); + for _ in 0..num_hops { + blinded_hops.push(Readable::read(r)?); + } + Ok(BlindedRoute { + 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 {