Skip to content

Commit 28c9b56

Browse files
authored
Merge pull request #1503 from valentinewallace/2022-05-onion-msgs
Onion messages v1
2 parents 4ebc8e5 + 17ec697 commit 28c9b56

17 files changed

+1325
-50
lines changed

fuzz/src/chanmon_consistency.rs

+9
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ use utils::test_logger::{self, Output};
5454
use utils::test_persister::TestPersister;
5555

5656
use bitcoin::secp256k1::{PublicKey,SecretKey};
57+
use bitcoin::secp256k1::ecdh::SharedSecret;
5758
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
5859
use bitcoin::secp256k1::Secp256k1;
5960

@@ -165,6 +166,14 @@ impl KeysInterface for KeyProvider {
165166
Ok(SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, self.node_id]).unwrap())
166167
}
167168

169+
fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
170+
let mut node_secret = self.get_node_secret(recipient)?;
171+
if let Some(tweak) = tweak {
172+
node_secret.mul_assign(tweak).map_err(|_| ())?;
173+
}
174+
Ok(SharedSecret::new(other_key, &node_secret))
175+
}
176+
168177
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
169178
KeyMaterial([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, self.node_id])
170179
}

fuzz/src/full_stack.rs

+9
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use utils::test_logger;
5151
use utils::test_persister::TestPersister;
5252

5353
use bitcoin::secp256k1::{PublicKey,SecretKey};
54+
use bitcoin::secp256k1::ecdh::SharedSecret;
5455
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
5556
use bitcoin::secp256k1::Secp256k1;
5657

@@ -269,6 +270,14 @@ impl KeysInterface for KeyProvider {
269270
Ok(self.node_secret.clone())
270271
}
271272

273+
fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
274+
let mut node_secret = self.get_node_secret(recipient)?;
275+
if let Some(tweak) = tweak {
276+
node_secret.mul_assign(tweak).map_err(|_| ())?;
277+
}
278+
Ok(SharedSecret::new(other_key, &node_secret))
279+
}
280+
272281
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
273282
self.inbound_payment_key.clone()
274283
}

lightning/src/chain/keysinterface.rs

+23
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use bitcoin::hash_types::WPubkeyHash;
2727

2828
use bitcoin::secp256k1::{SecretKey, PublicKey};
2929
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature, Signing};
30+
use bitcoin::secp256k1::ecdh::SharedSecret;
3031
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
3132
use bitcoin::{secp256k1, Witness};
3233

@@ -404,6 +405,12 @@ pub trait KeysInterface {
404405
/// This method must return the same value each time it is called with a given `Recipient`
405406
/// parameter.
406407
fn get_node_secret(&self, recipient: Recipient) -> Result<SecretKey, ()>;
408+
/// Gets the ECDH shared secret of our [`node secret`] and `other_key`, multiplying by `tweak` if
409+
/// one is provided. Note that this tweak can be applied to `other_key` instead of our node
410+
/// secret, though this is less efficient.
411+
///
412+
/// [`node secret`]: Self::get_node_secret
413+
fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()>;
407414
/// Get a script pubkey which we send funds to when claiming on-chain contestable outputs.
408415
///
409416
/// This method should return a different value each time it is called, to avoid linking
@@ -1133,6 +1140,14 @@ impl KeysInterface for KeysManager {
11331140
}
11341141
}
11351142

1143+
fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
1144+
let mut node_secret = self.get_node_secret(recipient)?;
1145+
if let Some(tweak) = tweak {
1146+
node_secret.mul_assign(tweak).map_err(|_| ())?;
1147+
}
1148+
Ok(SharedSecret::new(other_key, &node_secret))
1149+
}
1150+
11361151
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
11371152
self.inbound_payment_key.clone()
11381153
}
@@ -1217,6 +1232,14 @@ impl KeysInterface for PhantomKeysManager {
12171232
}
12181233
}
12191234

1235+
fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
1236+
let mut node_secret = self.get_node_secret(recipient)?;
1237+
if let Some(tweak) = tweak {
1238+
node_secret.mul_assign(tweak).map_err(|_| ())?;
1239+
}
1240+
Ok(SharedSecret::new(other_key, &node_secret))
1241+
}
1242+
12201243
fn get_inbound_payment_key_material(&self) -> KeyMaterial {
12211244
self.inbound_payment_key.clone()
12221245
}

lightning/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! figure out how best to make networking happen/timers fire/things get written to disk/keys get
1818
//! generated/etc. This makes it a good candidate for tight integration into an existing wallet
1919
//! instead of having a rather-separate lightning appendage to a wallet.
20-
//!
20+
//!
2121
//! `default` features are:
2222
//!
2323
//! * `std` - enables functionalities which require `std`, including `std::io` trait implementations and things which utilize time
@@ -76,6 +76,8 @@ pub mod util;
7676
pub mod chain;
7777
pub mod ln;
7878
pub mod routing;
79+
#[allow(unused)]
80+
mod onion_message; // To be exposed after sending/receiving OMs is supported in PeerManager.
7981

8082
#[cfg(feature = "std")]
8183
/// Re-export of either `core2::io` or `std::io`, depending on the `std` feature flag.

lightning/src/ln/channel.rs

+2
Original file line numberDiff line numberDiff line change
@@ -6589,6 +6589,7 @@ mod tests {
65896589
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
65906590
use bitcoin::secp256k1::ffi::Signature as FFISignature;
65916591
use bitcoin::secp256k1::{SecretKey,PublicKey};
6592+
use bitcoin::secp256k1::ecdh::SharedSecret;
65926593
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
65936594
use bitcoin::hashes::sha256::Hash as Sha256;
65946595
use bitcoin::hashes::Hash;
@@ -6629,6 +6630,7 @@ mod tests {
66296630
type Signer = InMemorySigner;
66306631

66316632
fn get_node_secret(&self, _recipient: Recipient) -> Result<SecretKey, ()> { panic!(); }
6633+
fn ecdh(&self, _recipient: Recipient, _other_key: &PublicKey, _tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> { panic!(); }
66326634
fn get_inbound_payment_key_material(&self) -> KeyMaterial { panic!(); }
66336635
fn get_destination_script(&self) -> Script {
66346636
let secp_ctx = Secp256k1::signing_only();

lightning/src/ln/channelmanager.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2192,7 +2192,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
21922192
}
21932193
}
21942194

2195-
let next_hop = match onion_utils::decode_next_hop(shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, msg.payment_hash) {
2195+
let next_hop = match onion_utils::decode_next_payment_hop(shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, msg.payment_hash) {
21962196
Ok(res) => res,
21972197
Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
21982198
return_malformed_err!(err_msg, err_code);
@@ -3153,7 +3153,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
31533153
let phantom_secret_res = self.keys_manager.get_node_secret(Recipient::PhantomNode);
31543154
if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id) {
31553155
let phantom_shared_secret = SharedSecret::new(&onion_packet.public_key.unwrap(), &phantom_secret_res.unwrap()).secret_bytes();
3156-
let next_hop = match onion_utils::decode_next_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
3156+
let next_hop = match onion_utils::decode_next_payment_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
31573157
Ok(res) => res,
31583158
Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
31593159
let sha256_of_onion = Sha256::hash(&onion_packet.hop_data).into_inner();

lightning/src/ln/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub mod channel;
4343
#[cfg(not(fuzzing))]
4444
pub(crate) mod channel;
4545

46-
mod onion_utils;
46+
pub(crate) mod onion_utils;
4747
pub mod wire;
4848

4949
// Older rustc (which we support) refuses to let us call the get_payment_preimage_hash!() macro

lightning/src/ln/msgs.rs

+54-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use bitcoin::blockdata::script::Script;
3131
use bitcoin::hash_types::{Txid, BlockHash};
3232

3333
use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
34+
use ln::onion_utils;
35+
use onion_message;
3436

3537
use prelude::*;
3638
use core::fmt;
@@ -40,7 +42,7 @@ use io_extras::read_to_end;
4042

4143
use util::events::MessageSendEventsProvider;
4244
use util::logger;
43-
use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt, Hostname};
45+
use util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt, Hostname};
4446

4547
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
4648

@@ -304,6 +306,14 @@ pub struct UpdateAddHTLC {
304306
pub(crate) onion_routing_packet: OnionPacket,
305307
}
306308

309+
/// An onion message to be sent or received from a peer
310+
#[derive(Clone, Debug, PartialEq)]
311+
pub struct OnionMessage {
312+
/// Used in decrypting the onion packet's payload.
313+
pub blinding_point: PublicKey,
314+
pub(crate) onion_routing_packet: onion_message::Packet,
315+
}
316+
307317
/// An update_fulfill_htlc message to be sent or received from a peer
308318
#[derive(Clone, Debug, PartialEq)]
309319
pub struct UpdateFulfillHTLC {
@@ -993,6 +1003,18 @@ pub(crate) struct OnionPacket {
9931003
pub(crate) hmac: [u8; 32],
9941004
}
9951005

1006+
impl onion_utils::Packet for OnionPacket {
1007+
type Data = onion_utils::FixedSizeOnionPacket;
1008+
fn new(pubkey: PublicKey, hop_data: onion_utils::FixedSizeOnionPacket, hmac: [u8; 32]) -> Self {
1009+
Self {
1010+
version: 0,
1011+
public_key: Ok(pubkey),
1012+
hop_data: hop_data.0,
1013+
hmac,
1014+
}
1015+
}
1016+
}
1017+
9961018
impl PartialEq for OnionPacket {
9971019
fn eq(&self, other: &OnionPacket) -> bool {
9981020
for (i, j) in self.hop_data.iter().zip(other.hop_data.iter()) {
@@ -1327,6 +1349,29 @@ impl_writeable_msg!(UpdateAddHTLC, {
13271349
onion_routing_packet
13281350
}, {});
13291351

1352+
impl Readable for OnionMessage {
1353+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1354+
let blinding_point: PublicKey = Readable::read(r)?;
1355+
let len: u16 = Readable::read(r)?;
1356+
let mut packet_reader = FixedLengthReader::new(r, len as u64);
1357+
let onion_routing_packet: onion_message::Packet = <onion_message::Packet as LengthReadable>::read(&mut packet_reader)?;
1358+
Ok(Self {
1359+
blinding_point,
1360+
onion_routing_packet,
1361+
})
1362+
}
1363+
}
1364+
1365+
impl Writeable for OnionMessage {
1366+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1367+
self.blinding_point.write(w)?;
1368+
let onion_packet_len = self.onion_routing_packet.serialized_length();
1369+
(onion_packet_len as u16).write(w)?;
1370+
self.onion_routing_packet.write(w)?;
1371+
Ok(())
1372+
}
1373+
}
1374+
13301375
impl Writeable for FinalOnionHopData {
13311376
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
13321377
self.payment_secret.0.write(w)?;
@@ -1372,6 +1417,14 @@ impl Writeable for OnionHopData {
13721417
}
13731418
}
13741419

1420+
// ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
1421+
// onion message packets.
1422+
impl ReadableArgs<()> for OnionHopData {
1423+
fn read<R: Read>(r: &mut R, _arg: ()) -> Result<Self, DecodeError> {
1424+
<Self as Readable>::read(r)
1425+
}
1426+
}
1427+
13751428
impl Readable for OnionHopData {
13761429
fn read<R: Read>(mut r: &mut R) -> Result<Self, DecodeError> {
13771430
use bitcoin::consensus::encode::{Decodable, Error, VarInt};

0 commit comments

Comments
 (0)