1use bytemuck::{Pod, Zeroable};
2
3#[cfg(not(feature = "solana"))]
4use sha3::Digest;
5
6pub const HASH_BYTES: usize = 32;
7
8#[repr(C)]
9#[derive(Clone, Copy, PartialEq, Debug, Default, Pod, Zeroable)]
10pub struct Hash {
11 pub(crate) value: [u8; 32],
12}
13
14#[repr(C)]
15#[derive(Clone, Copy, PartialEq, Debug, Pod, Zeroable)]
16pub struct Leaf(Hash);
17
18impl From<Hash> for [u8; HASH_BYTES] {
19 fn from(from: Hash) -> Self {
20 from.value
21 }
22}
23
24impl From<[u8; HASH_BYTES]> for Hash {
25 fn from(from: [u8; 32]) -> Self {
26 Self { value: from }
27 }
28}
29
30impl AsRef<[u8]> for Hash {
31 fn as_ref(&self) -> &[u8] {
32 &self.value
33 }
34}
35
36impl AsRef<[u8]> for Leaf {
37 fn as_ref(&self) -> &[u8] {
38 &self.0.value
39 }
40}
41
42impl From<Leaf> for Hash {
43 fn from(leaf: Leaf) -> Self {
44 leaf.0
45 }
46}
47
48impl Hash {
49 pub const LEN: usize = HASH_BYTES;
50
51 pub fn new(hash_slice: &[u8]) -> Self {
52 Hash {
53 value: <[u8; HASH_BYTES]>::try_from(hash_slice).unwrap(),
54 }
55 }
56
57 pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self {
58 Self { value: hash_array }
59 }
60
61 pub fn to_bytes(self) -> [u8; HASH_BYTES] {
62 self.value
63 }
64
65 pub fn as_leaf(self) -> Leaf {
66 Leaf(self)
67 }
68}
69
70impl Leaf {
71 pub fn new(data: &[&[u8]]) -> Self {
72 let mut inputs = vec![b"LEAF".as_ref()];
73 inputs.extend(data);
74 Leaf(hashv(&inputs))
75 }
76}
77
78#[cfg(feature = "solana")]
79#[inline(always)]
80pub fn hashv(data: &[&[u8]]) -> Hash {
81 let res = solana_program::keccak::hashv(data);
82 Hash::new_from_array(res.to_bytes())
83}
84
85#[cfg(not(feature = "solana"))]
86#[inline(always)]
87pub fn hashv(data: &[&[u8]]) -> Hash {
88 let mut hasher = sha3::Keccak256::new();
89 for d in data {
90 hasher.update(d);
91 }
92 Hash::new_from_array(hasher.finalize().into())
93}
94
95#[cfg(feature = "solana")]
96#[inline(always)]
97pub fn hash(data: &[u8]) -> Hash {
98 let res = solana_program::keccak::hash(data);
99 Hash::new_from_array(res.to_bytes())
100}
101
102#[cfg(not(feature = "solana"))]
103#[inline(always)]
104pub fn hash(data: &[u8]) -> Hash {
105 let mut hasher = sha3::Keccak256::new();
106 hasher.update(data);
107 Hash::new_from_array(hasher.finalize().into())
108}