Skip to content

Commit

Permalink
Allocation optimizations, review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
optout21 committed Sep 10, 2024
1 parent ca0e089 commit 8833d7c
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 10 deletions.
18 changes: 13 additions & 5 deletions lightning-invoice/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ impl FromBase32 for Bolt11InvoiceFeatures {
// Carry bits, 0, 1, 2, 3, or 4 bits
let mut carry_bits = 0;
let mut carry = 0u8;
let mut output = Vec::<u8>::new();
let expected_raw_length = (field_data.len() * 5 + 7) / 8;
let mut output = Vec::<u8>::with_capacity(expected_raw_length);

// Iterate over input in reverse
for curr_in in field_data.iter().rev() {
Expand All @@ -107,14 +108,21 @@ impl FromBase32 for Bolt11InvoiceFeatures {
carry_bits += 5;
}
}

// No more inputs, output remaining (if any)
if carry_bits > 0 {
output.push(carry);
}

// This is to double check the estimated length and
// satisfying mutation test on the capacity, which is mutatable
debug_assert_eq!(output.len(), expected_raw_length);

// Trim the highest feature bits
while !output.is_empty() && output[output.len() - 1] == 0 {
output.pop();
}

Ok(Bolt11InvoiceFeatures::from_le_bytes(output))
}
}
Expand Down Expand Up @@ -364,7 +372,7 @@ impl FromStr for SignedRawBolt11Invoice {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parsed = CheckedHrpstring::new::<Bech32>(s)?;
let hrp = parsed.hrp();
// Access original non-packed 32 byte values (as Fe32s)
// Access original non-packed 32 byte values (as Fe32s) (iterator type is needed for API hack)
let data: Vec<_> = parsed.fe32_iter::<alloc::boxed::Box<dyn Iterator<Item = u8>>>().collect();

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

Expand Down Expand Up @@ -582,7 +590,7 @@ impl FromBase32 for Sha256 {
// "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
Err(Bolt11ParseError::Skip)
} else {
Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
Ok(Sha256(sha256::Hash::from_slice(&<[u8; 32]>::from_base32(field_data)?)
.expect("length was checked before (52 u5 -> 32 u8)")))
}
}
Expand All @@ -608,7 +616,7 @@ impl FromBase32 for PayeePubKey {
// "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
Err(Bolt11ParseError::Skip)
} else {
let data_bytes = Vec::<u8>::from_base32(field_data)?;
let data_bytes = <[u8; 33]>::from_base32(field_data)?;
let pub_key = PublicKey::from_slice(&data_bytes)?;
Ok(pub_key.into())
}
Expand Down
16 changes: 11 additions & 5 deletions lightning-invoice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,8 @@ macro_rules! find_all_extract {
impl RawBolt11Invoice {
/// Hash the HRP (as bytes) and signatureless data part (as Fe32 iterator)
fn hash_from_parts<'s>(hrp_bytes: &[u8], data_without_signature: Box<dyn Iterator<Item = Fe32> + 's>) -> [u8; 32] {
use crate::de::FromBase32;
use crate::bech32::Fe32IterExt;
use bitcoin::hashes::HashEngine;

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

Expand All @@ -1018,12 +1019,17 @@ impl RawBolt11Invoice {
}
}

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

let mut hash: [u8; 32] = Default::default();
hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
hash.copy_from_slice(raw_hash.as_ref());
hash
}

Expand Down

0 comments on commit 8833d7c

Please sign in to comment.