use core::fmt;
use crate::primitives::gf32::Fe32;
pub const MAX_STRING_LENGTH: usize = 90;
pub const VERSION_0: Fe32 = Fe32::Q;
pub const VERSION_1: Fe32 = Fe32::P;
pub fn is_valid_witness_version(witness_version: Fe32) -> bool {
validate_witness_version(witness_version).is_ok()
}
pub fn is_valid_witness_program_length(length: usize, witness_version: Fe32) -> bool {
validate_witness_program_length(length, witness_version).is_ok()
}
pub fn validate_witness_version(witness_version: Fe32) -> Result<(), InvalidWitnessVersionError> {
if witness_version.to_u8() > 16 {
Err(InvalidWitnessVersionError(witness_version))
} else {
Ok(())
}
}
pub fn validate_witness_program_length(
length: usize,
version: Fe32,
) -> Result<(), WitnessLengthError> {
use WitnessLengthError::*;
if length < 2 {
return Err(TooShort);
}
if length > 40 {
return Err(TooLong);
}
if version == VERSION_0 && length != 20 && length != 32 {
return Err(InvalidSegwitV0);
}
Ok(())
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct InvalidWitnessVersionError(pub Fe32);
#[rustfmt::skip]
impl fmt::Display for InvalidWitnessVersionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "invalid segwit witness version: {} (bech32 character: '{}')", self.0.to_u8(), self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidWitnessVersionError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum WitnessLengthError {
TooShort,
TooLong,
InvalidSegwitV0,
}
impl fmt::Display for WitnessLengthError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use WitnessLengthError::*;
match *self {
TooShort => write!(f, "witness program is less than 2 bytes long"),
TooLong => write!(f, "witness program is more than 40 bytes long"),
InvalidSegwitV0 => write!(f, "the segwit v0 witness is not 20 or 32 bytes long"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for WitnessLengthError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use WitnessLengthError::*;
match *self {
TooShort | TooLong | InvalidSegwitV0 => None,
}
}
}