Skip to content

Commit 16dfab0

Browse files
Sending onion messages -- internal api changes
This commit covers the internal refactors needed for sending onion messages and docs updates
1 parent 39966e6 commit 16dfab0

File tree

4 files changed

+91
-11
lines changed

4 files changed

+91
-11
lines changed

lightning/src/ln/msgs.rs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -934,27 +934,27 @@ mod fuzzy_internal_msgs {
934934
// These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
935935
// them from untrusted input):
936936
#[derive(Clone)]
937-
pub(crate) struct FinalOnionHopData {
937+
pub(crate) struct FinalOnionPayload {
938938
pub(crate) payment_secret: PaymentSecret,
939939
/// The total value, in msat, of the payment as received by the ultimate recipient.
940940
/// Message serialization may panic if this value is more than 21 million Bitcoin.
941941
pub(crate) total_msat: u64,
942942
}
943943

944-
pub(crate) enum OnionHopDataFormat {
944+
pub(crate) enum OnionPayloadFormat {
945945
Legacy { // aka Realm-0
946946
short_channel_id: u64,
947947
},
948-
NonFinalNode {
948+
Forward {
949949
short_channel_id: u64,
950950
},
951-
FinalNode {
951+
Receive {
952952
payment_data: Option<FinalOnionHopData>,
953953
keysend_preimage: Option<PaymentPreimage>,
954954
},
955955
}
956956

957-
pub struct OnionHopData {
957+
pub struct OnionPayload {
958958
pub(crate) format: OnionHopDataFormat,
959959
/// The value, in msat, of the payment after this hop's fee is deducted.
960960
/// Message serialization may panic if this value is more than 21 million Bitcoin.
@@ -963,6 +963,27 @@ mod fuzzy_internal_msgs {
963963
// 12 bytes of 0-padding for Legacy format
964964
}
965965

966+
pub(crate) enum OnionMsgPayloadFormat {
967+
Forward {
968+
/// Senders of onion messages have the option of specifying an overriding [`blinding_point`]
969+
/// for forwarding nodes along the path. If this field is absent, forwarding nodes will
970+
/// calculate the next hop's blinding point by multiplying the blinding point that they
971+
/// received by a blinding factor.
972+
///
973+
/// [`blinding_point`]: crate::ln::msgs::OnionMessage::blinding_point
974+
next_blinding_override: Option<PublicKey>,
975+
/// The node id of the next hop in the onion message's path.
976+
next_node_id: PublicKey,
977+
},
978+
Receive {
979+
custom_tlvs: Vec<CustomTlv>,
980+
}
981+
}
982+
983+
pub struct OnionMsgPayload {
984+
pub(crate) format: OnionMsgPayloadFormat,
985+
}
986+
966987
pub struct DecodedOnionErrorPacket {
967988
pub(crate) hmac: [u8; 32],
968989
pub(crate) failuremsg: Vec<u8>,
@@ -1427,6 +1448,15 @@ impl Readable for OnionHopData {
14271448
}
14281449
}
14291450

1451+
/// Writes of `OnionMsgPayload`s are parameterized by the `rho` of a `SharedSecret`, which is used
1452+
/// to encrypt the onion message's `encrypted_data` field.
1453+
impl Writeable for (OnionMsgPayload, [u8; 32]) {
1454+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1455+
// calls:
1456+
// * ChaCha20Poly1305RFC::encrypt_in_place
1457+
}
1458+
}
1459+
14301460
impl Writeable for Ping {
14311461
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
14321462
self.ponglen.write(w)?;

lightning/src/ln/onion_message.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ impl<Signer: Sign, K: Deref> OnionMessager<Signer, K>
4545
/// LDK will not make peer connections for you, so you must be connected to the first hop of
4646
/// `intermediate_nodes` for sending to work.
4747
// NOTE: sending custom TLVs, reply paths, and sending to blinded routes aren't included atm
48-
pub fn send_onion_message(&self, recipient: PublicKey, intermediate_nodes: Vec<PublicKey>) -> Result<(), APIError> {}
48+
pub fn send_onion_message(&self, recipient: PublicKey, intermediate_nodes: Vec<PublicKey>) -> Result<(), APIError> {
49+
// calls:
50+
// * onion_utils::construct_onion_message_keys
51+
// * onion_utils::build_onion_message_payloads
52+
// * onion_utils::construct_onion_message_packet
53+
}
4954
}
5055

5156
impl OnionMessageHandler for OnionMessager {

lightning/src/ln/onion_utils.rs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,31 @@ pub(super) fn gen_ammag_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
7373
Hmac::from_engine(hmac).into_inner()
7474
}
7575

76+
/// Used in the construction of keys to build the onion routing packet for payments and onion
77+
/// messages, in `construct_onion_keys_callback`.
78+
///
79+
/// `construct_onion_keys_callback` needs to be able to take a path of `RouteHop`s, as we use the
80+
/// information in the `RouteHop` in processing onion faiilures. However, for onion messages, we
81+
/// don't have a `RouteHop` and instead only a list of node ids for the path. Thus this enum allows
82+
/// `construct_onion_keys_callback` to accommodate both use cases.
83+
pub(super) enum Hop {
84+
PublicKey(&PublicKey),
85+
Routing(&RouteHop),
86+
}
87+
88+
impl Hop {
89+
/// Retrieve the `Hop`'s node id.
90+
fn pubkey(&self) -> &PublicKey {}
91+
}
92+
7693
// can only fail if an intermediary hop has an invalid public key or session_priv is invalid
7794
#[inline]
78-
pub(super) fn construct_onion_keys_callback<T: secp256k1::Signing, FType: FnMut(SharedSecret, [u8; 32], PublicKey, &RouteHop, usize)> (secp_ctx: &Secp256k1<T>, path: &Vec<RouteHop>, session_priv: &SecretKey, mut callback: FType) -> Result<(), secp256k1::Error> {
95+
fn construct_onion_keys_callback<T: secp256k1::Signing, FType: FnMut(SharedSecret, [u8; 32], PublicKey, &Hop, usize)> (secp_ctx: &Secp256k1<T>, path: &Vec<Hop>, session_priv: &SecretKey, mut callback: FType) -> Result<(), secp256k1::Error> {
7996
let mut blinded_priv = session_priv.clone();
8097
let mut blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
8198

8299
for (idx, hop) in path.iter().enumerate() {
83-
let shared_secret = SharedSecret::new(&hop.pubkey, &blinded_priv);
100+
let shared_secret = SharedSecret::new(hop.pubkey(), &blinded_priv);
84101

85102
let mut sha = Sha256::engine();
86103
sha.input(&blinded_pub.serialize()[..]);
@@ -98,11 +115,20 @@ pub(super) fn construct_onion_keys_callback<T: secp256k1::Signing, FType: FnMut(
98115
Ok(())
99116
}
100117

118+
/// Construct keys for sending an onion message along the given `path`.
119+
///
120+
/// Returns keys for encrypting the `encrypted_data` field of the onion message and keys for
121+
/// encrypting the onion message's onion routing packet.
122+
pub(super) fn construct_onion_message_keys<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, path: Vec<&PublicKey>, session_priv: &SecretKey) -> Result<(Vec<[u8; 32]>, Vec<OnionKeys>), secp256k1::Error> {
123+
// calls `construct_onion_keys_callback`
124+
}
125+
101126
// can only fail if an intermediary hop has an invalid public key or session_priv is invalid
102127
pub(super) fn construct_onion_keys<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, path: &Vec<RouteHop>, session_priv: &SecretKey) -> Result<Vec<OnionKeys>, secp256k1::Error> {
103128
let mut res = Vec::with_capacity(path.len());
104129

105-
construct_onion_keys_callback(secp_ctx, path, session_priv, |shared_secret, _blinding_factor, ephemeral_pubkey, _, _| {
130+
let hops = path.iter().map(|hop| Hop::Routing(&hop));
131+
construct_onion_keys_callback(secp_ctx, hops, session_priv, |shared_secret, _blinding_factor, ephemeral_pubkey, _, _| {
106132
let (rho, mu) = gen_rho_mu_from_shared_secret(&shared_secret[..]);
107133

108134
res.push(OnionKeys {
@@ -119,6 +145,10 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T
119145
Ok(res)
120146
}
121147

148+
/// Builds an onion message payload for each hop in the `path`, ready to be encoded in the onion
149+
/// routing packet.
150+
pub(super) fn build_onion_message_payloads(mut path: Vec<PublicKey>) -> Result<Vec<msgs::OnionMsgPayload>, APIError> {}
151+
122152
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
123153
pub(super) fn build_onion_payloads(path: &Vec<RouteHop>, total_msat: u64, payment_secret_option: &Option<PaymentSecret>, starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>) -> Result<(Vec<msgs::OnionHopData>, u64, u32), APIError> {
124154
let mut cur_value_msat = 0u64;
@@ -199,6 +229,8 @@ pub(super) fn route_size_insane(payloads: &Vec<msgs::OnionHopData>) -> bool {
199229
}
200230

201231
/// panics if route_size_insane(paylods)
232+
// NOTE: I believe since onion messages can be variable size, we'll have to remove the panic
233+
// mentioned above^
202234
pub(super) fn construct_onion_packet(payloads: Vec<msgs::OnionHopData>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> msgs::OnionPacket {
203235
let mut packet_data = [0; ONION_DATA_LEN];
204236

@@ -208,6 +240,14 @@ pub(super) fn construct_onion_packet(payloads: Vec<msgs::OnionHopData>, onion_ke
208240
construct_onion_packet_with_init_noise(payloads, onion_keys, packet_data, associated_data)
209241
}
210242

243+
/// Constructs the onion routing packet for onion messages.
244+
// NOTE: this could prob be DRY'd with `construct_onion_packet`, but it'd lead to a large-ish diff,
245+
// and it's a small method.
246+
pub(super) fn construct_onion_message_packet(payloads: Vec<msgs::OnionMsgPayload>, encrypted_data_keys: Vec<[u8; 32]>, onion_packet_keys: Vec<OnionKeys>, prng_seed: [u8; 32]) -> msgs::OnionPacket {
247+
// calls:
248+
// * construct_onion_packet_with_init_noise
249+
}
250+
211251
#[cfg(test)]
212252
// Used in testing to write bogus OnionHopDatas, which is otherwise not representable in
213253
// msgs::OnionHopData.
@@ -221,7 +261,8 @@ pub(super) fn construct_onion_packet_bogus_hopdata<HD: Writeable>(payloads: Vec<
221261
}
222262

223263
/// panics if route_size_insane(paylods)
224-
fn construct_onion_packet_with_init_noise<HD: Writeable>(mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: [u8; ONION_DATA_LEN], associated_data: &PaymentHash) -> msgs::OnionPacket {
264+
fn construct_onion_packet_with_init_noise<HD: Writeable>(mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: [u8; ONION_DATA_LEN], associated_data: Option<&PaymentHash>) -> msgs::OnionPacket {
265+
// calls `msgs::OnionMsgPayload::write`
225266
let filler = {
226267
const ONION_HOP_DATA_LEN: usize = 65; // We may decrease this eventually after TLV is common
227268
let mut res = Vec::with_capacity(ONION_HOP_DATA_LEN * (payloads.len() - 1));
@@ -507,7 +548,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing, L: Deref>(secp_ctx: &
507548
}
508549

509550
/// Data decrypted from the onion payload.
510-
pub(crate) enum Hop {
551+
pub(crate) enum HopPayload {
511552
/// This onion payload was for us, not for forwarding to a next-hop. Contains information for
512553
/// verifying the incoming payment.
513554
Receive(msgs::OnionHopData),

lightning/src/util/chacha20poly1305rfc.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ mod real_chachapoly {
7070
self.mac.raw_result(out_tag);
7171
}
7272

73+
pub fn encrypt_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {}
74+
75+
fn encrypt_inner(&mut self, input_output: &mut [u8], output: Option<&mut [u8]>, out_tag: &mut [u8]) {}
76+
7377
pub fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
7478
assert!(input.len() == output.len());
7579
assert!(self.finished == false);

0 commit comments

Comments
 (0)