Move blinded message path util into message submodule
[rust-lightning] / lightning / src / blinded_path / message.rs
1 use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
2
3 use crate::blinded_path::{BlindedHop, BlindedPath};
4 use crate::blinded_path::utils;
5 use crate::io;
6 use crate::io::Cursor;
7 use crate::ln::onion_utils;
8 use crate::onion_message::ControlTlvs;
9 use crate::prelude::*;
10 use crate::sign::{NodeSigner, Recipient};
11 use crate::util::chacha20poly1305rfc::ChaChaPolyReadAdapter;
12 use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Writeable, Writer};
13
14 use core::mem;
15 use core::ops::Deref;
16
17 /// TLVs to encode in an intermediate onion message packet's hop data. When provided in a blinded
18 /// route, they are encoded into [`BlindedHop::encrypted_payload`].
19 pub(crate) struct ForwardTlvs {
20         /// The node id of the next hop in the onion message's path.
21         pub(crate) next_node_id: PublicKey,
22         /// Senders to a blinded path use this value to concatenate the route they find to the
23         /// introduction node with the blinded path.
24         pub(crate) next_blinding_override: Option<PublicKey>,
25 }
26
27 /// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
28 pub(crate) struct ReceiveTlvs {
29         /// If `path_id` is `Some`, it is used to identify the blinded path that this onion message is
30         /// sending to. This is useful for receivers to check that said blinded path is being used in
31         /// the right context.
32         pub(crate) path_id: Option<[u8; 32]>,
33 }
34
35 impl Writeable for ForwardTlvs {
36         fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
37                 // TODO: write padding
38                 encode_tlv_stream!(writer, {
39                         (4, self.next_node_id, required),
40                         (8, self.next_blinding_override, option)
41                 });
42                 Ok(())
43         }
44 }
45
46 impl Writeable for ReceiveTlvs {
47         fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
48                 // TODO: write padding
49                 encode_tlv_stream!(writer, {
50                         (6, self.path_id, option),
51                 });
52                 Ok(())
53         }
54 }
55
56 /// Construct blinded onion message hops for the given `unblinded_path`.
57 pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
58         secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], session_priv: &SecretKey
59 ) -> Result<Vec<BlindedHop>, secp256k1::Error> {
60         let mut blinded_hops = Vec::with_capacity(unblinded_path.len());
61
62         let mut prev_ss_and_blinded_node_id = None;
63         utils::construct_keys_callback(secp_ctx, unblinded_path, None, session_priv, |blinded_node_id, _, _, encrypted_payload_ss, unblinded_pk, _| {
64                 if let Some((prev_ss, prev_blinded_node_id)) = prev_ss_and_blinded_node_id {
65                         if let Some(pk) = unblinded_pk {
66                                 let payload = ForwardTlvs {
67                                         next_node_id: pk,
68                                         next_blinding_override: None,
69                                 };
70                                 blinded_hops.push(BlindedHop {
71                                         blinded_node_id: prev_blinded_node_id,
72                                         encrypted_payload: utils::encrypt_payload(payload, prev_ss),
73                                 });
74                         } else { debug_assert!(false); }
75                 }
76                 prev_ss_and_blinded_node_id = Some((encrypted_payload_ss, blinded_node_id));
77         })?;
78
79         if let Some((final_ss, final_blinded_node_id)) = prev_ss_and_blinded_node_id {
80                 let final_payload = ReceiveTlvs { path_id: None };
81                 blinded_hops.push(BlindedHop {
82                         blinded_node_id: final_blinded_node_id,
83                         encrypted_payload: utils::encrypt_payload(final_payload, final_ss),
84                 });
85         } else { debug_assert!(false) }
86
87         Ok(blinded_hops)
88 }
89
90 // Advance the blinded onion message path by one hop, so make the second hop into the new
91 // introduction node.
92 pub(crate) fn advance_path_by_one<NS: Deref, T: secp256k1::Signing + secp256k1::Verification>(
93         path: &mut BlindedPath, node_signer: &NS, secp_ctx: &Secp256k1<T>
94 ) -> Result<(), ()> where NS::Target: NodeSigner {
95         let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?;
96         let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
97         let encrypted_control_tlvs = path.blinded_hops.remove(0).encrypted_payload;
98         let mut s = Cursor::new(&encrypted_control_tlvs);
99         let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
100         match ChaChaPolyReadAdapter::read(&mut reader, rho) {
101                 Ok(ChaChaPolyReadAdapter { readable: ControlTlvs::Forward(ForwardTlvs {
102                         mut next_node_id, next_blinding_override,
103                 })}) => {
104                         let mut new_blinding_point = match next_blinding_override {
105                                 Some(blinding_point) => blinding_point,
106                                 None => {
107                                         onion_utils::next_hop_pubkey(secp_ctx, path.blinding_point,
108                                                 control_tlvs_ss.as_ref()).map_err(|_| ())?
109                                 }
110                         };
111                         mem::swap(&mut path.blinding_point, &mut new_blinding_point);
112                         mem::swap(&mut path.introduction_node_id, &mut next_node_id);
113                         Ok(())
114                 },
115                 _ => Err(())
116         }
117 }