1use serde::{Deserialize, Serialize};
5use sha2::{Digest, Sha256};
6use std::{convert::TryFrom, fmt, mem, str::FromStr};
7use thiserror::Error;
8
9pub const HASH_BYTES: usize = 32;
10#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
11#[repr(transparent)]
12pub struct Hash(pub [u8; HASH_BYTES]);
13
14#[derive(Clone, Default)]
15pub struct Hasher {
16 hasher: Sha256,
17}
18
19impl Hasher {
20 pub fn hash(&mut self, val: &[u8]) {
21 self.hasher.update(val);
22 }
23 pub fn hashv(&mut self, vals: &[&[u8]]) {
24 for val in vals {
25 self.hash(val);
26 }
27 }
28 pub fn result(self) -> Hash {
29 Hash(<[u8; HASH_BYTES]>::try_from(self.hasher.finalize().as_slice()).unwrap())
32 }
33}
34
35impl AsRef<[u8]> for Hash {
36 fn as_ref(&self) -> &[u8] {
37 &self.0[..]
38 }
39}
40
41impl fmt::Debug for Hash {
42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43 write!(f, "{}", bs58::encode(self.0).into_string())
44 }
45}
46
47impl fmt::Display for Hash {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 write!(f, "{}", bs58::encode(self.0).into_string())
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Error)]
54pub enum ParseHashError {
55 #[error("string decoded to wrong size for hash")]
56 WrongSize,
57 #[error("failed to decoded string to hash")]
58 Invalid,
59}
60
61impl FromStr for Hash {
62 type Err = ParseHashError;
63
64 fn from_str(s: &str) -> Result<Self, Self::Err> {
65 let bytes = bs58::decode(s)
66 .into_vec()
67 .map_err(|_| ParseHashError::Invalid)?;
68 if bytes.len() != mem::size_of::<Hash>() {
69 Err(ParseHashError::WrongSize)
70 } else {
71 Ok(Hash::new(&bytes))
72 }
73 }
74}
75
76impl Hash {
77 pub fn new(hash_slice: &[u8]) -> Self {
78 Hash(<[u8; HASH_BYTES]>::try_from(hash_slice).unwrap())
79 }
80
81 #[cfg(target_arch = "bpf")]
82 pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self {
83 Self(hash_array)
84 }
85
86 pub fn to_bytes(self) -> [u8; HASH_BYTES] {
87 self.0
88 }
89}
90
91pub fn hashv(vals: &[&[u8]]) -> Hash {
93 #[cfg(not(target_arch = "bpf"))]
96 {
97 let mut hasher = Hasher::default();
98 hasher.hashv(vals);
99 hasher.result()
100 }
101 #[cfg(target_arch = "bpf")]
103 {
104 extern "C" {
105 fn sol_sha256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64;
106 }
107 let mut hash_result = [0; HASH_BYTES];
108 unsafe {
109 sol_sha256(
110 vals as *const _ as *const u8,
111 vals.len() as u64,
112 &mut hash_result as *mut _ as *mut u8,
113 );
114 }
115 Hash::new_from_array(hash_result)
116 }
117}
118
119pub fn hash(val: &[u8]) -> Hash {
121 hashv(&[val])
122}