Skip to content

Commit 77bdc32

Browse files
authored
Merge pull request #933 from TheBlueMatt/2021-05-ser-fast
Speed up deserialization of secp256k1 objects significantly
2 parents c05347f + 7231b4a commit 77bdc32

11 files changed

+257
-185
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,8 @@ panic = "abort"
2222
opt-level = 3
2323
lto = true
2424
panic = "abort"
25+
26+
[profile.bench]
27+
opt-level = 3
28+
codegen-units = 1
29+
lto = true

lightning/src/ln/onion_utils.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use ln::{PaymentHash, PaymentSecret};
1111
use ln::channelmanager::HTLCSource;
1212
use ln::msgs;
1313
use routing::router::RouteHop;
14-
use util::byte_utils;
1514
use util::chacha20::ChaCha20;
1615
use util::errors::{self, APIError};
1716
use util::ser::{Readable, Writeable, LengthCalculatingWriter};
@@ -29,6 +28,7 @@ use bitcoin::secp256k1;
2928

3029
use prelude::*;
3130
use std::io::Cursor;
31+
use core::convert::TryInto;
3232
use core::ops::Deref;
3333

3434
pub(super) struct OnionKeys {
@@ -367,7 +367,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing, L: Deref>(secp_ctx: &
367367
const NODE: u16 = 0x2000;
368368
const UPDATE: u16 = 0x1000;
369369

370-
let error_code = byte_utils::slice_to_be16(&error_code_slice);
370+
let error_code = u16::from_be_bytes(error_code_slice.try_into().expect("len is 2"));
371371
error_code_ret = Some(error_code);
372372
error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
373373

@@ -394,7 +394,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing, L: Deref>(secp_ctx: &
394394
}
395395
else if error_code & UPDATE == UPDATE {
396396
if let Some(update_len_slice) = err_packet.failuremsg.get(debug_field_size+2..debug_field_size+4) {
397-
let update_len = byte_utils::slice_to_be16(&update_len_slice) as usize;
397+
let update_len = u16::from_be_bytes(update_len_slice.try_into().expect("len is 2")) as usize;
398398
if let Some(update_slice) = err_packet.failuremsg.get(debug_field_size + 4..debug_field_size + 4 + update_len) {
399399
if let Ok(chan_update) = msgs::ChannelUpdate::read(&mut Cursor::new(&update_slice)) {
400400
// if channel_update should NOT have caused the failure:

lightning/src/ln/peer_channel_encryptor.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
2121
use bitcoin::secp256k1;
2222

2323
use util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
24-
use util::byte_utils;
2524
use bitcoin::hashes::hex::ToHex;
2625

2726
/// Maximum Lightning message data length according to
@@ -141,7 +140,7 @@ impl PeerChannelEncryptor {
141140
#[inline]
142141
fn encrypt_with_ad(res: &mut[u8], n: u64, key: &[u8; 32], h: &[u8], plaintext: &[u8]) {
143142
let mut nonce = [0; 12];
144-
nonce[4..].copy_from_slice(&byte_utils::le64_to_array(n));
143+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
145144

146145
let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h);
147146
let mut tag = [0; 16];
@@ -152,7 +151,7 @@ impl PeerChannelEncryptor {
152151
#[inline]
153152
fn decrypt_with_ad(res: &mut[u8], n: u64, key: &[u8; 32], h: &[u8], cyphertext: &[u8]) -> Result<(), LightningError> {
154153
let mut nonce = [0; 12];
155-
nonce[4..].copy_from_slice(&byte_utils::le64_to_array(n));
154+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
156155

157156
let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h);
158157
if !chacha.decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]) {
@@ -406,7 +405,7 @@ impl PeerChannelEncryptor {
406405
*sn = 0;
407406
}
408407

409-
Self::encrypt_with_ad(&mut res[0..16+2], *sn, sk, &[0; 0], &byte_utils::be16_to_array(msg.len() as u16));
408+
Self::encrypt_with_ad(&mut res[0..16+2], *sn, sk, &[0; 0], &(msg.len() as u16).to_be_bytes());
410409
*sn += 1;
411410

412411
Self::encrypt_with_ad(&mut res[16+2..], *sn, sk, &[0; 0], msg);
@@ -435,7 +434,7 @@ impl PeerChannelEncryptor {
435434
let mut res = [0; 2];
436435
Self::decrypt_with_ad(&mut res, *rn, rk, &[0; 0], msg)?;
437436
*rn += 1;
438-
Ok(byte_utils::slice_to_be16(&res))
437+
Ok(u16::from_be_bytes(res))
439438
},
440439
_ => panic!("Tried to decrypt a message prior to noise handshake completion"),
441440
}

lightning/src/ln/wire.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,8 @@ impl Encode for msgs::GossipTimestampFilter {
350350
#[cfg(test)]
351351
mod tests {
352352
use super::*;
353-
use util::byte_utils;
354353
use prelude::*;
354+
use core::convert::TryInto;
355355

356356
// Big-endian wire encoding of Pong message (type = 19, byteslen = 2).
357357
const ENCODED_PONG: [u8; 6] = [0u8, 19u8, 0u8, 2u8, 0u8, 0u8];
@@ -397,7 +397,7 @@ mod tests {
397397

398398
#[test]
399399
fn read_unknown_message() {
400-
let buffer = &byte_utils::be16_to_array(::core::u16::MAX);
400+
let buffer = &::core::u16::MAX.to_be_bytes();
401401
let mut reader = ::std::io::Cursor::new(buffer);
402402
let message = read(&mut reader).unwrap();
403403
match message {
@@ -414,7 +414,7 @@ mod tests {
414414

415415
let type_length = ::core::mem::size_of::<u16>();
416416
let (type_bytes, payload_bytes) = buffer.split_at(type_length);
417-
assert_eq!(byte_utils::slice_to_be16(type_bytes), msgs::Pong::TYPE);
417+
assert_eq!(u16::from_be_bytes(type_bytes.try_into().unwrap()), msgs::Pong::TYPE);
418418
assert_eq!(payload_bytes, &ENCODED_PONG[type_length..]);
419419
}
420420

lightning/src/routing/network_graph.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,3 +2424,30 @@ mod tests {
24242424
assert!(result.is_err());
24252425
}
24262426
}
2427+
2428+
#[cfg(all(test, feature = "unstable"))]
2429+
mod benches {
2430+
use super::*;
2431+
2432+
use test::Bencher;
2433+
use std::io::Read;
2434+
2435+
#[bench]
2436+
fn read_network_graph(bench: &mut Bencher) {
2437+
let mut d = ::routing::router::test_utils::get_route_file().unwrap();
2438+
let mut v = Vec::new();
2439+
d.read_to_end(&mut v).unwrap();
2440+
bench.iter(|| {
2441+
let _ = NetworkGraph::read(&mut std::io::Cursor::new(&v)).unwrap();
2442+
});
2443+
}
2444+
2445+
#[bench]
2446+
fn write_network_graph(bench: &mut Bencher) {
2447+
let mut d = ::routing::router::test_utils::get_route_file().unwrap();
2448+
let net_graph = NetworkGraph::read(&mut d).unwrap();
2449+
bench.iter(|| {
2450+
let _ = net_graph.encode();
2451+
});
2452+
}
2453+
}

lightning/src/routing/router.rs

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3856,44 +3856,21 @@ mod tests {
38563856
}
38573857
}
38583858

3859-
use std::fs::File;
3860-
use util::ser::Readable;
3861-
/// Tries to open a network graph file, or panics with a URL to fetch it.
3862-
pub(super) fn get_route_file() -> Result<std::fs::File, std::io::Error> {
3863-
let res = File::open("net_graph-2021-05-27.bin") // By default we're run in RL/lightning
3864-
.or_else(|_| File::open("lightning/net_graph-2021-05-27.bin")) // We may be run manually in RL/
3865-
.or_else(|_| { // Fall back to guessing based on the binary location
3866-
// path is likely something like .../rust-lightning/target/debug/deps/lightning-...
3867-
let mut path = std::env::current_exe().unwrap();
3868-
path.pop(); // lightning-...
3869-
path.pop(); // deps
3870-
path.pop(); // debug
3871-
path.pop(); // target
3872-
path.push("lightning");
3873-
path.push("net_graph-2021-05-27.bin");
3874-
eprintln!("{}", path.to_str().unwrap());
3875-
File::open(path)
3876-
});
3877-
#[cfg(require_route_graph_test)]
3878-
return Ok(res.expect("Didn't have route graph and was configured to require it"));
3879-
#[cfg(not(require_route_graph_test))]
3880-
return res;
3881-
}
3882-
38833859
pub(super) fn random_init_seed() -> u64 {
38843860
// Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG.
38853861
use core::hash::{BuildHasher, Hasher};
38863862
let seed = std::collections::hash_map::RandomState::new().build_hasher().finish();
38873863
println!("Using seed of {}", seed);
38883864
seed
38893865
}
3866+
use util::ser::Readable;
38903867

38913868
#[test]
38923869
fn generate_routes() {
3893-
let mut d = match get_route_file() {
3870+
let mut d = match super::test_utils::get_route_file() {
38943871
Ok(f) => f,
3895-
Err(_) => {
3896-
eprintln!("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
3872+
Err(e) => {
3873+
eprintln!("{}", e);
38973874
return;
38983875
},
38993876
};
@@ -3917,10 +3894,10 @@ mod tests {
39173894

39183895
#[test]
39193896
fn generate_routes_mpp() {
3920-
let mut d = match get_route_file() {
3897+
let mut d = match super::test_utils::get_route_file() {
39213898
Ok(f) => f,
3922-
Err(_) => {
3923-
eprintln!("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
3899+
Err(e) => {
3900+
eprintln!("{}", e);
39243901
return;
39253902
},
39263903
};
@@ -3943,12 +3920,38 @@ mod tests {
39433920
}
39443921
}
39453922

3923+
#[cfg(test)]
3924+
pub(crate) mod test_utils {
3925+
use std::fs::File;
3926+
/// Tries to open a network graph file, or panics with a URL to fetch it.
3927+
pub(crate) fn get_route_file() -> Result<std::fs::File, &'static str> {
3928+
let res = File::open("net_graph-2021-05-27.bin") // By default we're run in RL/lightning
3929+
.or_else(|_| File::open("lightning/net_graph-2021-05-27.bin")) // We may be run manually in RL/
3930+
.or_else(|_| { // Fall back to guessing based on the binary location
3931+
// path is likely something like .../rust-lightning/target/debug/deps/lightning-...
3932+
let mut path = std::env::current_exe().unwrap();
3933+
path.pop(); // lightning-...
3934+
path.pop(); // deps
3935+
path.pop(); // debug
3936+
path.pop(); // target
3937+
path.push("lightning");
3938+
path.push("net_graph-2021-05-27.bin");
3939+
eprintln!("{}", path.to_str().unwrap());
3940+
File::open(path)
3941+
})
3942+
.map_err(|_| "Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
3943+
#[cfg(require_route_graph_test)]
3944+
return Ok(res.unwrap());
3945+
#[cfg(not(require_route_graph_test))]
3946+
return res;
3947+
}
3948+
}
3949+
39463950
#[cfg(all(test, feature = "unstable"))]
39473951
mod benches {
39483952
use super::*;
39493953
use util::logger::{Logger, Record};
39503954

3951-
use prelude::*;
39523955
use test::Bencher;
39533956

39543957
struct DummyLogger {}
@@ -3958,8 +3961,7 @@ mod benches {
39583961

39593962
#[bench]
39603963
fn generate_routes(bench: &mut Bencher) {
3961-
let mut d = tests::get_route_file()
3962-
.expect("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
3964+
let mut d = test_utils::get_route_file().unwrap();
39633965
let graph = NetworkGraph::read(&mut d).unwrap();
39643966

39653967
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
@@ -3990,8 +3992,7 @@ mod benches {
39903992

39913993
#[bench]
39923994
fn generate_mpp_routes(bench: &mut Bencher) {
3993-
let mut d = tests::get_route_file()
3994-
.expect("Please fetch https://bitcoin.ninja/ldk-net_graph-45d86ead641d-2021-05-27.bin and place it at lightning/net_graph-2021-05-27.bin");
3995+
let mut d = test_utils::get_route_file().unwrap();
39953996
let graph = NetworkGraph::read(&mut d).unwrap();
39963997

39973998
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...

lightning/src/util/byte_utils.rs

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

10-
#[inline]
11-
pub fn slice_to_be16(v: &[u8]) -> u16 {
12-
((v[0] as u16) << 8*1) |
13-
((v[1] as u16) << 8*0)
14-
}
15-
#[inline]
16-
pub fn slice_to_be32(v: &[u8]) -> u32 {
17-
((v[0] as u32) << 8*3) |
18-
((v[1] as u32) << 8*2) |
19-
((v[2] as u32) << 8*1) |
20-
((v[3] as u32) << 8*0)
21-
}
22-
#[cfg(not(feature = "fuzztarget"))] // Used only by poly1305
23-
#[inline]
24-
pub fn slice_to_le32(v: &[u8]) -> u32 {
25-
((v[0] as u32) << 8*0) |
26-
((v[1] as u32) << 8*1) |
27-
((v[2] as u32) << 8*2) |
28-
((v[3] as u32) << 8*3)
29-
}
3010
#[inline]
3111
pub fn slice_to_be48(v: &[u8]) -> u64 {
3212
((v[0] as u64) << 8*5) |
@@ -64,16 +44,6 @@ pub fn be32_to_array(u: u32) -> [u8; 4] {
6444
v[3] = ((u >> 8*0) & 0xff) as u8;
6545
v
6646
}
67-
#[cfg(not(feature = "fuzztarget"))] // Used only by poly1305
68-
#[inline]
69-
pub fn le32_to_array(u: u32) -> [u8; 4] {
70-
let mut v = [0; 4];
71-
v[0] = ((u >> 8*0) & 0xff) as u8;
72-
v[1] = ((u >> 8*1) & 0xff) as u8;
73-
v[2] = ((u >> 8*2) & 0xff) as u8;
74-
v[3] = ((u >> 8*3) & 0xff) as u8;
75-
v
76-
}
7747
#[inline]
7848
pub fn be48_to_array(u: u64) -> [u8; 6] {
7949
assert!(u & 0xffff_0000_0000_0000 == 0);
@@ -120,14 +90,10 @@ mod tests {
12090

12191
#[test]
12292
fn test_all() {
123-
assert_eq!(slice_to_be16(&[0xde, 0xad]), 0xdead);
124-
assert_eq!(slice_to_be32(&[0xde, 0xad, 0xbe, 0xef]), 0xdeadbeef);
125-
assert_eq!(slice_to_le32(&[0xef, 0xbe, 0xad, 0xde]), 0xdeadbeef);
12693
assert_eq!(slice_to_be48(&[0xde, 0xad, 0xbe, 0xef, 0x1b, 0xad]), 0xdeadbeef1bad);
12794
assert_eq!(slice_to_be64(&[0xde, 0xad, 0xbe, 0xef, 0x1b, 0xad, 0x1d, 0xea]), 0xdeadbeef1bad1dea);
12895
assert_eq!(be16_to_array(0xdead), [0xde, 0xad]);
12996
assert_eq!(be32_to_array(0xdeadbeef), [0xde, 0xad, 0xbe, 0xef]);
130-
assert_eq!(le32_to_array(0xdeadbeef), [0xef, 0xbe, 0xad, 0xde]);
13197
assert_eq!(be48_to_array(0xdeadbeef1bad), [0xde, 0xad, 0xbe, 0xef, 0x1b, 0xad]);
13298
assert_eq!(be64_to_array(0xdeadbeef1bad1dea), [0xde, 0xad, 0xbe, 0xef, 0x1b, 0xad, 0x1d, 0xea]);
13399
assert_eq!(le64_to_array(0xdeadbeef1bad1dea), [0xea, 0x1d, 0xad, 0x1b, 0xef, 0xbe, 0xad, 0xde]);

0 commit comments

Comments
 (0)