1 // This file is Copyright its original authors, visible in version control
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
10 //! Onion message utility methods live here.
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;
22 // TODO: DRY with onion_utils::construct_onion_keys_callback
24 pub(super) fn construct_keys_callback<T: secp256k1::Signing + secp256k1::Verification,
25 FType: FnMut(PublicKey, SharedSecret, PublicKey, [u8; 32], Option<PublicKey>)>(
26 secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey],
27 session_priv: &SecretKey, mut callback: FType
28 ) -> Result<(), secp256k1::Error> {
29 let mut msg_blinding_point_priv = session_priv.clone();
30 let mut msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
31 let mut onion_packet_pubkey_priv = msg_blinding_point_priv.clone();
32 let mut onion_packet_pubkey = msg_blinding_point.clone();
34 macro_rules! build_keys {
35 ($pk: expr, $blinded: expr) => {
36 let encrypted_data_ss = SharedSecret::new(&$pk, &msg_blinding_point_priv);
38 let blinded_hop_pk = if $blinded { $pk } else {
39 let hop_pk_blinding_factor = {
40 let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
41 hmac.input(encrypted_data_ss.as_ref());
42 Hmac::from_engine(hmac).into_inner()
44 let mut unblinded_pk = $pk;
45 unblinded_pk.mul_assign(secp_ctx, &hop_pk_blinding_factor)?;
48 let onion_packet_ss = SharedSecret::new(&blinded_hop_pk, &onion_packet_pubkey_priv);
50 let rho = onion_utils::gen_rho_from_shared_secret(encrypted_data_ss.as_ref());
51 let unblinded_pk_opt = if $blinded { None } else { Some($pk) };
52 callback(blinded_hop_pk, onion_packet_ss, onion_packet_pubkey, rho, unblinded_pk_opt);
54 let msg_blinding_point_blinding_factor = {
55 let mut sha = Sha256::engine();
56 sha.input(&msg_blinding_point.serialize()[..]);
57 sha.input(encrypted_data_ss.as_ref());
58 Sha256::from_engine(sha).into_inner()
61 msg_blinding_point_priv.mul_assign(&msg_blinding_point_blinding_factor)?;
62 msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
64 let onion_packet_pubkey_blinding_factor = {
65 let mut sha = Sha256::engine();
66 sha.input(&onion_packet_pubkey.serialize()[..]);
67 sha.input(onion_packet_ss.as_ref());
68 Sha256::from_engine(sha).into_inner()
70 onion_packet_pubkey_priv.mul_assign(&onion_packet_pubkey_blinding_factor)?;
71 onion_packet_pubkey = PublicKey::from_secret_key(secp_ctx, &onion_packet_pubkey_priv);
75 for pk in unblinded_path {
76 build_keys!(*pk, false);