Skip to content

Commit 48bd3d7

Browse files
committed
FesPadder and others
1 parent babfa97 commit 48bd3d7

File tree

2 files changed

+141
-34
lines changed

2 files changed

+141
-34
lines changed

lightning-invoice/src/de.rs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,18 @@ impl FromBase32 for Bolt11InvoiceFeatures {
8585
/// and taking the resulting 8-bit values (right to left),
8686
/// with the leading 0's skipped.
8787
fn from_base32(field_data: &[Fe32]) -> Result<Self, Self::Err> {
88-
// fes_to_bytes() trims, input needs to be padded, find padding size
89-
let input_len = field_data.len();
90-
let mut padding = 0;
91-
while ((input_len + padding) * 5) % 8 != 0 {
92-
padding += 1;
93-
}
88+
use crate::FesPaddable;
89+
9490
let mut output = field_data
9591
.iter()
9692
.map(|f| Fe32::try_from(f.to_u8().reverse_bits() >> 3).expect("<32"))
9793
.rev()
98-
.chain(core::iter::repeat(Fe32::Q).take(padding))
94+
// fes_to_bytes() trims, input needs to be padded
95+
.pad_fes()
9996
.fes_to_bytes()
10097
.map(|b| b.reverse_bits())
10198
.collect::<Vec<u8>>();
102-
// Trim the highest feature bits -<-- COULD NOT DO WITH ITER
99+
// Trim the highest feature bits <-- COULD NOT DO WITH ITER
103100
while !output.is_empty() && output[output.len() - 1] == 0 {
104101
output.pop();
105102
}
@@ -386,10 +383,8 @@ impl FromStr for SignedRawBolt11Invoice {
386383
fn from_str(s: &str) -> Result<Self, Self::Err> {
387384
let parsed = CheckedHrpstring::new::<Bech32>(s)?;
388385
let hrp = parsed.hrp();
389-
// Access original non-packed 32 byte values (as ascii + conversion)
390-
let data: Vec<_> = parsed.data_part_ascii_no_checksum().iter()
391-
.map(|ch| Fe32::from_char(char::from(*ch)).expect("value should be < 32"))
392-
.collect();
386+
// Access original non-packed 32 byte values (as Fe32s)
387+
let data: Vec<_> = parsed.fe32_iter::<alloc::boxed::Box<dyn Iterator<Item = u8>>>().collect();
393388

394389
const SIGNATURE_LEN5: usize = 104; // 32-bit values, 65 bytes
395390
if data.len() < SIGNATURE_LEN5 {
@@ -398,16 +393,15 @@ impl FromStr for SignedRawBolt11Invoice {
398393

399394
let raw_hrp: RawHrp = hrp.to_string().to_lowercase().parse()?;
400395
let data_part = RawDataPart::from_base32(&data[..data.len() - SIGNATURE_LEN5])?;
396+
let raw_invoice = RawBolt11Invoice {
397+
hrp: raw_hrp,
398+
data: data_part,
399+
};
400+
let hash = raw_invoice.signable_hash();
401401

402402
Ok(SignedRawBolt11Invoice {
403-
raw_invoice: RawBolt11Invoice {
404-
hrp: raw_hrp,
405-
data: data_part,
406-
},
407-
hash: RawBolt11Invoice::hash_from_parts(
408-
hrp.to_string().as_bytes(),
409-
&data[..data.len() - SIGNATURE_LEN5],
410-
),
403+
raw_invoice,
404+
hash,
411405
signature: Bolt11InvoiceSignature::from_base32(&data[data.len() - SIGNATURE_LEN5..])?,
412406
})
413407
}

lightning-invoice/src/lib.rs

Lines changed: 127 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,31 @@ pub enum Fallback {
528528
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
529529
pub struct Bolt11InvoiceSignature(pub RecoverableSignature);
530530

531+
/*
532+
impl Bolt11InvoiceSignature {
533+
fn from_bytes(data: &[u8]) -> Result<Self, Bolt11ParseError> {
534+
use bitcoin::secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
535+
536+
const SIGNATURE_LEN: usize = 65;
537+
if data.len() != SIGNATURE_LEN {
538+
return Err(Bolt11ParseError::InvalidSliceLength(
539+
data.len(),
540+
SIGNATURE_LEN,
541+
"Bolt11InvoiceSignature::from_bytes()".into(),
542+
));
543+
}
544+
let signature = &data[0..64];
545+
let recovery_id = RecoveryId::from_i32(data[64] as i32)?;
546+
debug_assert_eq!(recovery_id.to_i32(), 0);
547+
548+
Ok(Bolt11InvoiceSignature(RecoverableSignature::from_compact(
549+
signature,
550+
recovery_id
551+
)?))
552+
}
553+
}
554+
*/
555+
531556
impl PartialOrd for Bolt11InvoiceSignature {
532557
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
533558
Some(self.cmp(other))
@@ -998,6 +1023,84 @@ macro_rules! find_all_extract {
9981023
};
9991024
}
10001025

1026+
/// Adaptor to pad a Fe32 iter
1027+
// #[derive(Clone, PartialEq, Eq)]
1028+
pub struct FesPadder<I: Iterator<Item = Fe32>> {
1029+
end_reached: bool,
1030+
fe32_count: usize,
1031+
pad_count: u8,
1032+
iter: I,
1033+
}
1034+
1035+
impl<I> FesPadder<I>
1036+
where
1037+
I: Iterator<Item = Fe32>,
1038+
{
1039+
// type Item = u8;
1040+
1041+
fn new(iter: I) -> Self {
1042+
Self {
1043+
end_reached: false,
1044+
fe32_count: 0,
1045+
pad_count: 0,
1046+
iter,
1047+
}
1048+
}
1049+
1050+
fn pad_count_from_fe32_count(fe32_count: usize) -> u8 {
1051+
let remainder = (fe32_count * 5) % 8;
1052+
if remainder == 0 { 0 } else if remainder < 3 { 2 } else { 1 }
1053+
}
1054+
1055+
fn padded_count(fe32_count: usize) -> usize {
1056+
fe32_count + Self::pad_count_from_fe32_count(fe32_count) as usize
1057+
}
1058+
}
1059+
1060+
impl<I> Iterator for FesPadder<I>
1061+
where
1062+
I: Iterator<Item = Fe32>,
1063+
{
1064+
type Item = Fe32;
1065+
1066+
fn next(&mut self) -> Option<Self::Item> {
1067+
if let Some(elem) = self.iter.next() {
1068+
self.fe32_count += 1;
1069+
Some(elem)
1070+
} else {
1071+
// end reached
1072+
if !self.end_reached {
1073+
self.end_reached = true;
1074+
self.pad_count = Self::pad_count_from_fe32_count(self.fe32_count);
1075+
}
1076+
if self.pad_count > 0 {
1077+
self.pad_count -= 1;
1078+
Some(Fe32::Q)
1079+
} else {
1080+
None
1081+
}
1082+
}
1083+
}
1084+
1085+
fn size_hint(&self) -> (usize, Option<usize>) {
1086+
let (fes_min, fes_max) = self.iter.size_hint();
1087+
// +1 because we set last_fe with call to `next`.
1088+
let min = Self::padded_count(fes_min + 1);
1089+
let max = fes_max.map(|max| Self::padded_count(max));
1090+
(min, max)
1091+
}
1092+
}
1093+
1094+
/// Trait to pad an Fe32 iterator
1095+
pub trait FesPaddable: Sized + Iterator<Item = Fe32> {
1096+
/// Pad the iterator
1097+
fn pad_fes(self) -> FesPadder<Self> {
1098+
FesPadder::new(self)
1099+
}
1100+
}
1101+
1102+
impl<I> FesPaddable for I where I: Iterator<Item = Fe32> {}
1103+
10011104
#[allow(missing_docs)]
10021105
impl RawBolt11Invoice {
10031106
/// Hash the HRP (as bytes) and signatureless data part (as Fe32 iterator)
@@ -1008,35 +1111,45 @@ impl RawBolt11Invoice {
10081111

10091112
/// Hash the HRP as bytes and signatureless data part.
10101113
fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[Fe32]) -> [u8; 32] {
1011-
use crate::de::FromBase32;
1114+
use crate::bech32::Fe32IterExt;
10121115

1116+
let data_part = Vec::from(data_without_signature);
10131117
let mut preimage = Vec::<u8>::from(hrp_bytes);
1118+
preimage.extend_from_slice(
1119+
&data_part
1120+
.iter()
1121+
.copied()
1122+
// fes_to_bytes() trims, input needs to be padded
1123+
.pad_fes()
1124+
.fes_to_bytes()
1125+
.collect::<Vec<u8>>()
1126+
);
10141127

1015-
let mut data_part = Vec::from(data_without_signature);
1016-
let overhang = (data_part.len() * 5) % 8;
1017-
if overhang > 0 {
1018-
// add padding if data does not end at a byte boundary
1019-
data_part.push(Fe32::try_from(0).unwrap());
1128+
let mut hash: [u8; 32] = Default::default();
1129+
hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
1130+
hash
1131+
}
10201132

1021-
// if overhang is in (1..3) we need to add Fe32(0) padding two times
1022-
if overhang < 3 {
1023-
data_part.push(Fe32::try_from(0).unwrap());
1024-
}
1025-
}
1133+
/*
1134+
/// Hash the HRP as bytes and signatureless data part.
1135+
fn hash_from_parts_u8(hrp_bytes: &[u8], data_without_signature: &[u8]) -> [u8; 32] {
1136+
// use crate::de::FromBase32;
10261137
1027-
preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
1028-
.expect("No padding error may occur due to appended zero above."));
1138+
let mut preimage = Vec::<u8>::from(hrp_bytes);
1139+
let data_part = Vec::from(data_without_signature);
1140+
preimage.extend(data_part);
10291141
10301142
let mut hash: [u8; 32] = Default::default();
10311143
hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
10321144
hash
10331145
}
1146+
*/
10341147

10351148
/// Calculate the hash of the encoded `RawBolt11Invoice` which should be signed.
10361149
pub fn signable_hash(&self) -> [u8; 32] {
10371150
use crate::ser::Base32Iterable;
10381151

1039-
RawBolt11Invoice::hash_from_parts_iter(
1152+
Self::hash_from_parts_iter(
10401153
self.hrp.to_string().as_bytes(),
10411154
self.data.fe_iter(),
10421155
)

0 commit comments

Comments
 (0)