1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- // Utility hashing module copied from `solana_program::program::hash`, since we
- // can't import solana_program for compile time hashing for some reason.
- use serde::{Deserialize, Serialize};
- use sha2::{Digest, Sha256};
- use std::{fmt, mem, str::FromStr};
- use thiserror::Error;
- pub const HASH_BYTES: usize = 32;
- #[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
- #[repr(transparent)]
- pub struct Hash(pub [u8; HASH_BYTES]);
- #[derive(Clone, Default)]
- pub struct Hasher {
- hasher: Sha256,
- }
- impl Hasher {
- pub fn hash(&mut self, val: &[u8]) {
- self.hasher.update(val);
- }
- pub fn hashv(&mut self, vals: &[&[u8]]) {
- for val in vals {
- self.hash(val);
- }
- }
- pub fn result(self) -> Hash {
- // At the time of this writing, the sha2 library is stuck on an old version
- // of generic_array (0.9.0). Decouple ourselves with a clone to our version.
- Hash(<[u8; HASH_BYTES]>::try_from(self.hasher.finalize().as_slice()).unwrap())
- }
- }
- impl AsRef<[u8]> for Hash {
- fn as_ref(&self) -> &[u8] {
- &self.0[..]
- }
- }
- impl fmt::Debug for Hash {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", bs58::encode(self.0).into_string())
- }
- }
- impl fmt::Display for Hash {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", bs58::encode(self.0).into_string())
- }
- }
- #[derive(Debug, Clone, PartialEq, Eq, Error)]
- pub enum ParseHashError {
- #[error("string decoded to wrong size for hash")]
- WrongSize,
- #[error("failed to decoded string to hash")]
- Invalid,
- }
- impl FromStr for Hash {
- type Err = ParseHashError;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let bytes = bs58::decode(s)
- .into_vec()
- .map_err(|_| ParseHashError::Invalid)?;
- if bytes.len() != mem::size_of::<Hash>() {
- Err(ParseHashError::WrongSize)
- } else {
- Ok(Hash::new(&bytes))
- }
- }
- }
- impl Hash {
- pub fn new(hash_slice: &[u8]) -> Self {
- Hash(<[u8; HASH_BYTES]>::try_from(hash_slice).unwrap())
- }
- pub fn to_bytes(self) -> [u8; HASH_BYTES] {
- self.0
- }
- }
- /// Return a Sha256 hash for the given data.
- pub fn hashv(vals: &[&[u8]]) -> Hash {
- // Perform the calculation inline, calling this from within a program is
- // not supported
- let mut hasher = Hasher::default();
- hasher.hashv(vals);
- hasher.result()
- }
- /// Return a Sha256 hash for the given data.
- pub fn hash(val: &[u8]) -> Hash {
- hashv(&[val])
- }
|