diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index 1d2a4cdbfbe..1692988ba0b 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -17,13 +17,12 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["std"] no-std = ["lightning/no-std"] -std = ["bitcoin/std", "num-traits/std", "lightning/std", "bech32/std"] +std = ["bitcoin/std", "lightning/std", "bech32/std"] [dependencies] bech32 = { version = "0.9.0", default-features = false } lightning = { version = "0.0.121", path = "../lightning", default-features = false } secp256k1 = { version = "0.27.0", default-features = false, features = ["recovery", "alloc"] } -num-traits = { version = "0.2.8", default-features = false } serde = { version = "1.0.118", optional = true } bitcoin = { version = "0.30.2", default-features = false } diff --git a/lightning-invoice/src/de.rs b/lightning-invoice/src/de.rs index c75373ea9da..9284999b188 100644 --- a/lightning-invoice/src/de.rs +++ b/lightning-invoice/src/de.rs @@ -18,8 +18,6 @@ use lightning::ln::PaymentSecret; use lightning::routing::gossip::RoutingFees; use lightning::routing::router::{RouteHint, RouteHintHop}; -use num_traits::{CheckedAdd, CheckedMul}; - use secp256k1::ecdsa::{RecoveryId, RecoverableSignature}; use secp256k1::PublicKey; @@ -356,7 +354,7 @@ impl FromBase32 for PositiveTimestamp { if b32.len() != 7 { return Err(Bolt11ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into())); } - let timestamp: u64 = parse_int_be(b32, 32) + let timestamp: u64 = parse_u64_be(b32) .expect("7*5bit < 64bit, no overflow possible"); match PositiveTimestamp::from_unix_timestamp(timestamp) { Ok(t) => Ok(t), @@ -382,16 +380,17 @@ impl FromBase32 for Bolt11InvoiceSignature { } } -pub(crate) fn parse_int_be(digits: &[U], base: T) -> Option - where T: CheckedAdd + CheckedMul + From + Default, - U: Into + Copy -{ - digits.iter().fold(Some(Default::default()), |acc, b| - acc - .and_then(|x| x.checked_mul(&base)) - .and_then(|x| x.checked_add(&(Into::::into(*b)).into())) - ) -} +macro_rules! define_parse_int_be { ($name: ident, $ty: ty) => { + fn $name(digits: &[u5]) -> Option<$ty> { + digits.iter().fold(Some(Default::default()), |acc, b| + acc + .and_then(|x| x.checked_mul(32)) + .and_then(|x| x.checked_add((Into::::into(*b)).into())) + ) + } +} } +define_parse_int_be!(parse_u16_be, u16); +define_parse_int_be!(parse_u64_be, u64); fn parse_tagged_parts(data: &[u5]) -> Result, Bolt11ParseError> { let mut parts = Vec::::new(); @@ -404,7 +403,7 @@ fn parse_tagged_parts(data: &[u5]) -> Result, Bolt11ParseErr // Ignore tag at data[0], it will be handled in the TaggedField parsers and // parse the length to find the end of the tagged field's data - let len = parse_int_be(&data[1..3], 32).expect("can't overflow"); + let len = parse_u16_be(&data[1..3]).expect("can't overflow") as usize; let last_element = 3 + len; if data.len() < last_element { @@ -517,7 +516,7 @@ impl FromBase32 for ExpiryTime { type Err = Bolt11ParseError; fn from_base32(field_data: &[u5]) -> Result { - match parse_int_be::(field_data, 32) + match parse_u64_be(field_data) .map(ExpiryTime::from_seconds) { Some(t) => Ok(t), @@ -530,7 +529,7 @@ impl FromBase32 for MinFinalCltvExpiryDelta { type Err = Bolt11ParseError; fn from_base32(field_data: &[u5]) -> Result { - let expiry = parse_int_be::(field_data, 32); + let expiry = parse_u64_be(field_data); if let Some(expiry) = expiry { Ok(MinFinalCltvExpiryDelta(expiry)) } else { @@ -602,12 +601,12 @@ impl FromBase32 for PrivateRoute { let hop = RouteHintHop { src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?, - short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"), + short_channel_id: u64::from_be_bytes(channel_id), fees: RoutingFees { - base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"), - proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"), + base_msat: u32::from_be_bytes(hop_bytes[41..45].try_into().expect("slice too big?")), + proportional_millionths: u32::from_be_bytes(hop_bytes[45..49].try_into().expect("slice too big?")), }, - cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"), + cltv_expiry_delta: u16::from_be_bytes(hop_bytes[49..51].try_into().expect("slice too big?")), htlc_minimum_msat: None, htlc_maximum_msat: None, }; @@ -761,12 +760,16 @@ mod test { #[test] fn test_parse_int_from_bytes_be() { - use crate::de::parse_int_be; - - assert_eq!(parse_int_be::(&[1, 2, 3, 4], 256), Some(16909060)); - assert_eq!(parse_int_be::(&[1, 3], 32), Some(35)); - assert_eq!(parse_int_be::(&[255, 255, 255, 255], 256), Some(4294967295)); - assert_eq!(parse_int_be::(&[1, 0, 0, 0, 0], 256), None); + use crate::de::parse_u16_be; + + assert_eq!(parse_u16_be(&[ + u5::try_from_u8(1).unwrap(), u5::try_from_u8(2).unwrap(), + u5::try_from_u8(3).unwrap(), u5::try_from_u8(4).unwrap()] + ), Some(34916)); + assert_eq!(parse_u16_be(&[ + u5::try_from_u8(2).unwrap(), u5::try_from_u8(0).unwrap(), + u5::try_from_u8(0).unwrap(), u5::try_from_u8(0).unwrap()] + ), None); } #[test] @@ -916,7 +919,6 @@ mod test { use lightning::routing::router::{RouteHint, RouteHintHop}; use crate::PrivateRoute; use bech32::FromBase32; - use crate::de::parse_int_be; let input = from_bech32( "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\ @@ -932,7 +934,7 @@ mod test { 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55 ][..] ).unwrap(), - short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"), + short_channel_id: 0x0102030405060708, fees: RoutingFees { base_msat: 1, proportional_millionths: 20, @@ -949,7 +951,7 @@ mod test { 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55 ][..] ).unwrap(), - short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"), + short_channel_id: 0x030405060708090a, fees: RoutingFees { base_msat: 2, proportional_millionths: 30, diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index 5b326911444..20eaf7a82d2 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -31,7 +31,6 @@ pub mod utils; extern crate bech32; #[macro_use] extern crate lightning; -extern crate num_traits; extern crate secp256k1; extern crate alloc; #[cfg(any(test, feature = "std"))] @@ -2064,7 +2063,7 @@ mod test { let route_1 = RouteHint(vec![ RouteHintHop { src_node_id: public_key, - short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"), + short_channel_id: u64::from_be_bytes([123; 8]), fees: RoutingFees { base_msat: 2, proportional_millionths: 1, @@ -2075,7 +2074,7 @@ mod test { }, RouteHintHop { src_node_id: public_key, - short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"), + short_channel_id: u64::from_be_bytes([42; 8]), fees: RoutingFees { base_msat: 3, proportional_millionths: 2, @@ -2100,7 +2099,7 @@ mod test { }, RouteHintHop { src_node_id: public_key, - short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"), + short_channel_id: u64::from_be_bytes([1; 8]), fees: RoutingFees { base_msat: 5, proportional_millionths: 4,