Skip to content

Commit

Permalink
Convert HRP to lowercase for encoding purposes (#41)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
clarkmoody committed Jan 3, 2020
1 parent 16bbf7e commit ccbb003
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bech32"
version = "0.7.1"
version = "0.7.2"
authors = ["Clark Moody"]
repository = "https://github.com/rust-bitcoin/rust-bech32"
description = "Encodes and decodes the Bech32 format"
Expand Down
35 changes: 26 additions & 9 deletions src/lib.rs
Expand Up @@ -53,6 +53,7 @@
#![cfg_attr(feature = "strict", deny(warnings))]

use std::{error, fmt};
use std::borrow::Cow;

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

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

fn check_base32(self) -> Result<Vec<u5>, Self::Err> {
self.as_ref().iter().map(|x| u5::try_from_u8(*x)).collect::<Result<Vec<u5>, Error>>()
self.as_ref()
.iter()
.map(|x| u5::try_from_u8(*x))
.collect::<Result<Vec<u5>, Error>>()
}
}

Expand All @@ -331,7 +335,6 @@ enum Case {
}

/// Check if the HRP is valid. Returns the case of the HRP, if any.
/// True for uppercase, false for lowercase, None for only digits.
///
/// # Errors
/// * **MixedCase**: If the HRP contains both uppercase and lowercase characters.
Expand Down Expand Up @@ -381,14 +384,18 @@ pub fn encode_to_fmt<T: AsRef<[u5]>>(
hrp: &str,
data: T,
) -> Result<fmt::Result, Error> {
check_hrp(&hrp)?;
match Bech32Writer::new(hrp, fmt) {
let hrp_lower = match check_hrp(&hrp)? {
Case::Upper => Cow::Owned(hrp.to_lowercase()),
Case::Lower | Case::None => Cow::Borrowed(hrp),
};

match Bech32Writer::new(&hrp_lower, fmt) {
Ok(mut writer) => {
Ok(writer.write(data.as_ref()).and_then(|_| {
// Finalize manually to avoid panic on drop if write fails
writer.finalize()
}))
},
}
Err(e) => Ok(Err(e)),
}
}
Expand Down Expand Up @@ -802,8 +809,9 @@ mod tests {
}
}

let expected_rev_charset =
(0u8..128).map(|i| get_char_value(i as char)).collect::<Vec<_>>();
let expected_rev_charset = (0u8..128)
.map(|i| get_char_value(i as char))
.collect::<Vec<_>>();

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

assert_eq!(encoded_str, written_str);
}

#[test]
fn test_hrp_case() {
// Tests for issue with HRP case checking being ignored for encoding
use ToBase32;
let encoded_str = encode("HRP", [0x00, 0x00].to_base32()).unwrap();

assert_eq!(encoded_str, "hrp1qqqq40atq3");
}
}

0 comments on commit ccbb003

Please sign in to comment.