Skip to content

Commit 969085b

Browse files
committed
Avoid re-allocating to encrypt gossip messages when forwarding
When we forward gossip messages, we store them in a separate buffer before we encrypt them (and commit to the order in which they'll appear on the wire). Rather than storing that buffer encoded with no headroom, requiring re-allocating to add the message length and two MAC blocks, we here add the headroom prior to pushing it into the gossip buffer, avoiding an allocation.
1 parent 0503df8 commit 969085b

File tree

3 files changed

+53
-45
lines changed

3 files changed

+53
-45
lines changed

fuzz/src/peer_crypt.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// You may not use this file except in accordance with one or both of these
88
// licenses.
99

10-
use lightning::ln::peer_channel_encryptor::PeerChannelEncryptor;
10+
use lightning::ln::peer_channel_encryptor::{PeerChannelEncryptor, MessageBuf};
1111
use lightning::util::test_utils::TestNodeSigner;
1212

1313
use bitcoin::secp256k1::{Secp256k1, PublicKey, SecretKey};
@@ -77,7 +77,7 @@ pub fn do_test(data: &[u8]) {
7777
let mut buf = [0; 65536 + 16];
7878
loop {
7979
if get_slice!(1)[0] == 0 {
80-
crypter.encrypt_buffer(get_slice!(slice_to_be16(get_slice!(2))));
80+
crypter.encrypt_buffer(MessageBuf::from_encoded(&get_slice!(slice_to_be16(get_slice!(2)))));
8181
} else {
8282
let len = match crypter.decrypt_length_header(get_slice!(16+2)) {
8383
Ok(len) => len,

lightning/src/ln/peer_channel_encryptor.rs

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -427,16 +427,20 @@ impl PeerChannelEncryptor {
427427
Ok(self.their_node_id.unwrap().clone())
428428
}
429429

430-
/// Encrypts the given pre-serialized message, returning the encrypted version.
431-
/// panics if msg.len() > 65535 or Noise handshake has not finished.
432-
pub fn encrypt_buffer(&mut self, msg: &[u8]) -> Vec<u8> {
433-
if msg.len() > LN_MAX_MSG_LEN {
430+
/// Builds sendable bytes for a message.
431+
///
432+
/// `msgbuf` must begin with 16 + 2 dummy/0 bytes, which will be filled with the encrypted
433+
/// message length and its MAC. It should then be followed by the message bytes themselves
434+
/// (including the two byte message type).
435+
///
436+
/// For effeciency, the [`Vec::capacity`] should be at least 16 bytes larger than the
437+
/// [`Vec::len`], to avoid reallocating for the message MAC, which will be appended to the vec.
438+
fn encrypt_message_with_header_0s(&mut self, msgbuf: &mut Vec<u8>) {
439+
let msg_len = msgbuf.len() - 16 - 2;
440+
if msg_len > LN_MAX_MSG_LEN {
434441
panic!("Attempted to encrypt message longer than 65535 bytes!");
435442
}
436443

437-
let mut res = Vec::with_capacity(msg.len() + 16*2 + 2);
438-
res.resize(msg.len() + 16*2 + 2, 0);
439-
440444
match self.noise_state {
441445
NoiseState::Finished { ref mut sk, ref mut sn, ref mut sck, rk: _, rn: _, rck: _ } => {
442446
if *sn >= 1000 {
@@ -446,16 +450,21 @@ impl PeerChannelEncryptor {
446450
*sn = 0;
447451
}
448452

449-
Self::encrypt_with_ad(&mut res[0..16+2], *sn, sk, &[0; 0], &(msg.len() as u16).to_be_bytes());
453+
Self::encrypt_with_ad(&mut msgbuf[0..16+2], *sn, sk, &[0; 0], &(msg_len as u16).to_be_bytes());
450454
*sn += 1;
451455

452-
Self::encrypt_with_ad(&mut res[16+2..], *sn, sk, &[0; 0], msg);
456+
Self::encrypt_in_place_with_ad(msgbuf, 16+2, *sn, sk, &[0; 0]);
453457
*sn += 1;
454458
},
455459
_ => panic!("Tried to encrypt a message prior to noise handshake completion"),
456460
}
461+
}
457462

458-
res
463+
/// Encrypts the given pre-serialized message, returning the encrypted version.
464+
/// panics if msg.len() > 65535 or Noise handshake has not finished.
465+
pub fn encrypt_buffer(&mut self, mut msg: MessageBuf) -> Vec<u8> {
466+
self.encrypt_message_with_header_0s(&mut msg.0);
467+
msg.0
459468
}
460469

461470
/// Encrypts the given message, returning the encrypted version.
@@ -468,29 +477,7 @@ impl PeerChannelEncryptor {
468477
res.0.resize(16 + 2, 0);
469478
wire::write(message, &mut res).expect("In-memory messages must never fail to serialize");
470479

471-
let msg_len = res.0.len() - 16 - 2;
472-
if msg_len > LN_MAX_MSG_LEN {
473-
panic!("Attempted to encrypt message longer than 65535 bytes!");
474-
}
475-
476-
match self.noise_state {
477-
NoiseState::Finished { ref mut sk, ref mut sn, ref mut sck, rk: _, rn: _, rck: _ } => {
478-
if *sn >= 1000 {
479-
let (new_sck, new_sk) = hkdf_extract_expand_twice(sck, sk);
480-
*sck = new_sck;
481-
*sk = new_sk;
482-
*sn = 0;
483-
}
484-
485-
Self::encrypt_with_ad(&mut res.0[0..16+2], *sn, sk, &[0; 0], &(msg_len as u16).to_be_bytes());
486-
*sn += 1;
487-
488-
Self::encrypt_in_place_with_ad(&mut res.0, 16+2, *sn, sk, &[0; 0]);
489-
*sn += 1;
490-
},
491-
_ => panic!("Tried to encrypt a message prior to noise handshake completion"),
492-
}
493-
480+
self.encrypt_message_with_header_0s(&mut res.0);
494481
res.0
495482
}
496483

@@ -557,9 +544,30 @@ impl PeerChannelEncryptor {
557544
}
558545
}
559546

547+
/// A buffer which stores an encoded message (including the two message-type bytes) with some
548+
/// padding to allow for future encryption/MACing.
549+
pub struct MessageBuf(Vec<u8>);
550+
impl MessageBuf {
551+
/// Creates a new buffer from an encoded message (i.e. the two message-type bytes followed by
552+
/// the message contents).
553+
///
554+
/// Panics if the message is longer than 2^16.
555+
pub fn from_encoded(encoded_msg: &[u8]) -> Self {
556+
if encoded_msg.len() > LN_MAX_MSG_LEN {
557+
panic!("Attempted to encrypt message longer than 65535 bytes!");
558+
}
559+
// In addition to the message (continaing the two message type bytes), we also have to add
560+
// the message length header (and its MAC) and the message MAC.
561+
let mut res = Vec::with_capacity(encoded_msg.len() + 16*2 + 2);
562+
res.resize(encoded_msg.len() + 16 + 2, 0);
563+
res[16 + 2..].copy_from_slice(&encoded_msg);
564+
Self(res)
565+
}
566+
}
567+
560568
#[cfg(test)]
561569
mod tests {
562-
use super::LN_MAX_MSG_LEN;
570+
use super::{MessageBuf, LN_MAX_MSG_LEN};
563571

564572
use bitcoin::secp256k1::{PublicKey, SecretKey};
565573
use bitcoin::secp256k1::Secp256k1;
@@ -775,7 +783,7 @@ mod tests {
775783

776784
for i in 0..1005 {
777785
let msg = [0x68, 0x65, 0x6c, 0x6c, 0x6f];
778-
let mut res = outbound_peer.encrypt_buffer(&msg);
786+
let mut res = outbound_peer.encrypt_buffer(MessageBuf::from_encoded(&msg));
779787
assert_eq!(res.len(), 5 + 2*16 + 2);
780788

781789
let len_header = res[0..2+16].to_vec();
@@ -811,7 +819,7 @@ mod tests {
811819
fn max_message_len_encryption() {
812820
let mut outbound_peer = get_outbound_peer_for_initiator_test_vectors();
813821
let msg = [4u8; LN_MAX_MSG_LEN + 1];
814-
outbound_peer.encrypt_buffer(&msg);
822+
outbound_peer.encrypt_buffer(MessageBuf::from_encoded(&msg));
815823
}
816824

817825
#[test]

lightning/src/ln/peer_handler.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::ln::msgs::{ChannelMessageHandler, LightningError, SocketAddress, Onio
2727
#[cfg(not(c_bindings))]
2828
use crate::ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager};
2929
use crate::util::ser::{VecWriter, Writeable, Writer};
30-
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor, NextNoiseStep, MSG_BUF_ALLOC_SIZE};
30+
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor, NextNoiseStep, MessageBuf, MSG_BUF_ALLOC_SIZE};
3131
use crate::ln::wire;
3232
use crate::ln::wire::{Encode, Type};
3333
#[cfg(not(c_bindings))]
@@ -495,7 +495,7 @@ struct Peer {
495495
/// prioritize channel messages over them.
496496
///
497497
/// Note that these messages are *not* encrypted/MAC'd, and are only serialized.
498-
gossip_broadcast_buffer: VecDeque<Vec<u8>>,
498+
gossip_broadcast_buffer: VecDeque<MessageBuf>,
499499
awaiting_write_event: bool,
500500

501501
pending_read_buffer: Vec<u8>,
@@ -1102,7 +1102,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
11021102
}
11031103
if peer.should_buffer_gossip_broadcast() {
11041104
if let Some(msg) = peer.gossip_broadcast_buffer.pop_front() {
1105-
peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_buffer(&msg[..]));
1105+
peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_buffer(msg));
11061106
}
11071107
}
11081108
if peer.should_buffer_gossip_backfill() {
@@ -1251,7 +1251,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
12511251
}
12521252

12531253
/// Append a message to a peer's pending outbound/write gossip broadcast buffer
1254-
fn enqueue_encoded_gossip_broadcast(&self, peer: &mut Peer, encoded_message: Vec<u8>) {
1254+
fn enqueue_encoded_gossip_broadcast(&self, peer: &mut Peer, encoded_message: MessageBuf) {
12551255
peer.msgs_sent_since_pong += 1;
12561256
debug_assert!(peer.gossip_broadcast_buffer.len() <= OUTBOUND_BUFFER_LIMIT_DROP_GOSSIP);
12571257
peer.gossip_broadcast_buffer.push_back(encoded_message);
@@ -1800,7 +1800,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
18001800
if except_node.is_some() && peer.their_node_id.as_ref().map(|(pk, _)| pk) == except_node {
18011801
continue;
18021802
}
1803-
self.enqueue_encoded_gossip_broadcast(&mut *peer, encoded_msg.clone());
1803+
self.enqueue_encoded_gossip_broadcast(&mut *peer, MessageBuf::from_encoded(&encoded_msg));
18041804
}
18051805
},
18061806
wire::Message::NodeAnnouncement(ref msg) => {
@@ -1827,7 +1827,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
18271827
if except_node.is_some() && peer.their_node_id.as_ref().map(|(pk, _)| pk) == except_node {
18281828
continue;
18291829
}
1830-
self.enqueue_encoded_gossip_broadcast(&mut *peer, encoded_msg.clone());
1830+
self.enqueue_encoded_gossip_broadcast(&mut *peer, MessageBuf::from_encoded(&encoded_msg));
18311831
}
18321832
},
18331833
wire::Message::ChannelUpdate(ref msg) => {
@@ -1849,7 +1849,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
18491849
if except_node.is_some() && peer.their_node_id.as_ref().map(|(pk, _)| pk) == except_node {
18501850
continue;
18511851
}
1852-
self.enqueue_encoded_gossip_broadcast(&mut *peer, encoded_msg.clone());
1852+
self.enqueue_encoded_gossip_broadcast(&mut *peer, MessageBuf::from_encoded(&encoded_msg));
18531853
}
18541854
},
18551855
_ => debug_assert!(false, "We shouldn't attempt to forward anything but gossip messages"),

0 commit comments

Comments
 (0)