accumulators 0.5.1

Complete package of multiple Accumulators with Stores and hashing functions (Hashers)
use starknet::core::types::FromStrError;
use std::{
    fmt::{self, Debug},
    str::FromStr,
};
use strum_macros::EnumIter;
use thiserror::Error;

/// Hasher error
#[derive(Error, Debug)]
pub enum HasherError {
    #[error("Invalid hashing function")]
    InvalidHashingFunction,
    #[error(
        "Element size {element_size} is too big for hashing function with block size {block_size_bits}"
    )]
    InvalidElementSize {
        element_size: usize,
        block_size_bits: usize,
    },
    #[error("Invalid elements length for hashing function")]
    InvalidElementsLength,
    #[error("Fail to decode hex")]
    HexDecodeError(#[from] hex::FromHexError),
    #[error("Fail to convert to felt")]
    FeltConversionError(#[from] FromStrError),
}

/// A trait for hash functions
pub trait Hasher: Send + Sync + Debug {
    /// Hashes a data which is a vector of strings
    fn hash(&self, data: Vec<String>) -> Result<String, HasherError>;

    /// Checks if the element size is valid, i.e. if it is less than the block size
    fn is_element_size_valid(&self, element: &str) -> Result<bool, HasherError>;

    /// Hashes a single element
    fn hash_single(&self, data: &str) -> Result<String, HasherError>;

    /// Returns the genesis hash
    fn get_genesis(&self) -> Result<String, HasherError>;

    /// Returns the name of the [`HashingFunction`]
    fn get_name(&self) -> HashingFunction;

    /// Returns the block size in bits
    fn get_block_size_bits(&self) -> usize;
}

/// Hashing functions types supported by the hasher
#[derive(EnumIter, Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum HashingFunction {
    Keccak256,
    Poseidon,
    Pedersen,
    Blake,
}

impl FromStr for HashingFunction {
    type Err = HasherError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "keccak" => Ok(HashingFunction::Keccak256),
            "poseidon" => Ok(HashingFunction::Poseidon),
            "pedersen" => Ok(HashingFunction::Pedersen),
            "blake" => Ok(HashingFunction::Blake),
            _ => Err(HasherError::InvalidHashingFunction),
        }
    }
}

impl fmt::Display for HashingFunction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            HashingFunction::Keccak256 => write!(f, "keccak"),
            HashingFunction::Poseidon => write!(f, "poseidon"),
            HashingFunction::Pedersen => write!(f, "pedersen"),
            HashingFunction::Blake => write!(f, "blake"),
        }
    }
}

/// Returns the byte size of a hex string
pub fn byte_size(hex: &str) -> usize {
    let hex = hex.strip_prefix("0x").unwrap_or(hex);
    hex.len() / 2
}