Skip to content

Commit ccbb003

Browse files
authored
Convert HRP to lowercase for encoding purposes (#41)
* Convert HRP to lowercase for encoding purposes Some cargo fmt suggestions Fixes #40 * Bump version to 0.7.2 * Use Cow to avoid string allocation
1 parent 16bbf7e commit ccbb003

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bech32"
3-
version = "0.7.1"
3+
version = "0.7.2"
44
authors = ["Clark Moody"]
55
repository = "https://github.com/rust-bitcoin/rust-bech32"
66
description = "Encodes and decodes the Bech32 format"

src/lib.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#![cfg_attr(feature = "strict", deny(warnings))]
5454

5555
use std::{error, fmt};
56+
use std::borrow::Cow;
5657

5758
// AsciiExt is needed for Rust 1.14 but not for newer versions
5859
#[allow(unused_imports, deprecated)]
@@ -245,7 +246,7 @@ pub trait ToBase32 {
245246
}
246247

247248
/// Interface to calculate the length of the base32 representation before actually serializing
248-
pub trait Base32Len : ToBase32 {
249+
pub trait Base32Len: ToBase32 {
249250
/// Calculate the base32 serialized length
250251
fn base32_len(&self) -> usize;
251252
}
@@ -264,7 +265,7 @@ impl<T: AsRef<[u8]>> ToBase32 for T {
264265
// buffer holds too many bits, so we don't have to combine buffer bits with new bits
265266
// from this rounds byte.
266267
if buffer_bits >= 5 {
267-
writer.write_u5(u5((buffer & 0b11111000) >> 3 ))?;
268+
writer.write_u5(u5((buffer & 0b11111000) >> 3))?;
268269
buffer = buffer << 5;
269270
buffer_bits -= 5;
270271
}
@@ -319,7 +320,10 @@ impl<'f, T: AsRef<[u8]>> CheckBase32<Vec<u5>> for T {
319320
type Err = Error;
320321

321322
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>>()
323327
}
324328
}
325329

@@ -331,7 +335,6 @@ enum Case {
331335
}
332336

333337
/// 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.
335338
///
336339
/// # Errors
337340
/// * **MixedCase**: If the HRP contains both uppercase and lowercase characters.
@@ -381,14 +384,18 @@ pub fn encode_to_fmt<T: AsRef<[u5]>>(
381384
hrp: &str,
382385
data: T,
383386
) -> 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) {
386393
Ok(mut writer) => {
387394
Ok(writer.write(data.as_ref()).and_then(|_| {
388395
// Finalize manually to avoid panic on drop if write fails
389396
writer.finalize()
390397
}))
391-
},
398+
}
392399
Err(e) => Ok(Err(e)),
393400
}
394401
}
@@ -802,8 +809,9 @@ mod tests {
802809
}
803810
}
804811

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<_>>();
807815

808816
assert_eq!(&(CHARSET_REV[..]), expected_rev_charset.as_slice());
809817
}
@@ -840,4 +848,13 @@ mod tests {
840848

841849
assert_eq!(encoded_str, written_str);
842850
}
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+
}
843860
}

0 commit comments

Comments
 (0)