@@ -8,8 +8,8 @@ use core::num::ParseIntError;
88use core:: str;
99use core:: str:: FromStr ;
1010
11+ use bech32:: primitives:: decode:: { CheckedHrpstring , CheckedHrpstringError } ;
1112use bech32:: { Bech32 , Fe32 , Fe32IterExt } ;
12- use bech32:: primitives:: decode:: { CheckedHrpstring , CheckedHrpstringError , ChecksumError } ;
1313
1414use bitcoin:: { PubkeyHash , ScriptHash , WitnessVersion } ;
1515use bitcoin:: hashes:: Hash ;
@@ -39,19 +39,37 @@ pub trait FromBase32: Sized {
3939// FromBase32 implementations are here, because the trait is in this module.
4040
4141impl FromBase32 for Vec < u8 > {
42- type Err = CheckedHrpstringError ;
42+ type Err = Bolt11ParseError ;
4343
4444 fn from_base32 ( data : & [ Fe32 ] ) -> Result < Self , Self :: Err > {
4545 Ok ( data. iter ( ) . copied ( ) . fes_to_bytes ( ) . collect :: < Self > ( ) )
4646 }
4747}
4848
49+ impl < const N : usize > FromBase32 for [ u8 ; N ] {
50+ type Err = Bolt11ParseError ;
51+
52+ fn from_base32 ( data : & [ Fe32 ] ) -> Result < Self , Self :: Err > {
53+ data. iter ( ) . copied ( ) . fes_to_bytes ( ) . collect :: < Vec < _ > > ( ) . try_into ( ) . map_err ( |_| {
54+ Bolt11ParseError :: InvalidSliceLength (
55+ data. len ( ) ,
56+ ( N * 8 + 4 ) / 5 ,
57+ "<[u8; N]>::from_base32()" . into ( ) ,
58+ )
59+ } )
60+ }
61+ }
62+
4963impl FromBase32 for PaymentSecret {
50- type Err = CheckedHrpstringError ;
64+ type Err = Bolt11ParseError ;
5165
5266 fn from_base32 ( field_data : & [ Fe32 ] ) -> Result < Self , Self :: Err > {
5367 if field_data. len ( ) != 52 {
54- return Err ( CheckedHrpstringError :: Checksum ( ChecksumError :: InvalidLength ) ) // TODO(bech32): not entirely accurate
68+ return Err ( Bolt11ParseError :: InvalidSliceLength (
69+ field_data. len ( ) ,
70+ 52 ,
71+ "PaymentSecret::from_base32()" . into ( ) ,
72+ ) ) ;
5573 }
5674 let data_bytes = Vec :: < u8 > :: from_base32 ( field_data) ?;
5775 let mut payment_secret = [ 0 ; 32 ] ;
@@ -61,28 +79,45 @@ impl FromBase32 for PaymentSecret {
6179}
6280
6381impl FromBase32 for Bolt11InvoiceFeatures {
64- type Err = CheckedHrpstringError ;
82+ type Err = Bolt11ParseError ;
6583
84+ /// Convert to byte values, by packing the 5-bit groups,
85+ /// putting the 5-bit values from left to-right (reverse order),
86+ /// starting from the rightmost bit,
87+ /// and taking the resulting 8-bit values (right to left),
88+ /// with the leading 0's skipped.
6689 fn from_base32 ( field_data : & [ Fe32 ] ) -> Result < Self , Self :: Err > {
67- // Explanation for the "7": the normal way to round up when dividing is to add the divisor
68- // minus one before dividing
69- let length_bytes = ( field_data. len ( ) * 5 + 7 ) / 8 as usize ;
70- let mut res_bytes: Vec < u8 > = vec ! [ 0 ; length_bytes] ;
71- for ( u5_idx, chunk) in field_data. iter ( ) . enumerate ( ) {
72- let bit_pos_from_right_0_indexed = ( field_data. len ( ) - u5_idx - 1 ) * 5 ;
73- let new_byte_idx = ( bit_pos_from_right_0_indexed / 8 ) as usize ;
74- let new_bit_pos = bit_pos_from_right_0_indexed % 8 ;
75- let chunk_u16 = chunk. to_u8 ( ) as u16 ;
76- res_bytes[ new_byte_idx] |= ( ( chunk_u16 << new_bit_pos) & 0xff ) as u8 ;
77- if new_byte_idx != length_bytes - 1 {
78- res_bytes[ new_byte_idx + 1 ] |= ( ( chunk_u16 >> ( 8 -new_bit_pos) ) & 0xff ) as u8 ;
90+ // Fe32 conversion cannot be used, because this unpacks from right, right-to-left
91+ // Carry bits, 0, 1, 2, 3, or 4 bits
92+ let mut carry_bits = 0 ;
93+ let mut carry = 0u8 ;
94+ let mut output = Vec :: < u8 > :: new ( ) ;
95+
96+ // Iterate over input in reverse
97+ for curr_in in field_data. iter ( ) . rev ( ) {
98+ let curr_in_as_u8 = curr_in. to_u8 ( ) ;
99+ if carry_bits >= 3 {
100+ // we have a new full byte -- 3, 4 or 5 carry bits, plus 5 new ones
101+ // For combining with carry '|', '^', or '+' can be used (disjoint bit positions)
102+ let next = carry + ( curr_in_as_u8 << carry_bits) ;
103+ output. push ( next) ;
104+ carry = curr_in_as_u8 >> ( 8 - carry_bits) ;
105+ carry_bits -= 3 ; // added 5, removed 8
106+ } else {
107+ // only 0, 1, or 2 carry bits, plus 5 new ones
108+ carry += curr_in_as_u8 << carry_bits;
109+ carry_bits += 5 ;
79110 }
80111 }
81- // Trim the highest feature bits.
82- while !res_bytes . is_empty ( ) && res_bytes [ res_bytes . len ( ) - 1 ] == 0 {
83- res_bytes . pop ( ) ;
112+ // No more inputs, output remaining (if any)
113+ if carry_bits > 0 {
114+ output . push ( carry ) ;
84115 }
85- Ok ( Bolt11InvoiceFeatures :: from_le_bytes ( res_bytes) )
116+ // Trim the highest feature bits
117+ while !output. is_empty ( ) && output[ output. len ( ) - 1 ] == 0 {
118+ output. pop ( ) ;
119+ }
120+ Ok ( Bolt11InvoiceFeatures :: from_le_bytes ( output) )
86121 }
87122}
88123
@@ -342,7 +377,7 @@ impl FromStr for SignedRawBolt11Invoice {
342377 }
343378
344379 let raw_hrp: RawHrp = hrp. to_string ( ) . to_lowercase ( ) . parse ( ) ?;
345- let data_part = RawDataPart :: from_base32 ( & data[ ..data. len ( ) - SIGNATURE_LEN5 ] ) ?;
380+ let data_part = RawDataPart :: from_base32 ( & data[ ..data. len ( ) - SIGNATURE_LEN5 ] ) ?;
346381
347382 Ok ( SignedRawBolt11Invoice {
348383 raw_invoice : RawBolt11Invoice {
@@ -351,9 +386,9 @@ impl FromStr for SignedRawBolt11Invoice {
351386 } ,
352387 hash : RawBolt11Invoice :: hash_from_parts (
353388 hrp. to_string ( ) . as_bytes ( ) ,
354- & data[ ..data. len ( ) - SIGNATURE_LEN5 ]
389+ & data[ ..data. len ( ) - SIGNATURE_LEN5 ] ,
355390 ) ,
356- signature : Bolt11InvoiceSignature :: from_base32 ( & data[ data. len ( ) - SIGNATURE_LEN5 ..] ) ?,
391+ signature : Bolt11InvoiceSignature :: from_base32 ( & data[ data. len ( ) - SIGNATURE_LEN5 ..] ) ?,
357392 } )
358393 }
359394}
@@ -415,7 +450,11 @@ impl FromBase32 for PositiveTimestamp {
415450
416451 fn from_base32 ( b32 : & [ Fe32 ] ) -> Result < Self , Self :: Err > {
417452 if b32. len ( ) != 7 {
418- return Err ( Bolt11ParseError :: InvalidSliceLength ( "PositiveTimestamp::from_base32()" . into ( ) ) ) ;
453+ return Err ( Bolt11ParseError :: InvalidSliceLength (
454+ b32. len ( ) ,
455+ 7 ,
456+ "PositiveTimestamp::from_base32()" . into ( ) ,
457+ ) ) ;
419458 }
420459 let timestamp: u64 = parse_u64_be ( b32)
421460 . expect ( "7*5bit < 64bit, no overflow possible" ) ;
@@ -430,7 +469,11 @@ impl FromBase32 for Bolt11InvoiceSignature {
430469 type Err = Bolt11ParseError ;
431470 fn from_base32 ( signature : & [ Fe32 ] ) -> Result < Self , Self :: Err > {
432471 if signature. len ( ) != 104 {
433- return Err ( Bolt11ParseError :: InvalidSliceLength ( "Bolt11InvoiceSignature::from_base32()" . into ( ) ) ) ;
472+ return Err ( Bolt11ParseError :: InvalidSliceLength (
473+ signature. len ( ) ,
474+ 104 ,
475+ "Bolt11InvoiceSignature::from_base32()" . into ( ) ,
476+ ) ) ;
434477 }
435478 let recoverable_signature_bytes = Vec :: < u8 > :: from_base32 ( signature) ?;
436479 let signature = & recoverable_signature_bytes[ 0 ..64 ] ;
@@ -483,7 +526,9 @@ fn parse_tagged_parts(data: &[Fe32]) -> Result<Vec<RawTaggedField>, Bolt11ParseE
483526 Ok ( field) => {
484527 parts. push ( RawTaggedField :: KnownSemantics ( field) )
485528 } ,
486- Err ( Bolt11ParseError :: Skip ) |Err ( Bolt11ParseError :: Bech32Error ( _) ) => {
529+ Err ( Bolt11ParseError :: Skip )
530+ | Err ( Bolt11ParseError :: InvalidSliceLength ( _, _, _) )
531+ | Err ( Bolt11ParseError :: Bech32Error ( _) ) => {
487532 parts. push ( RawTaggedField :: UnknownSemantics ( field. into ( ) ) )
488533 } ,
489534 Err ( e) => { return Err ( e) }
@@ -688,9 +733,6 @@ impl Display for Bolt11ParseError {
688733 Bolt11ParseError :: Bech32Error ( ref e) => {
689734 write ! ( f, "Invalid bech32: {}" , e)
690735 }
691- Bolt11ParseError :: GenericBech32Error => {
692- write ! ( f, "Invalid bech32" )
693- }
694736 Bolt11ParseError :: ParseAmountError ( ref e) => {
695737 write ! ( f, "Invalid amount in hrp ({})" , e)
696738 }
@@ -700,9 +742,13 @@ impl Display for Bolt11ParseError {
700742 Bolt11ParseError :: DescriptionDecodeError ( ref e) => {
701743 write ! ( f, "Description is not a valid utf-8 string: {}" , e)
702744 }
703- Bolt11ParseError :: InvalidSliceLength ( ref function) => {
704- write ! ( f, "Slice in function {} had the wrong length" , function)
705- }
745+ Bolt11ParseError :: InvalidSliceLength ( ref len, ref expected, ref function) => {
746+ write ! (
747+ f,
748+ "Slice had length {} instead of {} in function {}" ,
749+ len, expected, function
750+ )
751+ } ,
706752 Bolt11ParseError :: BadPrefix => f. write_str ( "did not begin with 'ln'" ) ,
707753 Bolt11ParseError :: UnknownCurrency => f. write_str ( "currency code unknown" ) ,
708754 Bolt11ParseError :: UnknownSiPrefix => f. write_str ( "unknown SI prefix" ) ,
@@ -767,9 +813,7 @@ from_error!(Bolt11ParseError::DescriptionDecodeError, str::Utf8Error);
767813
768814impl From < CheckedHrpstringError > for Bolt11ParseError {
769815 fn from ( e : CheckedHrpstringError ) -> Self {
770- match e {
771- _ => Bolt11ParseError :: Bech32Error ( e)
772- }
816+ Self :: Bech32Error ( e)
773817 }
774818}
775819
0 commit comments