Support sending onion messages
[rust-lightning] / lightning / src / onion_message / utils.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! Onion message utility methods live here.
11
12 use bitcoin::hashes::{Hash, HashEngine};
13 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
14 use bitcoin::hashes::sha256::Hash as Sha256;
15 use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
16 use bitcoin::secp256k1::ecdh::SharedSecret;
17
18 use ln::onion_utils;
19 use super::blinded_route::BlindedRoute;
20 use super::messenger::Destination;
21
22 use prelude::*;
23
24 // TODO: DRY with onion_utils::construct_onion_keys_callback
25 #[inline]
26 pub(super) fn construct_keys_callback<T: secp256k1::Signing + secp256k1::Verification,
27         FType: FnMut(PublicKey, SharedSecret, PublicKey, [u8; 32], Option<PublicKey>, Option<Vec<u8>>)>(
28         secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Option<Destination>,
29         session_priv: &SecretKey, mut callback: FType
30 ) -> Result<(), secp256k1::Error> {
31         let mut msg_blinding_point_priv = session_priv.clone();
32         let mut msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
33         let mut onion_packet_pubkey_priv = msg_blinding_point_priv.clone();
34         let mut onion_packet_pubkey = msg_blinding_point.clone();
35
36         macro_rules! build_keys {
37                 ($pk: expr, $blinded: expr, $encrypted_payload: expr) => {{
38                         let encrypted_data_ss = SharedSecret::new(&$pk, &msg_blinding_point_priv);
39
40                         let blinded_hop_pk = if $blinded { $pk } else {
41                                 let hop_pk_blinding_factor = {
42                                         let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
43                                         hmac.input(encrypted_data_ss.as_ref());
44                                         Hmac::from_engine(hmac).into_inner()
45                                 };
46                                 let mut unblinded_pk = $pk;
47                                 unblinded_pk.mul_assign(secp_ctx, &hop_pk_blinding_factor)?;
48                                 unblinded_pk
49                         };
50                         let onion_packet_ss = SharedSecret::new(&blinded_hop_pk, &onion_packet_pubkey_priv);
51
52                         let rho = onion_utils::gen_rho_from_shared_secret(encrypted_data_ss.as_ref());
53                         let unblinded_pk_opt = if $blinded { None } else { Some($pk) };
54                         callback(blinded_hop_pk, onion_packet_ss, onion_packet_pubkey, rho, unblinded_pk_opt, $encrypted_payload);
55                         (encrypted_data_ss, onion_packet_ss)
56                 }}
57         }
58
59         macro_rules! build_keys_in_loop {
60                 ($pk: expr, $blinded: expr, $encrypted_payload: expr) => {
61                         let (encrypted_data_ss, onion_packet_ss) = build_keys!($pk, $blinded, $encrypted_payload);
62
63                         let msg_blinding_point_blinding_factor = {
64                                 let mut sha = Sha256::engine();
65                                 sha.input(&msg_blinding_point.serialize()[..]);
66                                 sha.input(encrypted_data_ss.as_ref());
67                                 Sha256::from_engine(sha).into_inner()
68                         };
69
70                         msg_blinding_point_priv.mul_assign(&msg_blinding_point_blinding_factor)?;
71                         msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
72
73                         let onion_packet_pubkey_blinding_factor = {
74                                 let mut sha = Sha256::engine();
75                                 sha.input(&onion_packet_pubkey.serialize()[..]);
76                                 sha.input(onion_packet_ss.as_ref());
77                                 Sha256::from_engine(sha).into_inner()
78                         };
79                         onion_packet_pubkey_priv.mul_assign(&onion_packet_pubkey_blinding_factor)?;
80                         onion_packet_pubkey = PublicKey::from_secret_key(secp_ctx, &onion_packet_pubkey_priv);
81                 };
82         }
83
84         for pk in unblinded_path {
85                 build_keys_in_loop!(*pk, false, None);
86         }
87         if let Some(dest) = destination {
88                 match dest {
89                         Destination::Node(pk) => {
90                                 build_keys!(pk, false, None);
91                         },
92                         Destination::BlindedRoute(BlindedRoute { blinded_hops, .. }) => {
93                                 for hop in blinded_hops {
94                                         build_keys_in_loop!(hop.blinded_node_id, true, Some(hop.encrypted_payload));
95                                 }
96                         },
97                 }
98         }
99         Ok(())
100 }