Skip to content

Commit

Permalink
Merge #164: Make from_char_unchecked public
Browse files Browse the repository at this point in the history
ca2f840 Make from_char_unchecked public (Tobin C. Harding)
b7767ee Split gf32::Error (Tobin C. Harding)

Pull request description:

  - Patch 1 is an error type clean up, part of this PR because it improves the error type returned by `from_char`.
  - Patch 2 documents the error return of `from_char` and makes `from_char_unchecked` public.

  Fix: #161

ACKs for top commit:
  apoelstra:
    ACK ca2f840

Tree-SHA512: 758c7d9bdb5f5ac1e24b379376f87caf0a0ee2af32409ac4c7e1e009b822c7ee400d69c2cf991472e06acf4bd27e7d93521d08565f319fc125b48fe386f7b3f8
  • Loading branch information
apoelstra committed Jan 8, 2024
2 parents c5c028e + ca2f840 commit 6d489a7
Showing 1 changed file with 60 additions and 19 deletions.
79 changes: 60 additions & 19 deletions src/primitives/gf32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,30 @@ impl Fe32 {
}

/// Creates a field element from a single bech32 character.
///
/// # Errors
///
/// If the input char is not part of the bech32 alphabet.
#[inline]
pub fn from_char(c: char) -> Result<Fe32, Error> {
pub fn from_char(c: char) -> Result<Fe32, FromCharError> {
use FromCharError::*;

// i8::try_from gets a value in the range 0..=127 since char is unsigned.
let byte = i8::try_from(u32::from(c)).map_err(|_| Error::InvalidChar(c))?;
let byte = i8::try_from(u32::from(c)).map_err(|_| NotAscii(c))?;
// Now we have a valid ASCII value cast is safe.
let ascii = byte as usize;
// We use -1 for any array element that is an invalid char to trigger error from u8::try_from
let u5 = u8::try_from(CHARS_INV[ascii]).map_err(|_| Error::InvalidChar(c))?;
let u5 = u8::try_from(CHARS_INV[ascii]).map_err(|_| Invalid(c))?;

Ok(Fe32(u5))
}

pub(crate) fn from_char_unchecked(c: u8) -> Fe32 { Fe32(CHARS_INV[usize::from(c)] as u8) }
/// Creates a field element from a single bech32 character.
///
/// # Panics
///
/// If the input character is not part of the bech32 alphabet.
pub fn from_char_unchecked(c: u8) -> Fe32 { Fe32(CHARS_INV[usize::from(c)] as u8) }

/// Converts the field element to a lowercase bech32 character.
#[inline]
Expand Down Expand Up @@ -245,7 +257,7 @@ macro_rules! impl_try_from {
($($ty:ident)+) => {
$(
impl TryFrom<$ty> for Fe32 {
type Error = Error;
type Error = TryFromError;

/// Tries to create an [`Fe32`] type from a signed source number type.
///
Expand All @@ -256,7 +268,7 @@ macro_rules! impl_try_from {
fn try_from(value: $ty) -> Result<Self, Self::Error> {
let byte = u8::try_from(value)?;
if byte > 31 {
Err(Error::InvalidByte(byte))?;
Err(TryFromError::InvalidByte(byte))?;
}
Ok(Fe32(byte))
}
Expand Down Expand Up @@ -324,48 +336,77 @@ impl ops::DivAssign for Fe32 {
fn div_assign(&mut self, other: Fe32) { *self = *self / other; }
}

/// A galois field related error.
/// A galois field error when converting from a character.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum FromCharError {
/// Tried to interpret a character as a GF32 element but it is not an ASCII character.
NotAscii(char),
/// Tried to interpret a character as a GF32 element but it is not part of the bech32 character set.
Invalid(char),
}

impl fmt::Display for FromCharError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use FromCharError::*;

match *self {
NotAscii(c) => write!(f, "non-ascii char in field element: {}", c),
Invalid(c) => write!(f, "invalid char in field element: {}", c),
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for FromCharError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use FromCharError::*;

match *self {
NotAscii(_) | Invalid(_) => None,
}
}
}

/// A galois field error when converting from an integer.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum Error {
pub enum TryFromError {
/// Tried to interpret an integer as a GF32 element but it could not be converted to an u8.
NotAByte(num::TryFromIntError),
/// Tried to interpret a byte as a GF32 element but its numeric value was outside of [0, 32).
InvalidByte(u8),
/// Tried to interpret a character as a GF32 element but it is not part of the bech32 character set.
InvalidChar(char),
}

impl fmt::Display for Error {
impl fmt::Display for TryFromError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Error::*;
use TryFromError::*;

match *self {
NotAByte(ref e) => write_err!(f, "invalid field element"; e),
InvalidByte(ref b) => write!(f, "invalid byte in field element: {:#04x}", b),
InvalidChar(ref c) => write!(f, "invalid char in field element: {}", c),
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {
impl std::error::Error for TryFromError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use Error::*;
use TryFromError::*;

match *self {
NotAByte(ref e) => Some(e),
InvalidByte(_) | InvalidChar(_) => None,
InvalidByte(_) => None,
}
}
}

impl From<num::TryFromIntError> for Error {
impl From<num::TryFromIntError> for TryFromError {
#[inline]
fn from(e: num::TryFromIntError) -> Self { Error::NotAByte(e) }
fn from(e: num::TryFromIntError) -> Self { Self::NotAByte(e) }
}

impl From<Infallible> for Error {
impl From<Infallible> for TryFromError {
#[inline]
fn from(i: Infallible) -> Self { match i {} }
}
Expand Down

0 comments on commit 6d489a7

Please sign in to comment.