light_token_interface/state/compressed_token/
hash.rs1use borsh::BorshSerialize;
2use light_compressed_account::hash_to_bn254_field_size_be;
3use light_hasher::{errors::HasherError, sha256::Sha256BE, Hasher, Poseidon};
4use light_program_profiler::profile;
5
6use super::TokenData;
7use crate::{state::compressed_token::CompressedTokenAccountState, NATIVE_MINT};
8
9impl TokenData {
22 pub fn is_native(&self) -> bool {
28 self.mint == NATIVE_MINT
29 }
30
31 pub fn hash_with_hashed_values(
32 hashed_mint: &[u8; 32],
33 hashed_owner: &[u8; 32],
34 amount_bytes: &[u8; 32],
35 hashed_delegate: &Option<&[u8; 32]>,
36 ) -> Result<[u8; 32], HasherError> {
37 Self::hash_inputs_with_hashed_values::<false>(
38 hashed_mint,
39 hashed_owner,
40 amount_bytes,
41 hashed_delegate,
42 )
43 }
44
45 pub fn hash_frozen_with_hashed_values(
46 hashed_mint: &[u8; 32],
47 hashed_owner: &[u8; 32],
48 amount_bytes: &[u8; 32],
49 hashed_delegate: &Option<&[u8; 32]>,
50 ) -> Result<[u8; 32], HasherError> {
51 Self::hash_inputs_with_hashed_values::<true>(
52 hashed_mint,
53 hashed_owner,
54 amount_bytes,
55 hashed_delegate,
56 )
57 }
58
59 pub fn hash_inputs_with_hashed_values<const FROZEN_INPUTS: bool>(
63 mint: &[u8; 32],
64 owner: &[u8; 32],
65 amount_bytes: &[u8],
66 hashed_delegate: &Option<&[u8; 32]>,
67 ) -> Result<[u8; 32], HasherError> {
68 let mut hash_inputs = vec![mint.as_slice(), owner.as_slice(), amount_bytes];
69 if let Some(hashed_delegate) = hashed_delegate {
70 hash_inputs.push(hashed_delegate.as_slice());
71 }
72 let mut state_bytes = [0u8; 32];
73 if FROZEN_INPUTS {
74 state_bytes[31] = CompressedTokenAccountState::Frozen as u8;
75 hash_inputs.push(&state_bytes[..]);
76 }
77 Poseidon::hashv(hash_inputs.as_slice())
78 }
79}
80
81impl TokenData {
82 #[profile]
85 #[inline(always)]
86 pub fn hash_sha_flat(&self) -> Result<[u8; 32], HasherError> {
87 let bytes = self.try_to_vec().map_err(|_| HasherError::BorshError)?;
88 Sha256BE::hash(bytes.as_slice())
89 }
90
91 pub fn hash_v2(&self) -> Result<[u8; 32], HasherError> {
98 self._hash::<true>()
99 }
100
101 pub fn hash_v1(&self) -> Result<[u8; 32], HasherError> {
106 self._hash::<false>()
107 }
108
109 fn _hash<const BATCHED: bool>(&self) -> Result<[u8; 32], HasherError> {
110 let hashed_mint = hash_to_bn254_field_size_be(self.mint.to_bytes().as_slice());
111 let hashed_owner = hash_to_bn254_field_size_be(self.owner.to_bytes().as_slice());
112 let mut amount_bytes = [0u8; 32];
113 if BATCHED {
114 amount_bytes[24..].copy_from_slice(self.amount.to_be_bytes().as_slice());
115 } else {
116 amount_bytes[24..].copy_from_slice(self.amount.to_le_bytes().as_slice());
117 }
118 let hashed_delegate;
119 let hashed_delegate_option = if let Some(delegate) = self.delegate {
120 hashed_delegate = hash_to_bn254_field_size_be(delegate.to_bytes().as_slice());
121 Some(&hashed_delegate)
122 } else {
123 None
124 };
125 if self.state != CompressedTokenAccountState::Initialized as u8 {
126 Self::hash_inputs_with_hashed_values::<true>(
127 &hashed_mint,
128 &hashed_owner,
129 &amount_bytes,
130 &hashed_delegate_option,
131 )
132 } else {
133 Self::hash_inputs_with_hashed_values::<false>(
134 &hashed_mint,
135 &hashed_owner,
136 &amount_bytes,
137 &hashed_delegate_option,
138 )
139 }
140 }
141}