1use crate::error::ProgramError;
11
12pub type Sha256Hash = [u8; 32];
14
15pub type Keccak256Hash = [u8; 32];
17
18pub type Blake3Hash = [u8; 32];
20
21pub const MAX_HASH_SEGMENTS: usize = 16;
23
24#[inline]
35#[allow(unused_mut)]
36pub fn sha256(inputs: &[&[u8]]) -> Result<Sha256Hash, ProgramError> {
37 if inputs.len() > MAX_HASH_SEGMENTS {
38 return Err(ProgramError::InvalidArgument);
39 }
40
41 let mut result = [0u8; 32];
42
43 #[cfg(target_os = "solana")]
44 {
45 const _: () = assert!(core::mem::size_of::<&[u8]>() == 16);
51 let rc = unsafe {
53 crate::syscalls::sol_sha256(
54 inputs.as_ptr() as *const u8,
55 inputs.len() as u64,
56 result.as_mut_ptr(),
57 )
58 };
59 if rc != 0 {
60 return Err(ProgramError::InvalidArgument);
61 }
62 }
63 #[cfg(not(target_os = "solana"))]
64 {
65 let _ = inputs;
66 }
69
70 Ok(result)
71}
72
73#[inline]
75pub fn sha256_single(input: &[u8]) -> Result<Sha256Hash, ProgramError> {
76 sha256(&[input])
77}
78
79#[inline]
84#[allow(unused_mut)]
85pub fn keccak256(inputs: &[&[u8]]) -> Result<Keccak256Hash, ProgramError> {
86 if inputs.len() > MAX_HASH_SEGMENTS {
87 return Err(ProgramError::InvalidArgument);
88 }
89
90 let mut result = [0u8; 32];
91
92 #[cfg(target_os = "solana")]
93 {
94 const _: () = assert!(core::mem::size_of::<&[u8]>() == 16);
96 let rc = unsafe {
98 crate::syscalls::sol_keccak256(
99 inputs.as_ptr() as *const u8,
100 inputs.len() as u64,
101 result.as_mut_ptr(),
102 )
103 };
104 if rc != 0 {
105 return Err(ProgramError::InvalidArgument);
106 }
107 }
108 #[cfg(not(target_os = "solana"))]
109 {
110 let _ = inputs;
111 }
112
113 Ok(result)
114}
115
116#[inline]
118pub fn keccak256_single(input: &[u8]) -> Result<Keccak256Hash, ProgramError> {
119 keccak256(&[input])
120}
121
122#[inline]
124#[allow(unused_mut)]
125pub fn blake3(inputs: &[&[u8]]) -> Result<Blake3Hash, ProgramError> {
126 if inputs.len() > MAX_HASH_SEGMENTS {
127 return Err(ProgramError::InvalidArgument);
128 }
129
130 let mut result = [0u8; 32];
131
132 #[cfg(target_os = "solana")]
133 {
134 const _: () = assert!(core::mem::size_of::<&[u8]>() == 16);
136 let rc = unsafe {
139 crate::syscalls::sol_blake3(
140 inputs.as_ptr() as *const u8,
141 inputs.len() as u64,
142 result.as_mut_ptr(),
143 )
144 };
145 if rc != 0 {
146 return Err(ProgramError::InvalidArgument);
147 }
148 }
149 #[cfg(not(target_os = "solana"))]
150 {
151 let _ = inputs;
152 }
153
154 Ok(result)
155}
156
157#[inline]
159pub fn blake3_single(input: &[u8]) -> Result<Blake3Hash, ProgramError> {
160 blake3(&[input])
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 const EMPTY: &[u8] = b"";
168
169 #[test]
170 fn sha256_accepts_sixteen_segments() {
171 let inputs = [EMPTY; MAX_HASH_SEGMENTS];
172 assert_eq!(sha256(&inputs), Ok([0; 32]));
173 }
174
175 #[test]
176 fn keccak256_accepts_sixteen_segments() {
177 let inputs = [EMPTY; MAX_HASH_SEGMENTS];
178 assert_eq!(keccak256(&inputs), Ok([0; 32]));
179 }
180
181 #[test]
182 fn blake3_accepts_sixteen_segments() {
183 let inputs = [EMPTY; MAX_HASH_SEGMENTS];
184 assert_eq!(blake3(&inputs), Ok([0; 32]));
185 }
186
187 #[test]
188 fn sha256_rejects_more_than_sixteen_segments() {
189 let inputs = [EMPTY; MAX_HASH_SEGMENTS + 1];
190 assert_eq!(sha256(&inputs), Err(ProgramError::InvalidArgument));
191 }
192
193 #[test]
194 fn keccak256_rejects_more_than_sixteen_segments() {
195 let inputs = [EMPTY; MAX_HASH_SEGMENTS + 1];
196 assert_eq!(keccak256(&inputs), Err(ProgramError::InvalidArgument));
197 }
198
199 #[test]
200 fn blake3_rejects_more_than_sixteen_segments() {
201 let inputs = [EMPTY; MAX_HASH_SEGMENTS + 1];
202 assert_eq!(blake3(&inputs), Err(ProgramError::InvalidArgument));
203 }
204}