Skip to content

Commit 22f2052

Browse files
committed
use new Fe32 type in place of gf32
This requires dropping `Ord` impls from the error types, but IMHO these didn't really make sense anyway. This also keeps the `u5` name. We will rename this in a later PR which replaces the *Base32 traits with iterator adaptors, since at that point there will be a much smaller API surface to change.
1 parent 7d96456 commit 22f2052

File tree

2 files changed

+20
-157
lines changed

2 files changed

+20
-157
lines changed

src/lib.rs

Lines changed: 19 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -59,78 +59,7 @@ pub mod primitives;
5959

6060
#[cfg(feature = "arrayvec")]
6161
use arrayvec::{ArrayVec, CapacityError};
62-
63-
/// Integer in the range `0..32`.
64-
#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, PartialOrd, Ord, Hash)]
65-
#[allow(non_camel_case_types)]
66-
pub struct u5(u8);
67-
68-
impl u5 {
69-
/// Returns a copy of the underlying `u8` value.
70-
pub fn to_u8(self) -> u8 { self.0 }
71-
72-
/// Gets a character representing this 5 bit value as defined in BIP173.
73-
pub fn to_char(self) -> char { CHARSET[self.to_u8() as usize] }
74-
}
75-
76-
impl From<u5> for u8 {
77-
fn from(v: u5) -> u8 { v.0 }
78-
}
79-
80-
macro_rules! impl_try_from_upper_bounded {
81-
($($ty:ident)+) => {
82-
$(
83-
impl TryFrom<$ty> for u5 {
84-
type Error = TryFromIntError;
85-
86-
/// Tries to create the target number type from a source number type.
87-
///
88-
/// # Errors
89-
///
90-
/// Returns an error if `value` overflows a `u5`.
91-
fn try_from(value: $ty) -> Result<Self, Self::Error> {
92-
if value > 31 {
93-
Err(TryFromIntError::PosOverflow)
94-
} else {
95-
let x = u8::try_from(value).expect("within range");
96-
Ok(u5(x))
97-
}
98-
}
99-
}
100-
)+
101-
}
102-
}
103-
macro_rules! impl_try_from_both_bounded {
104-
($($ty:ident)+) => {
105-
$(
106-
impl TryFrom<$ty> for u5 {
107-
type Error = TryFromIntError;
108-
109-
/// Tries to create the target number type from a source number type.
110-
///
111-
/// # Errors
112-
///
113-
/// Returns an error if `value` is outside of the range of a `u5`.
114-
fn try_from(value: $ty) -> Result<Self, Self::Error> {
115-
if value < 0 {
116-
Err(TryFromIntError::NegOverflow)
117-
} else if value > 31 {
118-
Err(TryFromIntError::PosOverflow)
119-
} else {
120-
let x = u8::try_from(value).expect("within range");
121-
Ok(u5(x))
122-
}
123-
}
124-
}
125-
)+
126-
}
127-
}
128-
impl_try_from_upper_bounded!(u8 u16 u32 u64 u128);
129-
impl_try_from_both_bounded!(i8 i16 i32 i64 i128);
130-
131-
impl AsRef<u8> for u5 {
132-
fn as_ref(&self) -> &u8 { &self.0 }
133-
}
62+
pub use primitives::gf32::Fe32 as u5;
13463

13564
/// Interface to write `u5`s into a sink.
13665
pub trait WriteBase32 {
@@ -306,7 +235,7 @@ write_base_n! { WriteBase32, u5, write_u5 }
306235
write_base_n! { WriteBase256, u8, write_u8 }
307236

308237
#[cfg(feature = "arrayvec")]
309-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
238+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
310239
/// Combination of Errors for use with array vec
311240
pub enum ComboError {
312241
/// Error from this crate
@@ -712,13 +641,6 @@ fn split_and_decode(s: &str) -> Result<(String, Vec<u5>), Error> {
712641
let data = raw_data
713642
.chars()
714643
.map(|c| {
715-
// Only check if c is in the ASCII range, all invalid ASCII
716-
// characters have the value -1 in CHARSET_REV (which covers
717-
// the whole ASCII range) and will be filtered out later.
718-
if !c.is_ascii() {
719-
return Err(Error::InvalidChar(c));
720-
}
721-
722644
if c.is_lowercase() {
723645
match case {
724646
Case::Upper => return Err(Error::MixedCase),
@@ -732,15 +654,7 @@ fn split_and_decode(s: &str) -> Result<(String, Vec<u5>), Error> {
732654
Case::Upper => {}
733655
}
734656
}
735-
736-
// c should be <128 since it is in the ASCII range, CHARSET_REV.len() == 128
737-
let num_value = CHARSET_REV[c as usize];
738-
739-
if !(0..=31).contains(&num_value) {
740-
return Err(Error::InvalidChar(c));
741-
}
742-
743-
Ok(u5::try_from(num_value as u8).expect("range checked above, num_value <= 31"))
657+
u5::from_char(c).map_err(Error::TryFrom)
744658
})
745659
.collect::<Result<Vec<u5>, Error>>()?;
746660

@@ -788,28 +702,11 @@ where
788702

789703
// Check data payload
790704
for c in raw_data.chars() {
791-
// Only check if c is in the ASCII range, all invalid ASCII
792-
// characters have the value -1 in CHARSET_REV (which covers
793-
// the whole ASCII range) and will be filtered out later.
794-
if !c.is_ascii() {
795-
Err(Error::InvalidChar(c))?;
796-
}
797-
798705
match case {
799706
Case::Upper => Err(Error::MixedCase)?,
800707
Case::None | Case::Lower => {}
801708
}
802-
803-
// c should be <128 since it is in the ASCII range, CHARSET_REV.len() == 128
804-
let num_value = CHARSET_REV[c as usize];
805-
806-
if !(0..32).contains(&num_value) {
807-
Err(Error::InvalidChar(c))?;
808-
}
809-
810-
data.write_u5(
811-
u5::try_from(num_value as u8).expect("range checked above, num_value <= 31"),
812-
)?;
709+
data.write_u5(u5::from_char(c).map_err(Error::TryFrom)?)?;
813710
}
814711

815712
// Ensure checksum
@@ -868,29 +765,11 @@ fn polymod(values: &[u5]) -> u32 {
868765
/// Human-readable part and data part separator.
869766
const SEP: char = '1';
870767

871-
/// Encoding character set. Maps data value -> char
872-
const CHARSET: [char; 32] = [
873-
'q', 'p', 'z', 'r', 'y', '9', 'x', '8', // +0
874-
'g', 'f', '2', 't', 'v', 'd', 'w', '0', // +8
875-
's', '3', 'j', 'n', '5', '4', 'k', 'h', // +16
876-
'c', 'e', '6', 'm', 'u', 'a', '7', 'l', // +24
877-
];
878-
879-
/// Reverse character set. Maps ASCII byte -> CHARSET index on [0,31]
880-
const CHARSET_REV: [i8; 128] = [
881-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
882-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
883-
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,
884-
-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,
885-
-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,
886-
-1, -1, -1, -1,
887-
];
888-
889768
/// Generator coefficients
890769
const GEN: [u32; 5] = [0x3b6a_57b2, 0x2650_8e6d, 0x1ea1_19fa, 0x3d42_33dd, 0x2a14_62b3];
891770

892771
/// Error types for Bech32 encoding / decoding.
893-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
772+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
894773
pub enum Error {
895774
/// String does not contain the separator character.
896775
MissingSeparator,
@@ -907,7 +786,7 @@ pub enum Error {
907786
/// Attempted to convert a value which overflows a `u5`.
908787
Overflow,
909788
/// Conversion to u5 failed.
910-
TryFrom(TryFromIntError),
789+
TryFrom(primitives::gf32::Error),
911790
}
912791

913792
impl From<Infallible> for Error {
@@ -944,8 +823,8 @@ impl std::error::Error for Error {
944823
}
945824
}
946825

947-
impl From<TryFromIntError> for Error {
948-
fn from(e: TryFromIntError) -> Self { Error::TryFrom(e) }
826+
impl From<primitives::gf32::Error> for Error {
827+
fn from(e: primitives::gf32::Error) -> Self { Error::TryFrom(e) }
949828
}
950829

951830
/// Error return when `TryFrom<T>` fails for T -> u5 conversion.
@@ -1132,21 +1011,21 @@ mod tests {
11321011
(" 1nwldj5",
11331012
Error::InvalidChar(' ')),
11341013
("abc1\u{2192}axkwrx",
1135-
Error::InvalidChar('\u{2192}')),
1014+
Error::TryFrom(primitives::gf32::Error::InvalidChar('\u{2192}'))),
11361015
("an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
11371016
Error::InvalidLength),
11381017
("pzry9x0s0muk",
11391018
Error::MissingSeparator),
11401019
("1pzry9x0s0muk",
11411020
Error::InvalidLength),
11421021
("x1b4n0q5v",
1143-
Error::InvalidChar('b')),
1022+
Error::TryFrom(primitives::gf32::Error::InvalidChar('b'))),
11441023
("ABC1DEFGOH",
1145-
Error::InvalidChar('O')),
1024+
Error::TryFrom(primitives::gf32::Error::InvalidChar('O'))),
11461025
("li1dgmt3",
11471026
Error::InvalidLength),
11481027
("de1lg7wt\u{ff}",
1149-
Error::InvalidChar('\u{ff}')),
1028+
Error::TryFrom(primitives::gf32::Error::InvalidChar('\u{ff}'))),
11501029
("\u{20}1xj0phk",
11511030
Error::InvalidChar('\u{20}')),
11521031
("\u{7F}1g6xzxy",
@@ -1158,15 +1037,15 @@ mod tests {
11581037
("1qyrz8wqd2c9m",
11591038
Error::InvalidLength),
11601039
("y1b0jsk6g",
1161-
Error::InvalidChar('b')),
1040+
Error::TryFrom(primitives::gf32::Error::InvalidChar('b'))),
11621041
("lt1igcx5c0",
1163-
Error::InvalidChar('i')),
1042+
Error::TryFrom(primitives::gf32::Error::InvalidChar('i'))),
11641043
("in1muywd",
11651044
Error::InvalidLength),
11661045
("mm1crxm3i",
1167-
Error::InvalidChar('i')),
1046+
Error::TryFrom(primitives::gf32::Error::InvalidChar('i'))),
11681047
("au1s5cgom",
1169-
Error::InvalidChar('o')),
1048+
Error::TryFrom(primitives::gf32::Error::InvalidChar('o'))),
11701049
("M1VUXWEZ",
11711050
Error::InvalidChecksum),
11721051
("16plkw9",
@@ -1248,10 +1127,10 @@ mod tests {
12481127
assert!([0u8, 1, 2, 30, 31, 255].check_base32_vec().is_err());
12491128

12501129
assert!([1u8, 2, 3, 4].check_base32_vec().is_ok());
1251-
assert_eq!(
1130+
assert!(matches!(
12521131
[30u8, 31, 35, 20].check_base32_vec(),
1253-
Err(Error::TryFrom(TryFromIntError::PosOverflow))
1254-
)
1132+
Err(Error::TryFrom(primitives::gf32::Error::InvalidByte(35)))
1133+
));
12551134
}
12561135

12571136
#[test]
@@ -1279,22 +1158,6 @@ mod tests {
12791158
assert_eq!([0xffu8].to_base32(), [0x1f, 0x1c].check_base32_vec().unwrap());
12801159
}
12811160

1282-
#[test]
1283-
fn reverse_charset() {
1284-
fn get_char_value(c: char) -> i8 {
1285-
let charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
1286-
match charset.find(c.to_ascii_lowercase()) {
1287-
Some(x) => x as i8,
1288-
None => -1,
1289-
}
1290-
}
1291-
1292-
let expected_rev_charset =
1293-
(0u8..128).map(|i| get_char_value(i as char)).collect::<Vec<_>>();
1294-
1295-
assert_eq!(&(CHARSET_REV[..]), expected_rev_charset.as_slice());
1296-
}
1297-
12981161
#[test]
12991162
#[cfg(feature = "alloc")]
13001163
fn write_with_checksum() {

src/primitives/gf32.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ impl ops::DivAssign for Fe32 {
307307
}
308308

309309
/// A galois field related error.
310-
#[derive(Debug)]
310+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
311311
#[non_exhaustive]
312312
pub enum Error {
313313
/// Tried to interpret an integer as a GF32 element but it could not be converted to an u8.

0 commit comments

Comments
 (0)