123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- // 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::{convert::TryFrom, 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())
- }
- #[cfg(target_arch = "bpf")]
- pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self {
- Self(hash_array)
- }
- 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
- #[cfg(not(target_arch = "bpf"))]
- {
- let mut hasher = Hasher::default();
- hasher.hashv(vals);
- hasher.result()
- }
- // Call via a system call to perform the calculation
- #[cfg(target_arch = "bpf")]
- {
- extern "C" {
- fn sol_sha256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64;
- }
- let mut hash_result = [0; HASH_BYTES];
- unsafe {
- sol_sha256(
- vals as *const _ as *const u8,
- vals.len() as u64,
- &mut hash_result as *mut _ as *mut u8,
- );
- }
- Hash::new_from_array(hash_result)
- }
- }
- /// Return a Sha256 hash for the given data.
- pub fn hash(val: &[u8]) -> Hash {
- hashv(&[val])
- }
|