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 From<[u8; HASH_BYTES]> for Leaf {
31 fn from(from: [u8; 32]) -> Self {
32 Self { 0: Hash { value: from } }
33 }
34}
35
36impl AsRef<[u8]> for Hash {
37 fn as_ref(&self) -> &[u8] {
38 &self.value
39 }
40}
41
42impl AsRef<[u8]> for Leaf {
43 fn as_ref(&self) -> &[u8] {
44 &self.0.value
45 }
46}
47
48impl From<Leaf> for Hash {
49 fn from(leaf: Leaf) -> Self {
50 leaf.0
51 }
52}
53
54impl Hash {
55 pub const LEN: usize = HASH_BYTES;
56
57 pub fn new(hash_slice: &[u8]) -> Self {
58 Hash {
59 value: <[u8; HASH_BYTES]>::try_from(hash_slice).unwrap(),
60 }
61 }
62
63 pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self {
64 Self { value: hash_array }
65 }
66
67 pub fn to_bytes(self) -> [u8; HASH_BYTES] {
68 self.value
69 }
70
71 pub fn as_leaf(self) -> Leaf {
72 Leaf(self)
73 }
74}
75
76impl Leaf {
77 pub fn new(data: &[&[u8]]) -> Self {
78 let mut inputs = vec![b"LEAF".as_ref()];
79 inputs.extend(data);
80 Leaf(hashv(&inputs))
81 }
82
83 pub fn to_bytes(self) -> [u8; HASH_BYTES] {
84 self.0.value
85 }
86}
87
88#[cfg(feature = "solana")]
89#[inline(always)]
90pub fn hashv(data: &[&[u8]]) -> Hash {
91 let res = solana_program::keccak::hashv(data);
92 Hash::new_from_array(res.to_bytes())
93}
94
95#[cfg(not(feature = "solana"))]
96#[inline(always)]
97pub fn hashv(data: &[&[u8]]) -> Hash {
98 let mut hasher = sha3::Keccak256::new();
99 for d in data {
100 hasher.update(d);
101 }
102 Hash::new_from_array(hasher.finalize().into())
103}
104
105#[cfg(feature = "solana")]
106#[inline(always)]
107pub fn hash(data: &[u8]) -> Hash {
108 let res = solana_program::keccak::hash(data);
109 Hash::new_from_array(res.to_bytes())
110}
111
112#[cfg(not(feature = "solana"))]
113#[inline(always)]
114pub fn hash(data: &[u8]) -> Hash {
115 let mut hasher = sha3::Keccak256::new();
116 hasher.update(data);
117 Hash::new_from_array(hasher.finalize().into())
118}