1use alloc::vec::Vec;
6
7use crate::{
8 felt,
9 intrinsics::{Digest, Felt, Word, assert_eq},
10};
11
12unsafe extern "C" {
13 #[link_name = "std::crypto::hashes::blake3::hash_1to1"]
19 fn extern_blake3_hash_1to1(
20 e1: u32,
21 e2: u32,
22 e3: u32,
23 e4: u32,
24 e5: u32,
25 e6: u32,
26 e7: u32,
27 e8: u32,
28 ptr: *mut u8,
29 );
30
31 #[link_name = "std::crypto::hashes::blake3::hash_2to1"]
37 fn extern_blake3_hash_2to1(
38 e1: u32,
39 e2: u32,
40 e3: u32,
41 e4: u32,
42 e5: u32,
43 e6: u32,
44 e7: u32,
45 e8: u32,
46 e9: u32,
47 e10: u32,
48 e11: u32,
49 e12: u32,
50 e13: u32,
51 e14: u32,
52 e15: u32,
53 e16: u32,
54 ptr: *mut u8,
55 );
56}
57
58unsafe extern "C" {
59 #[link_name = "std::crypto::hashes::sha256::hash_1to1"]
65 fn extern_sha256_hash_1to1(
66 e1: u32,
67 e2: u32,
68 e3: u32,
69 e4: u32,
70 e5: u32,
71 e6: u32,
72 e7: u32,
73 e8: u32,
74 ptr: *mut u8,
75 );
76
77 #[link_name = "std::crypto::hashes::sha256::hash_2to1"]
83 fn extern_sha256_hash_2to1(
84 e1: u32,
85 e2: u32,
86 e3: u32,
87 e4: u32,
88 e5: u32,
89 e6: u32,
90 e7: u32,
91 e8: u32,
92 e9: u32,
93 e10: u32,
94 e11: u32,
95 e12: u32,
96 e13: u32,
97 e14: u32,
98 e15: u32,
99 e16: u32,
100 ptr: *mut u8,
101 );
102}
103
104unsafe extern "C" {
105 #[link_name = "std::crypto::hashes::rpo::hash_memory"]
114 pub fn extern_hash_memory(ptr: u32, num_elements: u32, result_ptr: *mut Felt);
115
116 #[link_name = "std::crypto::hashes::rpo::hash_memory_words"]
126 pub fn extern_hash_memory_words(start_addr: u32, end_addr: u32, result_ptr: *mut Felt);
127}
128
129#[inline(always)]
131fn hash_1to1(
132 input: [u8; 32],
133 extern_hash_1to1: unsafe extern "C" fn(u32, u32, u32, u32, u32, u32, u32, u32, *mut u8),
134) -> [u8; 32] {
135 use crate::intrinsics::WordAligned;
136 let input = unsafe { core::mem::transmute::<[u8; 32], [u32; 8]>(input) };
137 unsafe {
138 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
139 let ptr = ret_area.as_mut_ptr() as *mut u8;
140 extern_hash_1to1(
141 input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7], ptr,
142 );
143 ret_area.assume_init().into_inner()
144 }
145}
146
147#[inline(always)]
149fn hash_2to1(
150 input: [u8; 64],
151 extern_hash_2to1: unsafe extern "C" fn(
152 u32,
153 u32,
154 u32,
155 u32,
156 u32,
157 u32,
158 u32,
159 u32,
160 u32,
161 u32,
162 u32,
163 u32,
164 u32,
165 u32,
166 u32,
167 u32,
168 *mut u8,
169 ),
170) -> [u8; 32] {
171 let input = unsafe { core::mem::transmute::<[u8; 64], [u32; 16]>(input) };
172 unsafe {
173 let mut ret_area = ::core::mem::MaybeUninit::<[u8; 32]>::uninit();
174 let ptr = ret_area.as_mut_ptr() as *mut u8;
175 extern_hash_2to1(
176 input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
177 input[8], input[9], input[10], input[11], input[12], input[13], input[14], input[15],
178 ptr,
179 );
180 ret_area.assume_init()
181 }
182}
183
184#[inline]
186pub fn blake3_hash_1to1(input: [u8; 32]) -> [u8; 32] {
187 hash_1to1(input, extern_blake3_hash_1to1)
188}
189
190#[inline]
192pub fn blake3_hash_2to1(input: [u8; 64]) -> [u8; 32] {
193 hash_2to1(input, extern_blake3_hash_2to1)
194}
195
196#[inline]
198pub fn sha256_hash_1to1(input: [u8; 32]) -> [u8; 32] {
199 use crate::intrinsics::WordAligned;
200
201 let swapped_words = {
202 let mut be_bytes = input;
203 for chunk in be_bytes.chunks_exact_mut(4) {
208 chunk.reverse();
209 }
210 unsafe { core::mem::transmute::<[u8; 32], [u32; 8]>(be_bytes) }
211 };
212
213 let [w0, w1, w2, w3, w4, w5, w6, w7] = swapped_words;
214
215 unsafe {
216 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
217 let ptr = ret_area.as_mut_ptr() as *mut u8;
218 extern_sha256_hash_1to1(w0, w1, w2, w3, w4, w5, w6, w7, ptr);
219 let mut output = ret_area.assume_init().into_inner();
220 for chunk in output.chunks_exact_mut(4) {
223 chunk.reverse();
224 }
225 output
226 }
227}
228
229#[inline]
231pub fn sha256_hash_2to1(input: [u8; 64]) -> [u8; 32] {
232 use crate::intrinsics::WordAligned;
233
234 let swapped_words = {
235 let mut be_bytes = input;
236 for chunk in be_bytes.chunks_exact_mut(4) {
239 chunk.reverse();
240 }
241 unsafe { core::mem::transmute::<[u8; 64], [u32; 16]>(be_bytes) }
242 };
243
244 let [w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15] = swapped_words;
245
246 unsafe {
247 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
248 let ptr = ret_area.as_mut_ptr() as *mut u8;
249 extern_sha256_hash_2to1(
250 w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15, ptr,
251 );
252 let mut output = ret_area.assume_init().into_inner();
253 for chunk in output.chunks_exact_mut(4) {
255 chunk.reverse();
256 }
257 output
258 }
259}
260
261#[inline]
271pub fn hash_elements(elements: Vec<Felt>) -> Digest {
272 let rust_ptr = elements.as_ptr().addr() as u32;
273 let element_count = elements.len();
274 let num_elements = element_count as u32;
275
276 unsafe {
277 let mut ret_area = core::mem::MaybeUninit::<Word>::uninit();
278 let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
279 let miden_ptr = rust_ptr / 4;
280 assert_eq(Felt::from_u32(miden_ptr % 4), felt!(0));
282
283 if element_count.is_multiple_of(4) {
284 let start_addr = miden_ptr;
285 let end_addr = start_addr + num_elements;
286 extern_hash_memory_words(start_addr, end_addr, result_ptr);
287 } else {
288 extern_hash_memory(miden_ptr, num_elements, result_ptr);
289 }
290
291 Digest::from_word(ret_area.assume_init().reverse())
292 }
293}
294
295#[inline]
303pub fn hash_words(words: &[Word]) -> Digest {
304 let rust_ptr = words.as_ptr().addr() as u32;
305
306 unsafe {
307 let mut ret_area = core::mem::MaybeUninit::<Word>::uninit();
308 let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
309 let miden_ptr = rust_ptr / 4;
310 assert_eq(Felt::from_u32(miden_ptr % 4), felt!(0));
312
313 let start_addr = miden_ptr;
314 let end_addr = start_addr + (words.len() as u32 * 4);
315 extern_hash_memory_words(start_addr, end_addr, result_ptr);
316
317 Digest::from_word(ret_area.assume_init().reverse())
318 }
319}