tendermint 0.6.0

Tendermint is a high-performance blockchain consensus engine that powers Byzantine fault tolerant applications written in any programming language. This crate provides types for representing information about Tendermint blockchain networks, including chain IDs, block IDs, and block heights.
Documentation
//! Hash functions and their outputs

use crate::{algorithm::HashAlgorithm, error::Error};
#[cfg(feature = "serde")]
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
use std::{
    fmt::{self, Display},
    str::FromStr,
};
use subtle_encoding::{Encoding, Hex};

/// Output size for the SHA-256 hash function
pub const SHA256_HASH_SIZE: usize = 32;

/// Hashes used for computing BlockIDs
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum Hash {
    /// SHA-256 hashes
    Sha256([u8; SHA256_HASH_SIZE]),
}

impl Hash {
    #[allow(clippy::new_ret_no_self)]
    /// Create a new `Hash` with the given algorithm type
    pub fn new(alg: HashAlgorithm, bytes: &[u8]) -> Result<Hash, Error> {
        match alg {
            HashAlgorithm::Sha256 => {
                if bytes.len() == SHA256_HASH_SIZE {
                    let mut h = [0u8; SHA256_HASH_SIZE];
                    h.copy_from_slice(bytes);
                    Ok(Hash::Sha256(h))
                } else {
                    Err(Error::Parse)
                }
            }
        }
    }

    /// Decode a `Hash` from upper-case hexadecimal
    pub fn from_hex_upper(alg: HashAlgorithm, s: &str) -> Result<Hash, Error> {
        match alg {
            HashAlgorithm::Sha256 => {
                let mut h = [0u8; SHA256_HASH_SIZE];
                Hex::upper_case().decode_to_slice(s.as_bytes(), &mut h)?;
                Ok(Hash::Sha256(h))
            }
        }
    }

    /// Borrow the `Hash` as a byte slice
    pub fn as_slice(&self) -> &[u8] {
        match self {
            Hash::Sha256(ref h) => h.as_ref(),
        }
    }
}

impl AsRef<[u8]> for Hash {
    fn as_ref(&self) -> &[u8] {
        self.as_slice()
    }
}

impl Display for Hash {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let hex = match self {
            Hash::Sha256(ref h) => Hex::upper_case().encode_to_string(h).unwrap(),
        };

        write!(f, "{}", hex)
    }
}

impl FromStr for Hash {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Error> {
        Self::from_hex_upper(HashAlgorithm::Sha256, s)
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Hash {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        Ok(Self::from_str(&String::deserialize(deserializer)?)
            .map_err(|e| D::Error::custom(format!("{}", e)))?)
    }
}

#[cfg(feature = "serde")]
impl Serialize for Hash {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        self.to_string().serialize(serializer)
    }
}