Skip to main content

anchor_syn/
hash.rs

1// Utility hashing module copied from `solana_program::program::hash`, since we
2// can't import solana_program for compile time hashing for some reason.
3
4use {
5    serde::{Deserialize, Serialize},
6    sha2::{Digest, Sha256},
7    std::{fmt, mem, str::FromStr},
8    thiserror::Error,
9};
10
11pub const HASH_BYTES: usize = 32;
12#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
13#[repr(transparent)]
14pub struct Hash(pub [u8; HASH_BYTES]);
15
16#[derive(Clone, Default)]
17pub struct Hasher {
18    hasher: Sha256,
19}
20
21impl Hasher {
22    pub fn hash(&mut self, val: &[u8]) {
23        self.hasher.update(val);
24    }
25    pub fn hashv(&mut self, vals: &[&[u8]]) {
26        for val in vals {
27            self.hash(val);
28        }
29    }
30    pub fn result(self) -> Hash {
31        // `generic-array ^0.14.8` logs deprecation warnings
32        //
33        // TODO: Remove once `sha2` (transitively) depends on `generic-array` v1.
34        #[allow(deprecated)]
35        Hash(<[u8; HASH_BYTES]>::try_from(self.hasher.finalize().as_slice()).unwrap())
36    }
37}
38
39impl AsRef<[u8]> for Hash {
40    fn as_ref(&self) -> &[u8] {
41        &self.0[..]
42    }
43}
44
45impl fmt::Debug for Hash {
46    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47        write!(f, "{}", bs58::encode(self.0).into_string())
48    }
49}
50
51impl fmt::Display for Hash {
52    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53        write!(f, "{}", bs58::encode(self.0).into_string())
54    }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Error)]
58pub enum ParseHashError {
59    #[error("string decoded to wrong size for hash")]
60    WrongSize,
61    #[error("failed to decoded string to hash")]
62    Invalid,
63}
64
65impl FromStr for Hash {
66    type Err = ParseHashError;
67
68    fn from_str(s: &str) -> Result<Self, Self::Err> {
69        let bytes = bs58::decode(s)
70            .into_vec()
71            .map_err(|_| ParseHashError::Invalid)?;
72        if bytes.len() != mem::size_of::<Hash>() {
73            Err(ParseHashError::WrongSize)
74        } else {
75            Ok(Hash::new(&bytes))
76        }
77    }
78}
79
80impl Hash {
81    pub fn new(hash_slice: &[u8]) -> Self {
82        Hash(<[u8; HASH_BYTES]>::try_from(hash_slice).unwrap())
83    }
84
85    pub fn to_bytes(self) -> [u8; HASH_BYTES] {
86        self.0
87    }
88}
89
90/// Return a Sha256 hash for the given data.
91pub fn hashv(vals: &[&[u8]]) -> Hash {
92    // Perform the calculation inline, calling this from within a program is
93    // not supported
94    let mut hasher = Hasher::default();
95    hasher.hashv(vals);
96    hasher.result()
97}
98
99/// Return a Sha256 hash for the given data.
100pub fn hash(val: &[u8]) -> Hash {
101    hashv(&[val])
102}