1#[cfg(all(target_family = "wasm", miden))]
6mod imp {
7 use alloc::vec::Vec;
8
9 use crate::{
10 felt,
11 intrinsics::{Digest, Felt, Word, assert_eq},
12 };
13
14 unsafe extern "C" {
15 #[link_name = "miden::core::crypto::hashes::blake3::hash"]
21 fn extern_blake3_hash(
22 e1: u32,
23 e2: u32,
24 e3: u32,
25 e4: u32,
26 e5: u32,
27 e6: u32,
28 e7: u32,
29 e8: u32,
30 ptr: *mut u8,
31 );
32
33 #[link_name = "miden::core::crypto::hashes::blake3::merge"]
39 fn extern_blake3_merge(
40 e1: u32,
41 e2: u32,
42 e3: u32,
43 e4: u32,
44 e5: u32,
45 e6: u32,
46 e7: u32,
47 e8: u32,
48 e9: u32,
49 e10: u32,
50 e11: u32,
51 e12: u32,
52 e13: u32,
53 e14: u32,
54 e15: u32,
55 e16: u32,
56 ptr: *mut u8,
57 );
58 }
59
60 unsafe extern "C" {
61 #[link_name = "miden::core::crypto::hashes::sha256::hash"]
67 fn extern_sha256_hash(
68 e1: u32,
69 e2: u32,
70 e3: u32,
71 e4: u32,
72 e5: u32,
73 e6: u32,
74 e7: u32,
75 e8: u32,
76 ptr: *mut u8,
77 );
78
79 #[link_name = "miden::core::crypto::hashes::sha256::merge"]
85 fn extern_sha256_merge(
86 e1: u32,
87 e2: u32,
88 e3: u32,
89 e4: u32,
90 e5: u32,
91 e6: u32,
92 e7: u32,
93 e8: u32,
94 e9: u32,
95 e10: u32,
96 e11: u32,
97 e12: u32,
98 e13: u32,
99 e14: u32,
100 e15: u32,
101 e16: u32,
102 ptr: *mut u8,
103 );
104 }
105
106 unsafe extern "C" {
107 #[link_name = "miden::core::crypto::hashes::rpo256::hash_elements"]
116 pub fn extern_hash_elements(ptr: u32, num_elements: u32, result_ptr: *mut Felt);
117
118 #[link_name = "miden::core::crypto::hashes::rpo256::hash_words"]
127 pub fn extern_hash_words(start_addr: u32, end_addr: u32, result_ptr: *mut Felt);
128 }
129
130 #[inline(always)]
132 fn hash(
133 input: [u8; 32],
134 extern_hash: unsafe extern "C" fn(u32, u32, u32, u32, u32, u32, u32, u32, *mut u8),
135 ) -> [u8; 32] {
136 use crate::intrinsics::WordAligned;
137 let input = unsafe { core::mem::transmute::<[u8; 32], [u32; 8]>(input) };
138 unsafe {
139 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
140 let ptr = ret_area.as_mut_ptr() as *mut u8;
141 extern_hash(
142 input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7], ptr,
143 );
144 ret_area.assume_init().into_inner()
145 }
146 }
147
148 #[inline(always)]
150 fn merge(
151 input: [u8; 64],
152 extern_merge: unsafe extern "C" fn(
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 u32,
169 *mut u8,
170 ),
171 ) -> [u8; 32] {
172 let input = unsafe { core::mem::transmute::<[u8; 64], [u32; 16]>(input) };
173 unsafe {
174 let mut ret_area = ::core::mem::MaybeUninit::<[u8; 32]>::uninit();
175 let ptr = ret_area.as_mut_ptr() as *mut u8;
176 extern_merge(
177 input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
178 input[8], input[9], input[10], input[11], input[12], input[13], input[14],
179 input[15], ptr,
180 );
181 ret_area.assume_init()
182 }
183 }
184
185 #[inline]
187 pub fn blake3_hash(input: [u8; 32]) -> [u8; 32] {
188 hash(input, extern_blake3_hash)
189 }
190
191 #[inline]
193 pub fn blake3_merge(input: [u8; 64]) -> [u8; 32] {
194 merge(input, extern_blake3_merge)
195 }
196
197 #[inline]
199 pub fn sha256_hash(input: [u8; 32]) -> [u8; 32] {
200 use crate::intrinsics::WordAligned;
201
202 let swapped_words = {
203 let mut be_bytes = input;
204 for chunk in be_bytes.chunks_exact_mut(4) {
209 chunk.reverse();
210 }
211 unsafe { core::mem::transmute::<[u8; 32], [u32; 8]>(be_bytes) }
212 };
213
214 let [w0, w1, w2, w3, w4, w5, w6, w7] = swapped_words;
215
216 unsafe {
217 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
218 let ptr = ret_area.as_mut_ptr() as *mut u8;
219 extern_sha256_hash(w0, w1, w2, w3, w4, w5, w6, w7, ptr);
220 let mut output = ret_area.assume_init().into_inner();
221 for chunk in output.chunks_exact_mut(4) {
224 chunk.reverse();
225 }
226 output
227 }
228 }
229
230 #[inline]
232 pub fn sha256_merge(input: [u8; 64]) -> [u8; 32] {
233 use crate::intrinsics::WordAligned;
234
235 let swapped_words = {
236 let mut be_bytes = input;
237 for chunk in be_bytes.chunks_exact_mut(4) {
240 chunk.reverse();
241 }
242 unsafe { core::mem::transmute::<[u8; 64], [u32; 16]>(be_bytes) }
243 };
244
245 let [w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15] = swapped_words;
246
247 unsafe {
248 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
249 let ptr = ret_area.as_mut_ptr() as *mut u8;
250 extern_sha256_merge(
251 w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15, ptr,
252 );
253 let mut output = ret_area.assume_init().into_inner();
254 for chunk in output.chunks_exact_mut(4) {
256 chunk.reverse();
257 }
258 output
259 }
260 }
261
262 #[inline]
272 pub fn hash_elements(elements: Vec<Felt>) -> Digest {
273 let rust_ptr = elements.as_ptr().addr() as u32;
274 let element_count = elements.len();
275 let num_elements = element_count as u32;
276
277 unsafe {
278 let mut ret_area = core::mem::MaybeUninit::<Word>::uninit();
279 let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
280 let miden_ptr = rust_ptr / 4;
281 assert_eq(Felt::from_u32(miden_ptr % 4), felt!(0));
283
284 if element_count.is_multiple_of(4) {
285 let start_addr = miden_ptr;
286 let end_addr = start_addr + num_elements;
287 extern_hash_words(start_addr, end_addr, result_ptr);
288 } else {
289 extern_hash_elements(miden_ptr, num_elements, result_ptr);
290 }
291
292 Digest::from_word(ret_area.assume_init().reverse())
293 }
294 }
295
296 #[inline]
304 pub fn hash_words(words: &[Word]) -> Digest {
305 let rust_ptr = words.as_ptr().addr() as u32;
306
307 let miden_ptr = rust_ptr / 4;
308 assert_eq(Felt::from_u32(miden_ptr % 4), felt!(0));
310
311 unsafe {
312 let mut ret_area = core::mem::MaybeUninit::<Word>::uninit();
313 let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
314 let start_addr = miden_ptr;
315 let end_addr = start_addr + (words.len() as u32 * 4);
316 extern_hash_words(start_addr, end_addr, result_ptr);
317
318 Digest::from_word(ret_area.assume_init().reverse())
319 }
320 }
321}
322
323#[cfg(not(all(target_family = "wasm", miden)))]
324mod imp {
325 use alloc::vec::Vec;
326
327 use crate::intrinsics::{Digest, Felt, Word};
328
329 #[inline]
331 pub fn blake3_hash(_input: [u8; 32]) -> [u8; 32] {
332 unimplemented!(
333 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
334 )
335 }
336
337 #[inline]
339 pub fn blake3_merge(_input: [u8; 64]) -> [u8; 32] {
340 unimplemented!(
341 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
342 )
343 }
344
345 #[inline]
347 pub fn sha256_hash(_input: [u8; 32]) -> [u8; 32] {
348 unimplemented!(
349 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
350 )
351 }
352
353 #[inline]
355 pub fn sha256_merge(_input: [u8; 64]) -> [u8; 32] {
356 unimplemented!(
357 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
358 )
359 }
360
361 #[inline]
364 pub fn hash_elements(_elements: Vec<Felt>) -> Digest {
365 unimplemented!(
366 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
367 )
368 }
369
370 #[inline]
373 pub fn hash_words(_words: &[Word]) -> Digest {
374 unimplemented!(
375 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
376 )
377 }
378
379 #[inline]
381 pub fn extern_hash_elements(_ptr: u32, _num_elements: u32, _result_ptr: *mut Felt) {
382 unimplemented!(
383 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
384 )
385 }
386
387 #[inline]
389 pub fn extern_hash_words(_start_addr: u32, _end_addr: u32, _result_ptr: *mut Felt) {
390 unimplemented!(
391 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
392 )
393 }
394}
395
396pub use imp::*;