From 59d6913066ebce9bed05f8669df1ead1a8f4bb82 Mon Sep 17 00:00:00 2001 From: Damian Poddebniak Date: Wed, 1 Jan 2020 16:06:23 +0100 Subject: [PATCH 1/5] Documentation * why is Bech32 used? * mention "1" as separator * refer explicitly to original description *for more details* --- src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ba0777c3..4b781211 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,18 +18,18 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -//! Encoding and decoding Bech32 format +//! Encoding and decoding of the Bech32 format //! -//! Bech32 is a 5-bit (base-32) encoding scheme that produces strings that comprise -//! a human-readable part, a separator, a data part, and a checksum. The encoding -//! implements a BCH code that guarantees error detection of up to four characters -//! with less than 1 in 1 billion chance of failing to detect more errors. +//! Bech32 is an encoding scheme that is easy to use for humans and efficient to encode in QR codes. //! -//! The Bech32 encoding was originally formulated in [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) +//! A Bech32 string consists of a human-readable part (HRP), a separator (the character `'1'`), and a data part. +//! A checksum at the end of the string provides error detection to prevent mistakes when the string is written off or read out loud. +//! +//! The original description in [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) has more details. //! //! # Examples //! -//! ```rust +//! ``` //! use bech32::{self, FromBase32, ToBase32}; //! //! let encoded = bech32::encode("bech32", vec![0x00, 0x01, 0x02].to_base32()).unwrap(); From 778b0eb61b23b05f85a4d2978865e97b32283500 Mon Sep 17 00:00:00 2001 From: Damian Poddebniak Date: Wed, 1 Jan 2020 16:20:06 +0100 Subject: [PATCH 2/5] cargo clippy --- src/lib.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4b781211..ac77b335 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,12 +75,12 @@ impl u5 { } /// Returns a copy of the underlying `u8` value - pub fn to_u8(&self) -> u8 { + pub fn to_u8(self) -> u8 { self.0 } /// Get char representing this 5 bit value as defined in BIP173 - pub fn to_char(&self) -> char { + pub fn to_char(self) -> char { CHARSET[self.to_u8() as usize] } } @@ -149,10 +149,11 @@ impl<'a> Bech32Writer<'a> { fn polymod_step(&mut self, v: u5) { let b = (self.chk >> 25) as u8; - self.chk = (self.chk & 0x1ffffff) << 5 ^ (u32::from(*v.as_ref())); - for i in 0..5 { + self.chk = (self.chk & 0x01ff_ffff) << 5 ^ (u32::from(*v.as_ref())); + + for (i, item) in GEN.iter().enumerate() { if (b >> i) & 1 == 1 { - self.chk ^= GEN[i] + self.chk ^= item; } } } @@ -265,8 +266,9 @@ impl> 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))?; - buffer = buffer << 5; + + writer.write_u5(u5((buffer & 0b1111_1000) >> 3 ))?; + buffer <<= 5; buffer_bits -= 5; } @@ -277,13 +279,13 @@ impl> ToBase32 for T { writer.write_u5(u5(from_buffer | from_byte))?; buffer = b << (5 - buffer_bits); - buffer_bits = 3 + buffer_bits; + buffer_bits += 3; } // There can be at most two u5s left in the buffer after processing all bytes, write them. if buffer_bits >= 5 { - writer.write_u5(u5((buffer & 0b11111000) >> 3))?; - buffer = buffer << 5; + writer.write_u5(u5((buffer & 0b1111_1000) >> 3))?; + buffer <<= 5; buffer_bits -= 5; } @@ -511,10 +513,11 @@ fn polymod(values: &[u5]) -> u32 { let mut b: u8; for v in values { b = (chk >> 25) as u8; - chk = (chk & 0x1ffffff) << 5 ^ (u32::from(*v.as_ref())); - for i in 0..5 { + chk = (chk & 0x01ff_ffff) << 5 ^ (u32::from(*v.as_ref())); + + for (i, item) in GEN.iter().enumerate() { if (b >> i) & 1 == 1 { - chk ^= GEN[i] + chk ^= item; } } } @@ -545,7 +548,7 @@ const CHARSET_REV: [i8; 128] = [ ]; /// Generator coefficients -const GEN: [u32; 5] = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; +const GEN: [u32; 5] = [0x3b6a_57b2, 0x2650_8e6d, 0x1ea1_19fa, 0x3d42_33dd, 0x2a14_62b3]; /// Error types for Bech32 encoding / decoding #[derive(Copy, Clone, PartialEq, Debug)] From bf159c8adcd70455cca8069e1595fcc3dd3cc5de Mon Sep 17 00:00:00 2001 From: Damian Poddebniak Date: Wed, 1 Jan 2020 17:19:02 +0100 Subject: [PATCH 3/5] rustfmt --- src/lib.rs | 55 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ac77b335..f2306352 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,6 @@ // Allow trait objects without dyn on nightly and make 1.22 ignore the unknown lint #![allow(unknown_lints)] #![allow(bare_trait_objects)] - #![deny(missing_docs)] #![deny(non_upper_case_globals)] #![deny(non_camel_case_types)] @@ -150,7 +149,7 @@ impl<'a> Bech32Writer<'a> { fn polymod_step(&mut self, v: u5) { let b = (self.chk >> 25) as u8; self.chk = (self.chk & 0x01ff_ffff) << 5 ^ (u32::from(*v.as_ref())); - + for (i, item) in GEN.iter().enumerate() { if (b >> i) & 1 == 1 { self.chk ^= item; @@ -174,9 +173,8 @@ impl<'a> Bech32Writer<'a> { let plm: u32 = self.chk ^ 1; for p in 0..6 { - self.formatter.write_char( - u5(((plm >> (5 * (5 - p))) & 0x1f) as u8).to_char() - )?; + self.formatter + .write_char(u5(((plm >> (5 * (5 - p))) & 0x1f) as u8).to_char())?; } Ok(()) @@ -194,7 +192,8 @@ impl<'a> WriteBase32 for Bech32Writer<'a> { impl<'a> Drop for Bech32Writer<'a> { fn drop(&mut self) { - self.inner_finalize().expect("Unhandled error writing the checksum on drop.") + self.inner_finalize() + .expect("Unhandled error writing the checksum on drop.") } } @@ -266,8 +265,7 @@ impl> 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 & 0b1111_1000) >> 3 ))?; + writer.write_u5(u5((buffer & 0b1111_1000) >> 3))?; buffer <<= 5; buffer_bits -= 5; } @@ -528,6 +526,7 @@ fn polymod(values: &[u5]) -> u32 { const SEP: char = '1'; /// Encoding character set. Maps data value -> char +#[rustfmt::skip] const CHARSET: [char; 32] = [ 'q','p','z','r','y','9','x','8', 'g','f','2','t','v','d','w','0', @@ -536,6 +535,7 @@ const CHARSET: [char; 32] = [ ]; /// Reverse character set. Maps ASCII byte -> CHARSET index on [0,31] +#[rustfmt::skip] const CHARSET_REV: [i8; 128] = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -548,7 +548,13 @@ const CHARSET_REV: [i8; 128] = [ ]; /// Generator coefficients -const GEN: [u32; 5] = [0x3b6a_57b2, 0x2650_8e6d, 0x1ea1_19fa, 0x3d42_33dd, 0x2a14_62b3]; +const GEN: [u32; 5] = [ + 0x3b6a_57b2, + 0x2650_8e6d, + 0x1ea1_19fa, + 0x3d42_33dd, + 0x2a14_62b3, +]; /// Error types for Bech32 encoding / decoding #[derive(Copy, Clone, PartialEq, Debug)] @@ -672,7 +678,11 @@ mod tests { for s in strings { let decode_result = decode(s); if !decode_result.is_ok() { - panic!("Did not decode: {:?} Reason: {:?}", s, decode_result.unwrap_err()); + panic!( + "Did not decode: {:?} Reason: {:?}", + s, + decode_result.unwrap_err() + ); } assert!(decode_result.is_ok()); let decoded = decode_result.unwrap(); @@ -710,7 +720,12 @@ mod tests { println!("{:?}", dec_result.unwrap()); panic!("Should be invalid: {:?}", s); } - assert_eq!(dec_result.unwrap_err(), expected_error, "testing input '{}'", s); + assert_eq!( + dec_result.unwrap_err(), + expected_error, + "testing input '{}'", + s + ); } } @@ -723,7 +738,13 @@ mod tests { (vec![0x01], 8, 8, true, vec![0x01]), (vec![0x01], 8, 4, true, vec![0x00, 0x01]), (vec![0x01], 8, 2, true, vec![0x00, 0x00, 0x00, 0x01]), - (vec![0x01], 8, 1, true, vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]), + ( + vec![0x01], + 8, + 1, + true, + vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], + ), (vec![0xff], 8, 5, true, vec![0x1f, 0x1c]), (vec![0x1f, 0x1c], 5, 8, false, vec![0xff]), ]; @@ -773,7 +794,10 @@ mod tests { assert!([0u8, 1, 2, 30, 31, 255].check_base32().is_err()); assert!([1u8, 2, 3, 4].check_base32().is_ok()); - assert_eq!([30u8, 31, 35, 20].check_base32(), Err(Error::InvalidData(35))); + assert_eq!( + [30u8, 31, 35, 20].check_base32(), + Err(Error::InvalidData(35)) + ); } #[test] @@ -787,7 +811,10 @@ mod tests { #[test] fn from_base32() { use FromBase32; - assert_eq!(Vec::from_base32(&[0x1f, 0x1c].check_base32().unwrap()), Ok(vec![0xff])); + assert_eq!( + Vec::from_base32(&[0x1f, 0x1c].check_base32().unwrap()), + Ok(vec![0xff]) + ); assert_eq!( Vec::from_base32(&[0x1f, 0x1f].check_base32().unwrap()), Err(Error::InvalidPadding) From 9b17146f8cc5701c4d91e63d13ce5867396f15f9 Mon Sep 17 00:00:00 2001 From: Damian Poddebniak Date: Mon, 6 Jan 2020 15:51:54 +0100 Subject: [PATCH 4/5] removed rustfmt::skip --- src/lib.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f2306352..b12fc764 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,8 +51,8 @@ #![deny(unused_mut)] #![cfg_attr(feature = "strict", deny(warnings))] -use std::{error, fmt}; use std::borrow::Cow; +use std::{error, fmt}; // AsciiExt is needed for Rust 1.14 but not for newer versions #[allow(unused_imports, deprecated)] @@ -526,25 +526,21 @@ fn polymod(values: &[u5]) -> u32 { const SEP: char = '1'; /// Encoding character set. Maps data value -> char -#[rustfmt::skip] const CHARSET: [char; 32] = [ - 'q','p','z','r','y','9','x','8', - 'g','f','2','t','v','d','w','0', - 's','3','j','n','5','4','k','h', - 'c','e','6','m','u','a','7','l' + 'q', 'p', 'z', 'r', 'y', '9', 'x', '8', // +0 + 'g', 'f', '2', 't', 'v', 'd', 'w', '0', // +8 + 's', '3', 'j', 'n', '5', '4', 'k', 'h', // +16 + 'c', 'e', '6', 'm', 'u', 'a', '7', 'l', // +24 ]; /// Reverse character set. Maps ASCII byte -> CHARSET index on [0,31] -#[rustfmt::skip] const CHARSET_REV: [i8; 128] = [ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, + -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, -1, 29, + -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, + -1, -1, -1, -1, ]; /// Generator coefficients From 71e0c2a0b61710f7b4b50c158fcfb05601e20ade Mon Sep 17 00:00:00 2001 From: Sebastian Geisler Date: Sat, 11 Jan 2020 15:17:46 +0100 Subject: [PATCH 5/5] add automatic travis checks for formatting/clippy --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 11ff9939..16446d22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,14 @@ script: jobs: include: + - stage: best practices + rust: stable + install: + - rustup component add rustfmt + - rustup component add clippy + script: + - rustfmt --check src/lib.rs + - cargo clippy -- -D warnings - stage: fuzz before_install: - sudo apt-get -qq update