Skip to content

Commit 8833d7c

Browse files
committed
Allocation optimizations, review comments
1 parent ca0e089 commit 8833d7c

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

lightning-invoice/src/de.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ impl FromBase32 for Bolt11InvoiceFeatures {
8989
// Carry bits, 0, 1, 2, 3, or 4 bits
9090
let mut carry_bits = 0;
9191
let mut carry = 0u8;
92-
let mut output = Vec::<u8>::new();
92+
let expected_raw_length = (field_data.len() * 5 + 7) / 8;
93+
let mut output = Vec::<u8>::with_capacity(expected_raw_length);
9394

9495
// Iterate over input in reverse
9596
for curr_in in field_data.iter().rev() {
@@ -107,14 +108,21 @@ impl FromBase32 for Bolt11InvoiceFeatures {
107108
carry_bits += 5;
108109
}
109110
}
111+
110112
// No more inputs, output remaining (if any)
111113
if carry_bits > 0 {
112114
output.push(carry);
113115
}
116+
117+
// This is to double check the estimated length and
118+
// satisfying mutation test on the capacity, which is mutatable
119+
debug_assert_eq!(output.len(), expected_raw_length);
120+
114121
// Trim the highest feature bits
115122
while !output.is_empty() && output[output.len() - 1] == 0 {
116123
output.pop();
117124
}
125+
118126
Ok(Bolt11InvoiceFeatures::from_le_bytes(output))
119127
}
120128
}
@@ -364,7 +372,7 @@ impl FromStr for SignedRawBolt11Invoice {
364372
fn from_str(s: &str) -> Result<Self, Self::Err> {
365373
let parsed = CheckedHrpstring::new::<Bech32>(s)?;
366374
let hrp = parsed.hrp();
367-
// Access original non-packed 32 byte values (as Fe32s)
375+
// Access original non-packed 32 byte values (as Fe32s) (iterator type is needed for API hack)
368376
let data: Vec<_> = parsed.fe32_iter::<alloc::boxed::Box<dyn Iterator<Item = u8>>>().collect();
369377

370378
const SIGNATURE_LEN5: usize = 104; // 32-bit values, 65 bytes
@@ -470,7 +478,7 @@ impl FromBase32 for Bolt11InvoiceSignature {
470478
"Bolt11InvoiceSignature::from_base32()".into(),
471479
));
472480
}
473-
let recoverable_signature_bytes = Vec::<u8>::from_base32(signature)?;
481+
let recoverable_signature_bytes = <[u8; 65]>::from_base32(signature)?;
474482
let signature = &recoverable_signature_bytes[0..64];
475483
let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
476484

@@ -582,7 +590,7 @@ impl FromBase32 for Sha256 {
582590
// "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
583591
Err(Bolt11ParseError::Skip)
584592
} else {
585-
Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
593+
Ok(Sha256(sha256::Hash::from_slice(&<[u8; 32]>::from_base32(field_data)?)
586594
.expect("length was checked before (52 u5 -> 32 u8)")))
587595
}
588596
}
@@ -608,7 +616,7 @@ impl FromBase32 for PayeePubKey {
608616
// "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
609617
Err(Bolt11ParseError::Skip)
610618
} else {
611-
let data_bytes = Vec::<u8>::from_base32(field_data)?;
619+
let data_bytes = <[u8; 33]>::from_base32(field_data)?;
612620
let pub_key = PublicKey::from_slice(&data_bytes)?;
613621
Ok(pub_key.into())
614622
}

lightning-invoice/src/lib.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,8 @@ macro_rules! find_all_extract {
10021002
impl RawBolt11Invoice {
10031003
/// Hash the HRP (as bytes) and signatureless data part (as Fe32 iterator)
10041004
fn hash_from_parts<'s>(hrp_bytes: &[u8], data_without_signature: Box<dyn Iterator<Item = Fe32> + 's>) -> [u8; 32] {
1005-
use crate::de::FromBase32;
1005+
use crate::bech32::Fe32IterExt;
1006+
use bitcoin::hashes::HashEngine;
10061007

10071008
let mut data_part = data_without_signature.collect::<Vec<Fe32>>();
10081009

@@ -1018,12 +1019,17 @@ impl RawBolt11Invoice {
10181019
}
10191020
}
10201021

1021-
let mut preimage = Vec::<u8>::from(hrp_bytes);
1022-
preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
1023-
.expect("No padding error may occur due to appended zero above."));
1022+
// Hash bytes and data part sequentially
1023+
let mut engine = sha256::Hash::engine();
1024+
engine.input(hrp_bytes);
1025+
// Iterate over data
1026+
// Note: if it was not for padding, this could go on the supplied original iterator
1027+
// (see https://github.com/rust-bitcoin/rust-bech32/issues/198)
1028+
data_part.into_iter().fes_to_bytes().for_each(|v| { engine.input(&[v])});
1029+
let raw_hash = sha256::Hash::from_engine(engine);
10241030

10251031
let mut hash: [u8; 32] = Default::default();
1026-
hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
1032+
hash.copy_from_slice(raw_hash.as_ref());
10271033
hash
10281034
}
10291035

0 commit comments

Comments
 (0)