Skip to content

Commit

Permalink
Merge pull request #1503 from valentinewallace/2022-05-onion-msgs
Browse files Browse the repository at this point in the history
Onion messages v1
  • Loading branch information
TheBlueMatt authored Aug 3, 2022
2 parents 4ebc8e5 + 17ec697 commit 28c9b56
Show file tree
Hide file tree
Showing 17 changed files with 1,325 additions and 50 deletions.
9 changes: 9 additions & 0 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ use utils::test_logger::{self, Output};
use utils::test_persister::TestPersister;

use bitcoin::secp256k1::{PublicKey,SecretKey};
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
use bitcoin::secp256k1::Secp256k1;

Expand Down Expand Up @@ -165,6 +166,14 @@ impl KeysInterface for KeyProvider {
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())
}

fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
let mut node_secret = self.get_node_secret(recipient)?;
if let Some(tweak) = tweak {
node_secret.mul_assign(tweak).map_err(|_| ())?;
}
Ok(SharedSecret::new(other_key, &node_secret))
}

fn get_inbound_payment_key_material(&self) -> KeyMaterial {
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])
}
Expand Down
9 changes: 9 additions & 0 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use utils::test_logger;
use utils::test_persister::TestPersister;

use bitcoin::secp256k1::{PublicKey,SecretKey};
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
use bitcoin::secp256k1::Secp256k1;

Expand Down Expand Up @@ -269,6 +270,14 @@ impl KeysInterface for KeyProvider {
Ok(self.node_secret.clone())
}

fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
let mut node_secret = self.get_node_secret(recipient)?;
if let Some(tweak) = tweak {
node_secret.mul_assign(tweak).map_err(|_| ())?;
}
Ok(SharedSecret::new(other_key, &node_secret))
}

fn get_inbound_payment_key_material(&self) -> KeyMaterial {
self.inbound_payment_key.clone()
}
Expand Down
23 changes: 23 additions & 0 deletions lightning/src/chain/keysinterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use bitcoin::hash_types::WPubkeyHash;

use bitcoin::secp256k1::{SecretKey, PublicKey};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature, Signing};
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
use bitcoin::{secp256k1, Witness};

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

fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
let mut node_secret = self.get_node_secret(recipient)?;
if let Some(tweak) = tweak {
node_secret.mul_assign(tweak).map_err(|_| ())?;
}
Ok(SharedSecret::new(other_key, &node_secret))
}

fn get_inbound_payment_key_material(&self) -> KeyMaterial {
self.inbound_payment_key.clone()
}
Expand Down Expand Up @@ -1217,6 +1232,14 @@ impl KeysInterface for PhantomKeysManager {
}
}

fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> {
let mut node_secret = self.get_node_secret(recipient)?;
if let Some(tweak) = tweak {
node_secret.mul_assign(tweak).map_err(|_| ())?;
}
Ok(SharedSecret::new(other_key, &node_secret))
}

fn get_inbound_payment_key_material(&self) -> KeyMaterial {
self.inbound_payment_key.clone()
}
Expand Down
4 changes: 3 additions & 1 deletion lightning/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! figure out how best to make networking happen/timers fire/things get written to disk/keys get
//! generated/etc. This makes it a good candidate for tight integration into an existing wallet
//! instead of having a rather-separate lightning appendage to a wallet.
//!
//!
//! `default` features are:
//!
//! * `std` - enables functionalities which require `std`, including `std::io` trait implementations and things which utilize time
Expand Down Expand Up @@ -76,6 +76,8 @@ pub mod util;
pub mod chain;
pub mod ln;
pub mod routing;
#[allow(unused)]
mod onion_message; // To be exposed after sending/receiving OMs is supported in PeerManager.

#[cfg(feature = "std")]
/// Re-export of either `core2::io` or `std::io`, depending on the `std` feature flag.
Expand Down
2 changes: 2 additions & 0 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6589,6 +6589,7 @@ mod tests {
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1::ffi::Signature as FFISignature;
use bitcoin::secp256k1::{SecretKey,PublicKey};
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
Expand Down Expand Up @@ -6629,6 +6630,7 @@ mod tests {
type Signer = InMemorySigner;

fn get_node_secret(&self, _recipient: Recipient) -> Result<SecretKey, ()> { panic!(); }
fn ecdh(&self, _recipient: Recipient, _other_key: &PublicKey, _tweak: Option<&[u8; 32]>) -> Result<SharedSecret, ()> { panic!(); }
fn get_inbound_payment_key_material(&self) -> KeyMaterial { panic!(); }
fn get_destination_script(&self) -> Script {
let secp_ctx = Secp256k1::signing_only();
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2192,7 +2192,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
}
}

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) {
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) {
Ok(res) => res,
Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
return_malformed_err!(err_msg, err_code);
Expand Down Expand Up @@ -3153,7 +3153,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
let phantom_secret_res = self.keys_manager.get_node_secret(Recipient::PhantomNode);
if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id) {
let phantom_shared_secret = SharedSecret::new(&onion_packet.public_key.unwrap(), &phantom_secret_res.unwrap()).secret_bytes();
let next_hop = match onion_utils::decode_next_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
let next_hop = match onion_utils::decode_next_payment_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
Ok(res) => res,
Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
let sha256_of_onion = Sha256::hash(&onion_packet.hop_data).into_inner();
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub mod channel;
#[cfg(not(fuzzing))]
pub(crate) mod channel;

mod onion_utils;
pub(crate) mod onion_utils;
pub mod wire;

// Older rustc (which we support) refuses to let us call the get_payment_preimage_hash!() macro
Expand Down
55 changes: 54 additions & 1 deletion lightning/src/ln/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ use bitcoin::blockdata::script::Script;
use bitcoin::hash_types::{Txid, BlockHash};

use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
use ln::onion_utils;
use onion_message;

use prelude::*;
use core::fmt;
Expand All @@ -40,7 +42,7 @@ use io_extras::read_to_end;

use util::events::MessageSendEventsProvider;
use util::logger;
use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt, Hostname};
use util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt, Hostname};

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

Expand Down Expand Up @@ -304,6 +306,14 @@ pub struct UpdateAddHTLC {
pub(crate) onion_routing_packet: OnionPacket,
}

/// An onion message to be sent or received from a peer
#[derive(Clone, Debug, PartialEq)]
pub struct OnionMessage {
/// Used in decrypting the onion packet's payload.
pub blinding_point: PublicKey,
pub(crate) onion_routing_packet: onion_message::Packet,
}

/// An update_fulfill_htlc message to be sent or received from a peer
#[derive(Clone, Debug, PartialEq)]
pub struct UpdateFulfillHTLC {
Expand Down Expand Up @@ -993,6 +1003,18 @@ pub(crate) struct OnionPacket {
pub(crate) hmac: [u8; 32],
}

impl onion_utils::Packet for OnionPacket {
type Data = onion_utils::FixedSizeOnionPacket;
fn new(pubkey: PublicKey, hop_data: onion_utils::FixedSizeOnionPacket, hmac: [u8; 32]) -> Self {
Self {
version: 0,
public_key: Ok(pubkey),
hop_data: hop_data.0,
hmac,
}
}
}

impl PartialEq for OnionPacket {
fn eq(&self, other: &OnionPacket) -> bool {
for (i, j) in self.hop_data.iter().zip(other.hop_data.iter()) {
Expand Down Expand Up @@ -1327,6 +1349,29 @@ impl_writeable_msg!(UpdateAddHTLC, {
onion_routing_packet
}, {});

impl Readable for OnionMessage {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let blinding_point: PublicKey = Readable::read(r)?;
let len: u16 = Readable::read(r)?;
let mut packet_reader = FixedLengthReader::new(r, len as u64);
let onion_routing_packet: onion_message::Packet = <onion_message::Packet as LengthReadable>::read(&mut packet_reader)?;
Ok(Self {
blinding_point,
onion_routing_packet,
})
}
}

impl Writeable for OnionMessage {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.blinding_point.write(w)?;
let onion_packet_len = self.onion_routing_packet.serialized_length();
(onion_packet_len as u16).write(w)?;
self.onion_routing_packet.write(w)?;
Ok(())
}
}

impl Writeable for FinalOnionHopData {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.payment_secret.0.write(w)?;
Expand Down Expand Up @@ -1372,6 +1417,14 @@ impl Writeable for OnionHopData {
}
}

// ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
// onion message packets.
impl ReadableArgs<()> for OnionHopData {
fn read<R: Read>(r: &mut R, _arg: ()) -> Result<Self, DecodeError> {
<Self as Readable>::read(r)
}
}

impl Readable for OnionHopData {
fn read<R: Read>(mut r: &mut R) -> Result<Self, DecodeError> {
use bitcoin::consensus::encode::{Decodable, Error, VarInt};
Expand Down
Loading

0 comments on commit 28c9b56

Please sign in to comment.