use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
#[allow(unused_imports)]
use crate::prelude::*;
use bitcoin::hashes::hmac::Hmac;
use bitcoin::hashes::sha256::Hash as Sha256;
use crate::blinded_path::{BlindedHop, BlindedPath, Direction, IntroductionNode, NodeIdLookUp};
use crate::blinded_path::utils;
use crate::io;
use crate::io::Cursor;
use crate::ln::channelmanager::PaymentId;
use crate::ln::msgs::DecodeError;
use crate::ln::{PaymentHash, onion_utils};
use crate::offers::nonce::Nonce;
use crate::onion_message::packet::ControlTlvs;
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
use crate::sign::{EntropySource, NodeSigner, Recipient};
use crate::crypto::streams::ChaChaPolyReadAdapter;
use crate::util::scid_utils;
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, Writeable, Writer};
use core::mem;
use core::ops::Deref;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct BlindedMessagePath(pub(super) BlindedPath);
impl Writeable for BlindedMessagePath {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.0.write(w)
}
}
impl Readable for BlindedMessagePath {
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
Ok(Self(BlindedPath::read(r)?))
}
}
impl BlindedMessagePath {
pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>
) -> Result<Self, ()> where ES::Target: EntropySource {
Self::new(&[], recipient_node_id, context, entropy_source, secp_ctx)
}
pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey, context: MessageContext,
entropy_source: ES, secp_ctx: &Secp256k1<T>
) -> Result<Self, ()> where ES::Target: EntropySource {
let introduction_node = IntroductionNode::NodeId(
intermediate_nodes.first().map_or(recipient_node_id, |n| n.node_id)
);
let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
Ok(Self(BlindedPath {
introduction_node,
blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
blinded_hops: blinded_hops(
secp_ctx, intermediate_nodes, recipient_node_id,
context, &blinding_secret,
).map_err(|_| ())?,
}))
}
pub fn use_compact_introduction_node(&mut self, network_graph: &ReadOnlyNetworkGraph) {
if let IntroductionNode::NodeId(pubkey) = &self.0.introduction_node {
let node_id = NodeId::from_pubkey(pubkey);
if let Some(node_info) = network_graph.node(&node_id) {
if let Some((scid, channel_info)) = node_info
.channels
.iter()
.filter_map(|scid| network_graph.channel(*scid).map(|info| (*scid, info)))
.min_by_key(|(scid, _)| scid_utils::block_from_scid(*scid))
{
let direction = if node_id == channel_info.node_one {
Direction::NodeOne
} else {
debug_assert_eq!(node_id, channel_info.node_two);
Direction::NodeTwo
};
self.0.introduction_node =
IntroductionNode::DirectedShortChannelId(direction, scid);
}
}
}
}
pub fn public_introduction_node_id<'a>(
&self, network_graph: &'a ReadOnlyNetworkGraph
) -> Option<&'a NodeId> {
self.0.public_introduction_node_id(network_graph)
}
pub fn introduction_node(&self) -> &IntroductionNode {
&self.0.introduction_node
}
pub fn blinding_point(&self) -> PublicKey {
self.0.blinding_point
}
pub fn blinded_hops(&self) -> &[BlindedHop] {
&self.0.blinded_hops
}
pub fn advance_path_by_one<NS: Deref, NL: Deref, T>(
&mut self, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
) -> Result<(), ()>
where
NS::Target: NodeSigner,
NL::Target: NodeIdLookUp,
T: secp256k1::Signing + secp256k1::Verification,
{
let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.0.blinding_point, None)?;
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
let encrypted_control_tlvs = &self.0.blinded_hops.get(0).ok_or(())?.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 { next_hop, next_blinding_override })
}) => {
let next_node_id = match next_hop {
NextMessageHop::NodeId(pubkey) => pubkey,
NextMessageHop::ShortChannelId(scid) => match node_id_lookup.next_node_id(scid) {
Some(pubkey) => pubkey,
None => return Err(()),
},
};
let mut new_blinding_point = match next_blinding_override {
Some(blinding_point) => blinding_point,
None => {
onion_utils::next_hop_pubkey(secp_ctx, self.0.blinding_point,
control_tlvs_ss.as_ref()).map_err(|_| ())?
}
};
mem::swap(&mut self.0.blinding_point, &mut new_blinding_point);
self.0.introduction_node = IntroductionNode::NodeId(next_node_id);
self.0.blinded_hops.remove(0);
Ok(())
},
_ => Err(())
}
}
pub(crate) fn introduction_node_mut(&mut self) -> &mut IntroductionNode {
&mut self.0.introduction_node
}
#[cfg(test)]
pub fn from_raw(
introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec<BlindedHop>
) -> Self {
Self(BlindedPath {
introduction_node: IntroductionNode::NodeId(introduction_node_id),
blinding_point,
blinded_hops,
})
}
#[cfg(test)]
pub fn clear_blinded_hops(&mut self) {
self.0.blinded_hops.clear()
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum NextMessageHop {
NodeId(PublicKey),
ShortChannelId(u64),
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct ForwardNode {
pub node_id: PublicKey,
pub short_channel_id: Option<u64>,
}
pub(crate) struct ForwardTlvs {
pub(crate) next_hop: NextMessageHop,
pub(crate) next_blinding_override: Option<PublicKey>,
}
pub(crate) struct ReceiveTlvs {
pub context: Option<MessageContext>
}
impl Writeable for ForwardTlvs {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
let (next_node_id, short_channel_id) = match self.next_hop {
NextMessageHop::NodeId(pubkey) => (Some(pubkey), None),
NextMessageHop::ShortChannelId(scid) => (None, Some(scid)),
};
encode_tlv_stream!(writer, {
(2, short_channel_id, option),
(4, next_node_id, option),
(8, self.next_blinding_override, option)
});
Ok(())
}
}
impl Writeable for ReceiveTlvs {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
encode_tlv_stream!(writer, {
(65537, self.context, option),
});
Ok(())
}
}
#[derive(Clone, Debug)]
pub enum MessageContext {
Offers(OffersContext),
Custom(Vec<u8>),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum OffersContext {
InvoiceRequest {
nonce: Nonce,
},
OutboundPayment {
payment_id: PaymentId,
nonce: Nonce,
hmac: Option<Hmac<Sha256>>,
},
InboundPayment {
payment_hash: PaymentHash,
},
}
impl_writeable_tlv_based_enum!(MessageContext,
{0, Offers} => (),
{1, Custom} => (),
);
impl_writeable_tlv_based_enum!(OffersContext,
(0, InvoiceRequest) => {
(0, nonce, required),
},
(1, OutboundPayment) => {
(0, payment_id, required),
(1, nonce, required),
(2, hmac, option),
},
(2, InboundPayment) => {
(0, payment_hash, required),
},
);
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey,
context: MessageContext, session_priv: &SecretKey
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
let pks = intermediate_nodes.iter().map(|node| &node.node_id)
.chain(core::iter::once(&recipient_node_id));
let tlvs = pks.clone()
.skip(1) .zip(intermediate_nodes.iter().map(|node| node.short_channel_id))
.map(|(pubkey, scid)| match scid {
Some(scid) => NextMessageHop::ShortChannelId(scid),
None => NextMessageHop::NodeId(*pubkey),
})
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ context: Some(context) })));
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
}