53
53
#![ cfg_attr( feature = "strict" , deny( warnings) ) ]
54
54
55
55
use std:: { error, fmt} ;
56
+ use std:: borrow:: Cow ;
56
57
57
58
// AsciiExt is needed for Rust 1.14 but not for newer versions
58
59
#[ allow( unused_imports, deprecated) ]
@@ -245,7 +246,7 @@ pub trait ToBase32 {
245
246
}
246
247
247
248
/// Interface to calculate the length of the base32 representation before actually serializing
248
- pub trait Base32Len : ToBase32 {
249
+ pub trait Base32Len : ToBase32 {
249
250
/// Calculate the base32 serialized length
250
251
fn base32_len ( & self ) -> usize ;
251
252
}
@@ -264,7 +265,7 @@ impl<T: AsRef<[u8]>> ToBase32 for T {
264
265
// buffer holds too many bits, so we don't have to combine buffer bits with new bits
265
266
// from this rounds byte.
266
267
if buffer_bits >= 5 {
267
- writer. write_u5 ( u5 ( ( buffer & 0b11111000 ) >> 3 ) ) ?;
268
+ writer. write_u5 ( u5 ( ( buffer & 0b11111000 ) >> 3 ) ) ?;
268
269
buffer = buffer << 5 ;
269
270
buffer_bits -= 5 ;
270
271
}
@@ -319,7 +320,10 @@ impl<'f, T: AsRef<[u8]>> CheckBase32<Vec<u5>> for T {
319
320
type Err = Error ;
320
321
321
322
fn check_base32 ( self ) -> Result < Vec < u5 > , Self :: Err > {
322
- self . as_ref ( ) . iter ( ) . map ( |x| u5:: try_from_u8 ( * x) ) . collect :: < Result < Vec < u5 > , Error > > ( )
323
+ self . as_ref ( )
324
+ . iter ( )
325
+ . map ( |x| u5:: try_from_u8 ( * x) )
326
+ . collect :: < Result < Vec < u5 > , Error > > ( )
323
327
}
324
328
}
325
329
@@ -331,7 +335,6 @@ enum Case {
331
335
}
332
336
333
337
/// Check if the HRP is valid. Returns the case of the HRP, if any.
334
- /// True for uppercase, false for lowercase, None for only digits.
335
338
///
336
339
/// # Errors
337
340
/// * **MixedCase**: If the HRP contains both uppercase and lowercase characters.
@@ -381,14 +384,18 @@ pub fn encode_to_fmt<T: AsRef<[u5]>>(
381
384
hrp : & str ,
382
385
data : T ,
383
386
) -> Result < fmt:: Result , Error > {
384
- check_hrp ( & hrp) ?;
385
- match Bech32Writer :: new ( hrp, fmt) {
387
+ let hrp_lower = match check_hrp ( & hrp) ? {
388
+ Case :: Upper => Cow :: Owned ( hrp. to_lowercase ( ) ) ,
389
+ Case :: Lower | Case :: None => Cow :: Borrowed ( hrp) ,
390
+ } ;
391
+
392
+ match Bech32Writer :: new ( & hrp_lower, fmt) {
386
393
Ok ( mut writer) => {
387
394
Ok ( writer. write ( data. as_ref ( ) ) . and_then ( |_| {
388
395
// Finalize manually to avoid panic on drop if write fails
389
396
writer. finalize ( )
390
397
} ) )
391
- } ,
398
+ }
392
399
Err ( e) => Ok ( Err ( e) ) ,
393
400
}
394
401
}
@@ -802,8 +809,9 @@ mod tests {
802
809
}
803
810
}
804
811
805
- let expected_rev_charset =
806
- ( 0u8 ..128 ) . map ( |i| get_char_value ( i as char ) ) . collect :: < Vec < _ > > ( ) ;
812
+ let expected_rev_charset = ( 0u8 ..128 )
813
+ . map ( |i| get_char_value ( i as char ) )
814
+ . collect :: < Vec < _ > > ( ) ;
807
815
808
816
assert_eq ! ( & ( CHARSET_REV [ ..] ) , expected_rev_charset. as_slice( ) ) ;
809
817
}
@@ -840,4 +848,13 @@ mod tests {
840
848
841
849
assert_eq ! ( encoded_str, written_str) ;
842
850
}
851
+
852
+ #[ test]
853
+ fn test_hrp_case ( ) {
854
+ // Tests for issue with HRP case checking being ignored for encoding
855
+ use ToBase32 ;
856
+ let encoded_str = encode ( "HRP" , [ 0x00 , 0x00 ] . to_base32 ( ) ) . unwrap ( ) ;
857
+
858
+ assert_eq ! ( encoded_str, "hrp1qqqq40atq3" ) ;
859
+ }
843
860
}
0 commit comments